blob: 74dae92b5b0746be5f8e272f53967a4520821b94 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
Bram Moolenaarf1f60f82016-01-16 15:40:53 +010071static int get_maxbacktrace_level(void);
72static void do_setdebugtracelevel(char_u *arg);
73static void do_checkbacktracelevel(void);
74static void do_showbacktrace(char_u *cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +000075
76/*
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
79 */
80 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010081do_debug(char_u *cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +000082{
83 int save_msg_scroll = msg_scroll;
84 int save_State = State;
85 int save_did_emsg = did_emsg;
86 int save_cmd_silent = cmd_silent;
87 int save_msg_silent = msg_silent;
88 int save_emsg_silent = emsg_silent;
89 int save_redir_off = redir_off;
90 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000091 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000092 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 int save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 int n;
95 char_u *cmdline = NULL;
96 char_u *p;
97 char *tail = NULL;
98 static int last_cmd = 0;
99#define CMD_CONT 1
100#define CMD_NEXT 2
101#define CMD_STEP 3
102#define CMD_FINISH 4
103#define CMD_QUIT 5
104#define CMD_INTERRUPT 6
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100105#define CMD_BACKTRACE 7
106#define CMD_FRAME 8
107#define CMD_UP 9
108#define CMD_DOWN 10
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109
110#ifdef ALWAYS_USE_GUI
111 /* Can't do this when there is no terminal for input/output. */
112 if (!gui.in_use)
113 {
114 /* Break as soon as possible. */
115 debug_break_level = 9999;
116 return;
117 }
118#endif
119
120 /* Make sure we are in raw mode and start termcap mode. Might have side
121 * effects... */
122 settmode(TMODE_RAW);
123 starttermcap();
124
125 ++RedrawingDisabled; /* don't redisplay the window */
126 ++no_wait_return; /* don't wait for return */
127 did_emsg = FALSE; /* don't use error from debugged stuff */
128 cmd_silent = FALSE; /* display commands */
129 msg_silent = FALSE; /* display messages */
130 emsg_silent = FALSE; /* display error messages */
131 redir_off = TRUE; /* don't redirect debug commands */
132
133 State = NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134
135 if (!debug_did_msg)
136 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
137 if (sourcing_name != NULL)
138 msg(sourcing_name);
139 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000142 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143
144 /*
145 * Repeat getting a command and executing it.
146 */
147 for (;;)
148 {
149 msg_scroll = TRUE;
150 need_wait_return = FALSE;
Bram Moolenaar85b11762016-02-27 18:13:23 +0100151
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 save_ex_normal_busy = ex_normal_busy;
158 ex_normal_busy = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000160 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 typeahead_saved = TRUE;
163 save_ignore_script = ignore_script;
164 ignore_script = TRUE;
165 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166
Bram Moolenaardc303bc2016-05-17 17:45:38 +0200167 vim_free(cmdline);
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000168 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000170 if (typeahead_saved)
171 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000173 ignore_script = save_ignore_script;
174 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176
177 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100178 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 if (cmdline != NULL)
180 {
181 /* If this is a debug command, set "last_cmd".
182 * If not, reset "last_cmd".
183 * For a blank line use previous command. */
184 p = skipwhite(cmdline);
185 if (*p != NUL)
186 {
187 switch (*p)
188 {
189 case 'c': last_cmd = CMD_CONT;
190 tail = "ont";
191 break;
192 case 'n': last_cmd = CMD_NEXT;
193 tail = "ext";
194 break;
195 case 's': last_cmd = CMD_STEP;
196 tail = "tep";
197 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100198 case 'f':
199 last_cmd = 0;
200 if (p[1] == 'r')
201 {
202 last_cmd = CMD_FRAME;
203 tail = "rame";
204 }
205 else
206 {
207 last_cmd = CMD_FINISH;
208 tail = "inish";
209 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210 break;
211 case 'q': last_cmd = CMD_QUIT;
212 tail = "uit";
213 break;
214 case 'i': last_cmd = CMD_INTERRUPT;
215 tail = "nterrupt";
216 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100217 case 'b': last_cmd = CMD_BACKTRACE;
218 if (p[1] == 't')
219 tail = "t";
220 else
221 tail = "acktrace";
222 break;
223 case 'w': last_cmd = CMD_BACKTRACE;
224 tail = "here";
225 break;
226 case 'u': last_cmd = CMD_UP;
227 tail = "p";
228 break;
229 case 'd': last_cmd = CMD_DOWN;
230 tail = "own";
231 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 default: last_cmd = 0;
233 }
234 if (last_cmd != 0)
235 {
236 /* Check that the tail matches. */
237 ++p;
238 while (*p != NUL && *p == *tail)
239 {
240 ++p;
241 ++tail;
242 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100243 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 last_cmd = 0;
245 }
246 }
247
248 if (last_cmd != 0)
249 {
250 /* Execute debug command: decided where to break next and
251 * return. */
252 switch (last_cmd)
253 {
254 case CMD_CONT:
255 debug_break_level = -1;
256 break;
257 case CMD_NEXT:
258 debug_break_level = ex_nesting_level;
259 break;
260 case CMD_STEP:
261 debug_break_level = 9999;
262 break;
263 case CMD_FINISH:
264 debug_break_level = ex_nesting_level - 1;
265 break;
266 case CMD_QUIT:
267 got_int = TRUE;
268 debug_break_level = -1;
269 break;
270 case CMD_INTERRUPT:
271 got_int = TRUE;
272 debug_break_level = 9999;
273 /* Do not repeat ">interrupt" cmd, continue stepping. */
274 last_cmd = CMD_STEP;
275 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100276 case CMD_BACKTRACE:
277 do_showbacktrace(cmd);
278 continue;
279 case CMD_FRAME:
280 if (*p == NUL)
281 {
282 do_showbacktrace(cmd);
283 }
284 else
285 {
286 p = skipwhite(p);
287 do_setdebugtracelevel(p);
288 }
289 continue;
290 case CMD_UP:
291 debug_backtrace_level++;
292 do_checkbacktracelevel();
293 continue;
294 case CMD_DOWN:
295 debug_backtrace_level--;
296 do_checkbacktracelevel();
297 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100299 /* Going out reset backtrace_level */
300 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301 break;
302 }
303
304 /* don't debug this command */
305 n = debug_break_level;
306 debug_break_level = -1;
307 (void)do_cmdline(cmdline, getexline, NULL,
308 DOCMD_VERBOSE|DOCMD_EXCRESET);
309 debug_break_level = n;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 }
311 lines_left = Rows - 1;
312 }
313 vim_free(cmdline);
314
315 --RedrawingDisabled;
316 --no_wait_return;
317 redraw_all_later(NOT_VALID);
318 need_wait_return = FALSE;
319 msg_scroll = save_msg_scroll;
320 lines_left = Rows - 1;
321 State = save_State;
322 did_emsg = save_did_emsg;
323 cmd_silent = save_cmd_silent;
324 msg_silent = save_msg_silent;
325 emsg_silent = save_emsg_silent;
326 redir_off = save_redir_off;
327
328 /* Only print the message again when typing a command before coming back
329 * here. */
330 debug_did_msg = TRUE;
331}
332
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100333 static int
334get_maxbacktrace_level(void)
335{
336 char *p, *q;
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200337 int maxbacktrace = 0;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100338
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100339 if (sourcing_name != NULL)
340 {
341 p = (char *)sourcing_name;
342 while ((q = strstr(p, "..")) != NULL)
343 {
344 p = q + 2;
345 maxbacktrace++;
346 }
347 }
348 return maxbacktrace;
349}
350
351 static void
352do_setdebugtracelevel(char_u *arg)
353{
354 int level;
355
356 level = atoi((char *)arg);
357 if (*arg == '+' || level < 0)
358 debug_backtrace_level += level;
359 else
360 debug_backtrace_level = level;
361
362 do_checkbacktracelevel();
363}
364
365 static void
366do_checkbacktracelevel(void)
367{
368 if (debug_backtrace_level < 0)
369 {
370 debug_backtrace_level = 0;
371 MSG(_("frame is zero"));
372 }
373 else
374 {
375 int max = get_maxbacktrace_level();
376
377 if (debug_backtrace_level > max)
378 {
379 debug_backtrace_level = max;
380 smsg((char_u *)_("frame at highest level: %d"), max);
381 }
382 }
383}
384
385 static void
386do_showbacktrace(char_u *cmd)
387{
388 char *cur;
389 char *next;
390 int i = 0;
391 int max = get_maxbacktrace_level();
392
393 if (sourcing_name != NULL)
394 {
395 cur = (char *)sourcing_name;
396 while (!got_int)
397 {
398 next = strstr(cur, "..");
399 if (next != NULL)
400 *next = NUL;
401 if (i == max - debug_backtrace_level)
402 smsg((char_u *)"->%d %s", max - i, cur);
403 else
404 smsg((char_u *)" %d %s", max - i, cur);
405 ++i;
406 if (next == NULL)
407 break;
408 *next = '.';
409 cur = next + 2;
410 }
411 }
412 if (sourcing_lnum != 0)
413 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
414 else
415 smsg((char_u *)_("cmd: %s"), cmd);
416}
417
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418/*
419 * ":debug".
420 */
421 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100422ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423{
424 int debug_break_level_save = debug_break_level;
425
426 debug_break_level = 9999;
427 do_cmdline_cmd(eap->arg);
428 debug_break_level = debug_break_level_save;
429}
430
431static char_u *debug_breakpoint_name = NULL;
432static linenr_T debug_breakpoint_lnum;
433
434/*
435 * When debugging or a breakpoint is set on a skipped command, no debug prompt
436 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
437 * debug_skipped_name is then set to the source name in the breakpoint case. If
438 * a skipped command decides itself that a debug prompt should be displayed, it
439 * can do so by calling dbg_check_skipped().
440 */
441static int debug_skipped;
442static char_u *debug_skipped_name;
443
444/*
445 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
446 * at or below the break level. But only when the line is actually
447 * executed. Return TRUE and set breakpoint_name for skipped commands that
448 * decide to execute something themselves.
449 * Called from do_one_cmd() before executing a command.
450 */
451 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100452dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453{
454 char_u *p;
455
456 debug_skipped = FALSE;
457 if (debug_breakpoint_name != NULL)
458 {
459 if (!eap->skip)
460 {
461 /* replace K_SNR with "<SNR>" */
462 if (debug_breakpoint_name[0] == K_SPECIAL
463 && debug_breakpoint_name[1] == KS_EXTRA
464 && debug_breakpoint_name[2] == (int)KE_SNR)
465 p = (char_u *)"<SNR>";
466 else
467 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000468 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
469 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 debug_breakpoint_name + (*p == NUL ? 0 : 3),
471 (long)debug_breakpoint_lnum);
472 debug_breakpoint_name = NULL;
473 do_debug(eap->cmd);
474 }
475 else
476 {
477 debug_skipped = TRUE;
478 debug_skipped_name = debug_breakpoint_name;
479 debug_breakpoint_name = NULL;
480 }
481 }
482 else if (ex_nesting_level <= debug_break_level)
483 {
484 if (!eap->skip)
485 do_debug(eap->cmd);
486 else
487 {
488 debug_skipped = TRUE;
489 debug_skipped_name = NULL;
490 }
491 }
492}
493
494/*
495 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
496 * set. Return TRUE when the debug mode is entered this time.
497 */
498 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100499dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500{
501 int prev_got_int;
502
503 if (debug_skipped)
504 {
505 /*
506 * Save the value of got_int and reset it. We don't want a previous
507 * interruption cause flushing the input buffer.
508 */
509 prev_got_int = got_int;
510 got_int = FALSE;
511 debug_breakpoint_name = debug_skipped_name;
512 /* eap->skip is TRUE */
513 eap->skip = FALSE;
514 (void)dbg_check_breakpoint(eap);
515 eap->skip = TRUE;
516 got_int |= prev_got_int;
517 return TRUE;
518 }
519 return FALSE;
520}
521
522/*
523 * The list of breakpoints: dbg_breakp.
524 * This is a grow-array of structs.
525 */
526struct debuggy
527{
528 int dbg_nr; /* breakpoint number */
529 int dbg_type; /* DBG_FUNC or DBG_FILE */
530 char_u *dbg_name; /* function or file name */
531 regprog_T *dbg_prog; /* regexp program */
532 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534};
535
536static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000537#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
538#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539static int last_breakp = 0; /* nr of last defined breakpoint */
540
Bram Moolenaar05159a02005-02-26 23:04:13 +0000541#ifdef FEAT_PROFILE
542/* Profiling uses file and func names similar to breakpoints. */
543static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
544#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545#define DBG_FUNC 1
546#define DBG_FILE 2
547
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100548static int dbg_parsearg(char_u *arg, garray_T *gap);
549static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550
551/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000552 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
553 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
554 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 * Returns FAIL for failure.
556 */
557 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100558dbg_parsearg(
559 char_u *arg,
560 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561{
562 char_u *p = arg;
563 char_u *q;
564 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000565 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566
Bram Moolenaar05159a02005-02-26 23:04:13 +0000567 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000569 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570
571 /* Find "func" or "file". */
572 if (STRNCMP(p, "func", 4) == 0)
573 bp->dbg_type = DBG_FUNC;
574 else if (STRNCMP(p, "file", 4) == 0)
575 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000576 else if (
577#ifdef FEAT_PROFILE
578 gap != &prof_ga &&
579#endif
580 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000581 {
582 if (curbuf->b_ffname == NULL)
583 {
584 EMSG(_(e_noname));
585 return FAIL;
586 }
587 bp->dbg_type = DBG_FILE;
588 here = TRUE;
589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590 else
591 {
592 EMSG2(_(e_invarg2), p);
593 return FAIL;
594 }
595 p = skipwhite(p + 4);
596
597 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000598 if (here)
599 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000600 else if (
601#ifdef FEAT_PROFILE
602 gap != &prof_ga &&
603#endif
604 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 {
606 bp->dbg_lnum = getdigits(&p);
607 p = skipwhite(p);
608 }
609 else
610 bp->dbg_lnum = 0;
611
612 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000613 if ((!here && *p == NUL)
614 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
616 {
617 EMSG2(_(e_invarg2), arg);
618 return FAIL;
619 }
620
621 if (bp->dbg_type == DBG_FUNC)
622 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000623 else if (here)
624 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 else
626 {
627 /* Expand the file name in the same way as do_source(). This means
628 * doing it twice, so that $DIR/file gets expanded when $DIR is
629 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 if (q == NULL)
632 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 vim_free(q);
635 if (p == NULL)
636 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000637 if (*p != '*')
638 {
639 bp->dbg_name = fix_fname(p);
640 vim_free(p);
641 }
642 else
643 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 }
645
646 if (bp->dbg_name == NULL)
647 return FAIL;
648 return OK;
649}
650
651/*
652 * ":breakadd".
653 */
654 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100655ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656{
657 struct debuggy *bp;
658 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000659 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660
Bram Moolenaar05159a02005-02-26 23:04:13 +0000661 gap = &dbg_breakp;
662#ifdef FEAT_PROFILE
663 if (eap->cmdidx == CMD_profile)
664 gap = &prof_ga;
665#endif
666
667 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000669 bp = &DEBUGGY(gap, gap->ga_len);
670 bp->dbg_forceit = eap->forceit;
671
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
673 if (pat != NULL)
674 {
675 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
676 vim_free(pat);
677 }
678 if (pat == NULL || bp->dbg_prog == NULL)
679 vim_free(bp->dbg_name);
680 else
681 {
682 if (bp->dbg_lnum == 0) /* default line number is 1 */
683 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000684#ifdef FEAT_PROFILE
685 if (eap->cmdidx != CMD_profile)
686#endif
687 {
688 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
689 ++debug_tick;
690 }
691 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 }
693 }
694}
695
696/*
697 * ":debuggreedy".
698 */
699 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100700ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701{
702 if (eap->addr_count == 0 || eap->line2 != 0)
703 debug_greedy = TRUE;
704 else
705 debug_greedy = FALSE;
706}
707
708/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000709 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 */
711 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100712ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713{
714 struct debuggy *bp, *bpi;
715 int nr;
716 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000717 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 int i;
719 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000720 garray_T *gap;
721
722 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000723 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200724 {
725#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000726 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200727#else
728 ex_ni(eap);
729 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000730#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200731 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732
733 if (vim_isdigit(*eap->arg))
734 {
735 /* ":breakdel {nr}" */
736 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000737 for (i = 0; i < gap->ga_len; ++i)
738 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 {
740 todel = i;
741 break;
742 }
743 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000744 else if (*eap->arg == '*')
745 {
746 todel = 0;
747 del_all = TRUE;
748 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 else
750 {
751 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000752 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000754 bp = &DEBUGGY(gap, gap->ga_len);
755 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000757 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 if (bp->dbg_type == bpi->dbg_type
759 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
760 && (bp->dbg_lnum == bpi->dbg_lnum
761 || (bp->dbg_lnum == 0
762 && (best_lnum == 0
763 || bpi->dbg_lnum < best_lnum))))
764 {
765 todel = i;
766 best_lnum = bpi->dbg_lnum;
767 }
768 }
769 vim_free(bp->dbg_name);
770 }
771
772 if (todel < 0)
773 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
774 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000775 {
776 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000777 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000778 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200779 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000780 --gap->ga_len;
781 if (todel < gap->ga_len)
782 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
783 (gap->ga_len - todel) * sizeof(struct debuggy));
784#ifdef FEAT_PROFILE
785 if (eap->cmdidx == CMD_breakdel)
786#endif
787 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000788 if (!del_all)
789 break;
790 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000791
792 /* If all breakpoints were removed clear the array. */
793 if (gap->ga_len == 0)
794 ga_clear(gap);
795 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796}
797
798/*
799 * ":breaklist".
800 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100802ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803{
804 struct debuggy *bp;
805 int i;
806
807 if (dbg_breakp.ga_len == 0)
808 MSG(_("No breakpoints defined"));
809 else
810 for (i = 0; i < dbg_breakp.ga_len; ++i)
811 {
812 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200813 if (bp->dbg_type == DBG_FILE)
814 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 smsg((char_u *)_("%3d %s %s line %ld"),
816 bp->dbg_nr,
817 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200818 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 (long)bp->dbg_lnum);
820 }
821}
822
823/*
824 * Find a breakpoint for a function or sourced file.
825 * Returns line number at which to break; zero when no matching breakpoint.
826 */
827 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100828dbg_find_breakpoint(
829 int file, /* TRUE for a file, FALSE for a function */
830 char_u *fname, /* file or function name */
831 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000833 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
834}
835
836#if defined(FEAT_PROFILE) || defined(PROTO)
837/*
838 * Return TRUE if profiling is on for a function or sourced file.
839 */
840 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100841has_profiling(
842 int file, /* TRUE for a file, FALSE for a function */
843 char_u *fname, /* file or function name */
844 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845{
846 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
847 != (linenr_T)0);
848}
849#endif
850
851/*
852 * Common code for dbg_find_breakpoint() and has_profiling().
853 */
854 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100855debuggy_find(
856 int file, /* TRUE for a file, FALSE for a function */
857 char_u *fname, /* file or function name */
858 linenr_T after, /* after this line number */
859 garray_T *gap, /* either &dbg_breakp or &prof_ga */
860 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 struct debuggy *bp;
863 int i;
864 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 char_u *name = fname;
866 int prev_got_int;
867
Bram Moolenaar05159a02005-02-26 23:04:13 +0000868 /* Return quickly when there are no breakpoints. */
869 if (gap->ga_len == 0)
870 return (linenr_T)0;
871
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 /* Replace K_SNR in function name with "<SNR>". */
873 if (!file && fname[0] == K_SPECIAL)
874 {
875 name = alloc((unsigned)STRLEN(fname) + 3);
876 if (name == NULL)
877 name = fname;
878 else
879 {
880 STRCPY(name, "<SNR>");
881 STRCPY(name + 5, fname + 3);
882 }
883 }
884
Bram Moolenaar05159a02005-02-26 23:04:13 +0000885 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000887 /* Skip entries that are not useful or are for a line that is beyond
888 * an already found breakpoint. */
889 bp = &DEBUGGY(gap, i);
890 if (((bp->dbg_type == DBG_FILE) == file && (
891#ifdef FEAT_PROFILE
892 gap == &prof_ga ||
893#endif
894 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000897 * Save the value of got_int and reset it. We don't want a
898 * previous interruption cancel matching, only hitting CTRL-C
899 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900 */
901 prev_got_int = got_int;
902 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100903 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000904 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000906 if (fp != NULL)
907 *fp = bp->dbg_forceit;
908 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 got_int |= prev_got_int;
910 }
911 }
912 if (name != fname)
913 vim_free(name);
914
915 return lnum;
916}
917
918/*
919 * Called when a breakpoint was encountered.
920 */
921 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100922dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923{
924 /* We need to check if this line is actually executed in do_one_cmd() */
925 debug_breakpoint_name = name;
926 debug_breakpoint_lnum = lnum;
927}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000928
929
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000930# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000931/*
932 * Store the current time in "tm".
933 */
934 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100935profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000936{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000937# ifdef WIN3264
938 QueryPerformanceCounter(tm);
939# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000940 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000941# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000942}
943
944/*
945 * Compute the elapsed time from "tm" till now and store in "tm".
946 */
947 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100948profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000949{
950 proftime_T now;
951
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000952# ifdef WIN3264
953 QueryPerformanceCounter(&now);
954 tm->QuadPart = now.QuadPart - tm->QuadPart;
955# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000956 gettimeofday(&now, NULL);
957 tm->tv_usec = now.tv_usec - tm->tv_usec;
958 tm->tv_sec = now.tv_sec - tm->tv_sec;
959 if (tm->tv_usec < 0)
960 {
961 tm->tv_usec += 1000000;
962 --tm->tv_sec;
963 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000964# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000965}
966
967/*
968 * Subtract the time "tm2" from "tm".
969 */
970 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100971profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000972{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000973# ifdef WIN3264
974 tm->QuadPart -= tm2->QuadPart;
975# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000976 tm->tv_usec -= tm2->tv_usec;
977 tm->tv_sec -= tm2->tv_sec;
978 if (tm->tv_usec < 0)
979 {
980 tm->tv_usec += 1000000;
981 --tm->tv_sec;
982 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000983# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000984}
985
986/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000987 * Return a string that represents the time in "tm".
988 * Uses a static buffer!
989 */
990 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100991profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000992{
993 static char buf[50];
994
995# ifdef WIN3264
996 LARGE_INTEGER fr;
997
998 QueryPerformanceFrequency(&fr);
999 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1000# else
1001 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001002# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001003 return buf;
1004}
1005
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001006# if defined(FEAT_FLOAT) || defined(PROTO)
1007/*
1008 * Return a float that represents the time in "tm".
1009 */
1010 float_T
1011profile_float(proftime_T *tm)
1012{
1013# ifdef WIN3264
1014 LARGE_INTEGER fr;
1015
1016 QueryPerformanceFrequency(&fr);
1017 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
1018# else
1019 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
1020# endif
1021}
1022# endif
1023
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001024/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001025 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001026 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001027 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001028profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001029{
1030 if (msec <= 0) /* no limit */
1031 profile_zero(tm);
1032 else
1033 {
1034# ifdef WIN3264
1035 LARGE_INTEGER fr;
1036
1037 QueryPerformanceCounter(tm);
1038 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001039 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001040# else
1041 long usec;
1042
1043 gettimeofday(tm, NULL);
1044 usec = (long)tm->tv_usec + (long)msec * 1000;
1045 tm->tv_usec = usec % 1000000L;
1046 tm->tv_sec += usec / 1000000L;
1047# endif
1048 }
1049}
1050
1051/*
1052 * Return TRUE if the current time is past "tm".
1053 */
1054 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001055profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001056{
1057 proftime_T now;
1058
1059# ifdef WIN3264
1060 if (tm->QuadPart == 0) /* timer was not set */
1061 return FALSE;
1062 QueryPerformanceCounter(&now);
1063 return (now.QuadPart > tm->QuadPart);
1064# else
1065 if (tm->tv_sec == 0) /* timer was not set */
1066 return FALSE;
1067 gettimeofday(&now, NULL);
1068 return (now.tv_sec > tm->tv_sec
1069 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1070# endif
1071}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001072
1073/*
1074 * Set the time in "tm" to zero.
1075 */
1076 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001077profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001078{
1079# ifdef WIN3264
1080 tm->QuadPart = 0;
1081# else
1082 tm->tv_usec = 0;
1083 tm->tv_sec = 0;
1084# endif
1085}
1086
Bram Moolenaar76929292008-01-06 19:07:36 +00001087# endif /* FEAT_PROFILE || FEAT_RELTIME */
1088
Bram Moolenaar975b5272016-03-15 23:10:59 +01001089# if defined(FEAT_TIMERS) || defined(PROTO)
1090static timer_T *first_timer = NULL;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001091static long last_timer_id = 0;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001092
Bram Moolenaar75537a92016-09-05 22:45:28 +02001093# ifdef WIN3264
1094# define GET_TIMEDIFF(timer, now) \
1095 (long)(((double)(timer->tr_due.QuadPart - now.QuadPart) \
Bram Moolenaara7c023e2016-10-12 12:13:35 +02001096 / (double)fr.QuadPart) * 1000)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001097# else
1098# define GET_TIMEDIFF(timer, now) \
1099 (timer->tr_due.tv_sec - now.tv_sec) * 1000 \
Bram Moolenaara7c023e2016-10-12 12:13:35 +02001100 + (timer->tr_due.tv_usec - now.tv_usec) / 1000
Bram Moolenaar75537a92016-09-05 22:45:28 +02001101# endif
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001102
Bram Moolenaar975b5272016-03-15 23:10:59 +01001103/*
1104 * Insert a timer in the list of timers.
1105 */
1106 static void
1107insert_timer(timer_T *timer)
1108{
1109 timer->tr_next = first_timer;
1110 timer->tr_prev = NULL;
1111 if (first_timer != NULL)
1112 first_timer->tr_prev = timer;
1113 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +02001114 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001115}
1116
1117/*
1118 * Take a timer out of the list of timers.
1119 */
1120 static void
1121remove_timer(timer_T *timer)
1122{
1123 if (timer->tr_prev == NULL)
1124 first_timer = timer->tr_next;
1125 else
1126 timer->tr_prev->tr_next = timer->tr_next;
1127 if (timer->tr_next != NULL)
1128 timer->tr_next->tr_prev = timer->tr_prev;
1129}
1130
1131 static void
1132free_timer(timer_T *timer)
1133{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001134 free_callback(timer->tr_callback, timer->tr_partial);
1135 vim_free(timer);
Bram Moolenaar975b5272016-03-15 23:10:59 +01001136}
1137
1138/*
1139 * Create a timer and return it. NULL if out of memory.
1140 * Caller should set the callback.
1141 */
1142 timer_T *
1143create_timer(long msec, int repeat)
1144{
1145 timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
Bram Moolenaaree39ef02016-09-10 19:17:42 +02001146 long prev_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001147
1148 if (timer == NULL)
1149 return NULL;
Bram Moolenaaree39ef02016-09-10 19:17:42 +02001150 if (++last_timer_id <= prev_id)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001151 /* Overflow! Might cause duplicates... */
1152 last_timer_id = 0;
1153 timer->tr_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001154 insert_timer(timer);
1155 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001156 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001157 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001158
1159 profile_setlimit(msec, &timer->tr_due);
1160 return timer;
1161}
1162
1163/*
1164 * Invoke the callback of "timer".
1165 */
1166 static void
1167timer_callback(timer_T *timer)
1168{
1169 typval_T rettv;
1170 int dummy;
1171 typval_T argv[2];
1172
1173 argv[0].v_type = VAR_NUMBER;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001174 argv[0].vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001175 argv[1].v_type = VAR_UNKNOWN;
1176
1177 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
Bram Moolenaardf48fb42016-07-22 21:50:18 +02001178 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar975b5272016-03-15 23:10:59 +01001179 timer->tr_partial, NULL);
1180 clear_tv(&rettv);
1181}
1182
1183/*
1184 * Call timers that are due.
1185 * Return the time in msec until the next timer is due.
1186 */
1187 long
Bram Moolenaarcf089462016-06-12 21:18:43 +02001188check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001189{
1190 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001191 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001192 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001193 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001194 proftime_T now;
1195 int did_one = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001196 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001197# ifdef WIN3264
1198 LARGE_INTEGER fr;
1199
1200 QueryPerformanceFrequency(&fr);
1201# endif
Bram Moolenaar75537a92016-09-05 22:45:28 +02001202 profile_start(&now);
1203 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001204 {
Bram Moolenaar75537a92016-09-05 22:45:28 +02001205 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001206
Bram Moolenaar75537a92016-09-05 22:45:28 +02001207 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
1208 continue;
1209 this_due = GET_TIMEDIFF(timer, now);
1210 if (this_due <= 1)
1211 {
Bram Moolenaar1e8e1452017-06-24 16:03:06 +02001212 int save_timer_busy = timer_busy;
1213 int save_vgetc_busy = vgetc_busy;
1214
1215 timer_busy = timer_busy > 0 || vgetc_busy > 0;
1216 vgetc_busy = 0;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001217 timer->tr_firing = TRUE;
1218 timer_callback(timer);
1219 timer->tr_firing = FALSE;
1220 timer_next = timer->tr_next;
1221 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +02001222 timer_busy = save_timer_busy;
1223 vgetc_busy = save_vgetc_busy;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001224
1225 /* Only fire the timer again if it repeats and stop_timer() wasn't
1226 * called while inside the callback (tr_id == -1). */
1227 if (timer->tr_repeat != 0 && timer->tr_id != -1)
1228 {
1229 profile_setlimit(timer->tr_interval, &timer->tr_due);
1230 this_due = GET_TIMEDIFF(timer, now);
1231 if (this_due < 1)
1232 this_due = 1;
1233 if (timer->tr_repeat > 0)
1234 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001235 }
Bram Moolenaar75537a92016-09-05 22:45:28 +02001236 else
1237 {
1238 this_due = -1;
1239 remove_timer(timer);
1240 free_timer(timer);
1241 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001242 }
Bram Moolenaar75537a92016-09-05 22:45:28 +02001243 if (this_due > 0 && (next_due == -1 || next_due > this_due))
1244 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001245 }
1246
1247 if (did_one)
1248 redraw_after_callback();
1249
Bram Moolenaar75537a92016-09-05 22:45:28 +02001250 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001251}
1252
1253/*
1254 * Find a timer by ID. Returns NULL if not found;
1255 */
1256 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +02001257find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001258{
1259 timer_T *timer;
1260
Bram Moolenaar75537a92016-09-05 22:45:28 +02001261 if (id >= 0)
1262 {
1263 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1264 if (timer->tr_id == id)
1265 return timer;
1266 }
1267 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001268}
1269
1270
1271/*
1272 * Stop a timer and delete it.
1273 */
1274 void
1275stop_timer(timer_T *timer)
1276{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001277 if (timer->tr_firing)
1278 /* Free the timer after the callback returns. */
1279 timer->tr_id = -1;
1280 else
1281 {
1282 remove_timer(timer);
1283 free_timer(timer);
1284 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001285}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001286
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001287 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001288stop_all_timers(void)
1289{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001290 timer_T *timer;
1291 timer_T *timer_next;
1292
1293 for (timer = first_timer; timer != NULL; timer = timer_next)
1294 {
1295 timer_next = timer->tr_next;
1296 stop_timer(timer);
1297 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001298}
1299
1300 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001301add_timer_info(typval_T *rettv, timer_T *timer)
1302{
1303 list_T *list = rettv->vval.v_list;
1304 dict_T *dict = dict_alloc();
1305 dictitem_T *di;
1306 long remaining;
1307 proftime_T now;
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001308# ifdef WIN3264
1309 LARGE_INTEGER fr;
1310#endif
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001311
1312 if (dict == NULL)
1313 return;
1314 list_append_dict(list, dict);
1315
Bram Moolenaar75537a92016-09-05 22:45:28 +02001316 dict_add_nr_str(dict, "id", timer->tr_id, NULL);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001317 dict_add_nr_str(dict, "time", (long)timer->tr_interval, NULL);
1318
1319 profile_start(&now);
1320# ifdef WIN3264
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001321 QueryPerformanceFrequency(&fr);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001322# endif
Bram Moolenaar75537a92016-09-05 22:45:28 +02001323 remaining = GET_TIMEDIFF(timer, now);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001324 dict_add_nr_str(dict, "remaining", (long)remaining, NULL);
1325
1326 dict_add_nr_str(dict, "repeat",
1327 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1), NULL);
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001328 dict_add_nr_str(dict, "paused", (long)(timer->tr_paused), NULL);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001329
1330 di = dictitem_alloc((char_u *)"callback");
1331 if (di != NULL)
1332 {
1333 if (dict_add(dict, di) == FAIL)
1334 vim_free(di);
1335 else if (timer->tr_partial != NULL)
1336 {
1337 di->di_tv.v_type = VAR_PARTIAL;
1338 di->di_tv.vval.v_partial = timer->tr_partial;
1339 ++timer->tr_partial->pt_refcount;
1340 }
1341 else
1342 {
1343 di->di_tv.v_type = VAR_FUNC;
1344 di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
1345 }
1346 di->di_tv.v_lock = 0;
1347 }
1348}
1349
1350 void
1351add_timer_info_all(typval_T *rettv)
1352{
1353 timer_T *timer;
1354
1355 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001356 if (timer->tr_id != -1)
1357 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001358}
1359
Bram Moolenaare3188e22016-05-31 21:13:04 +02001360/*
1361 * Mark references in partials of timers.
1362 */
1363 int
1364set_ref_in_timer(int copyID)
1365{
1366 int abort = FALSE;
1367 timer_T *timer;
1368 typval_T tv;
1369
1370 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1371 {
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +02001372 if (timer->tr_partial != NULL)
1373 {
1374 tv.v_type = VAR_PARTIAL;
1375 tv.vval.v_partial = timer->tr_partial;
1376 }
1377 else
1378 {
1379 tv.v_type = VAR_FUNC;
1380 tv.vval.v_string = timer->tr_callback;
1381 }
Bram Moolenaare3188e22016-05-31 21:13:04 +02001382 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1383 }
1384 return abort;
1385}
Bram Moolenaar623e2632016-07-30 22:47:56 +02001386
1387# if defined(EXITFREE) || defined(PROTO)
1388 void
1389timer_free_all()
1390{
1391 timer_T *timer;
1392
1393 while (first_timer != NULL)
1394 {
1395 timer = first_timer;
1396 remove_timer(timer);
1397 free_timer(timer);
1398 }
1399}
1400# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +01001401# endif
1402
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001403#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1404# if defined(HAVE_MATH_H)
1405# include <math.h>
1406# endif
1407
1408/*
1409 * Divide the time "tm" by "count" and store in "tm2".
1410 */
1411 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001412profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001413{
1414 if (count == 0)
1415 profile_zero(tm2);
1416 else
1417 {
1418# ifdef WIN3264
1419 tm2->QuadPart = tm->QuadPart / count;
1420# else
1421 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1422
1423 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001424 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001425# endif
1426 }
1427}
1428#endif
1429
Bram Moolenaar76929292008-01-06 19:07:36 +00001430# if defined(FEAT_PROFILE) || defined(PROTO)
1431/*
1432 * Functions for profiling.
1433 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001434static void script_do_profile(scriptitem_T *si);
1435static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001436static proftime_T prof_wait_time;
1437
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001438/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001439 * Add the time "tm2" to "tm".
1440 */
1441 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001442profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001443{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001444# ifdef WIN3264
1445 tm->QuadPart += tm2->QuadPart;
1446# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001447 tm->tv_usec += tm2->tv_usec;
1448 tm->tv_sec += tm2->tv_sec;
1449 if (tm->tv_usec >= 1000000)
1450 {
1451 tm->tv_usec -= 1000000;
1452 ++tm->tv_sec;
1453 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001454# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001455}
1456
1457/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001458 * Add the "self" time from the total time and the children's time.
1459 */
1460 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001461profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001462{
1463 /* Check that the result won't be negative. Can happen with recursive
1464 * calls. */
1465#ifdef WIN3264
1466 if (total->QuadPart <= children->QuadPart)
1467 return;
1468#else
1469 if (total->tv_sec < children->tv_sec
1470 || (total->tv_sec == children->tv_sec
1471 && total->tv_usec <= children->tv_usec))
1472 return;
1473#endif
1474 profile_add(self, total);
1475 profile_sub(self, children);
1476}
1477
1478/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001479 * Get the current waittime.
1480 */
1481 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001482profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001483{
1484 *tm = prof_wait_time;
1485}
1486
1487/*
1488 * Subtract the passed waittime since "tm" from "tma".
1489 */
1490 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001491profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001492{
1493 proftime_T tm3 = prof_wait_time;
1494
1495 profile_sub(&tm3, tm);
1496 profile_sub(tma, &tm3);
1497}
1498
1499/*
1500 * Return TRUE if "tm1" and "tm2" are equal.
1501 */
1502 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001503profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001504{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001505# ifdef WIN3264
1506 return (tm1->QuadPart == tm2->QuadPart);
1507# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001508 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001509# endif
1510}
1511
1512/*
1513 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1514 */
1515 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001516profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001517{
1518# ifdef WIN3264
1519 return (int)(tm2->QuadPart - tm1->QuadPart);
1520# else
1521 if (tm1->tv_sec == tm2->tv_sec)
1522 return tm2->tv_usec - tm1->tv_usec;
1523 return tm2->tv_sec - tm1->tv_sec;
1524# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001525}
1526
Bram Moolenaar05159a02005-02-26 23:04:13 +00001527static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001528static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001529
1530/*
1531 * ":profile cmd args"
1532 */
1533 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001534ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001535{
1536 char_u *e;
1537 int len;
1538
1539 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001540 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001541 e = skipwhite(e);
1542
1543 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1544 {
1545 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001546 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001547 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001548 profile_zero(&prof_wait_time);
1549 set_vim_var_nr(VV_PROFILING, 1L);
1550 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001551 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001552 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001553 else if (STRCMP(eap->arg, "pause") == 0)
1554 {
1555 if (do_profiling == PROF_YES)
1556 profile_start(&pause_time);
1557 do_profiling = PROF_PAUSED;
1558 }
1559 else if (STRCMP(eap->arg, "continue") == 0)
1560 {
1561 if (do_profiling == PROF_PAUSED)
1562 {
1563 profile_end(&pause_time);
1564 profile_add(&prof_wait_time, &pause_time);
1565 }
1566 do_profiling = PROF_YES;
1567 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001568 else
1569 {
1570 /* The rest is similar to ":breakadd". */
1571 ex_breakadd(eap);
1572 }
1573}
1574
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001575/* Command line expansion for :profile. */
1576static enum
1577{
1578 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001579 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001580} pexpand_what;
1581
1582static char *pexpand_cmds[] = {
1583 "start",
1584#define PROFCMD_START 0
1585 "pause",
1586#define PROFCMD_PAUSE 1
1587 "continue",
1588#define PROFCMD_CONTINUE 2
1589 "func",
1590#define PROFCMD_FUNC 3
1591 "file",
1592#define PROFCMD_FILE 4
1593 NULL
1594#define PROFCMD_LAST 5
1595};
1596
1597/*
1598 * Function given to ExpandGeneric() to obtain the profile command
1599 * specific expansion.
1600 */
1601 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001602get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001603{
1604 switch (pexpand_what)
1605 {
1606 case PEXP_SUBCMD:
1607 return (char_u *)pexpand_cmds[idx];
1608 /* case PEXP_FUNC: TODO */
1609 default:
1610 return NULL;
1611 }
1612}
1613
1614/*
1615 * Handle command line completion for :profile command.
1616 */
1617 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001618set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001619{
1620 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001621
1622 /* Default: expand subcommands. */
1623 xp->xp_context = EXPAND_PROFILE;
1624 pexpand_what = PEXP_SUBCMD;
1625 xp->xp_pattern = arg;
1626
1627 end_subcmd = skiptowhite(arg);
1628 if (*end_subcmd == NUL)
1629 return;
1630
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001631 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001632 {
1633 xp->xp_context = EXPAND_FILES;
1634 xp->xp_pattern = skipwhite(end_subcmd);
1635 return;
1636 }
1637
1638 /* TODO: expand function names after "func" */
1639 xp->xp_context = EXPAND_NOTHING;
1640}
1641
Bram Moolenaar05159a02005-02-26 23:04:13 +00001642/*
1643 * Dump the profiling info.
1644 */
1645 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001646profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001647{
1648 FILE *fd;
1649
1650 if (profile_fname != NULL)
1651 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001652 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001653 if (fd == NULL)
1654 EMSG2(_(e_notopen), profile_fname);
1655 else
1656 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001657 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001658 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001659 fclose(fd);
1660 }
1661 }
1662}
1663
1664/*
1665 * Start profiling script "fp".
1666 */
1667 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001668script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001669{
1670 si->sn_pr_count = 0;
1671 profile_zero(&si->sn_pr_total);
1672 profile_zero(&si->sn_pr_self);
1673
1674 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1675 si->sn_prl_idx = -1;
1676 si->sn_prof_on = TRUE;
1677 si->sn_pr_nest = 0;
1678}
1679
1680/*
1681 * save time when starting to invoke another script or function.
1682 */
1683 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001684script_prof_save(
1685 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001686{
1687 scriptitem_T *si;
1688
1689 if (current_SID > 0 && current_SID <= script_items.ga_len)
1690 {
1691 si = &SCRIPT_ITEM(current_SID);
1692 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1693 profile_start(&si->sn_pr_child);
1694 }
1695 profile_get_wait(tm);
1696}
1697
1698/*
1699 * Count time spent in children after invoking another script or function.
1700 */
1701 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001702script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001703{
1704 scriptitem_T *si;
1705
1706 if (current_SID > 0 && current_SID <= script_items.ga_len)
1707 {
1708 si = &SCRIPT_ITEM(current_SID);
1709 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1710 {
1711 profile_end(&si->sn_pr_child);
1712 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1713 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1714 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1715 }
1716 }
1717}
1718
1719static proftime_T inchar_time;
1720
1721/*
1722 * Called when starting to wait for the user to type a character.
1723 */
1724 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001725prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001726{
1727 profile_start(&inchar_time);
1728}
1729
1730/*
1731 * Called when finished waiting for the user to type a character.
1732 */
1733 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001734prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001735{
1736 profile_end(&inchar_time);
1737 profile_add(&prof_wait_time, &inchar_time);
1738}
1739
1740/*
1741 * Dump the profiling results for all scripts in file "fd".
1742 */
1743 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001744script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001745{
1746 int id;
1747 scriptitem_T *si;
1748 int i;
1749 FILE *sfd;
1750 sn_prl_T *pp;
1751
1752 for (id = 1; id <= script_items.ga_len; ++id)
1753 {
1754 si = &SCRIPT_ITEM(id);
1755 if (si->sn_prof_on)
1756 {
1757 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1758 if (si->sn_pr_count == 1)
1759 fprintf(fd, "Sourced 1 time\n");
1760 else
1761 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1762 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1763 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1764 fprintf(fd, "\n");
1765 fprintf(fd, "count total (s) self (s)\n");
1766
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001767 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001768 if (sfd == NULL)
1769 fprintf(fd, "Cannot open file!\n");
1770 else
1771 {
1772 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1773 {
1774 if (vim_fgets(IObuff, IOSIZE, sfd))
1775 break;
1776 pp = &PRL_ITEM(si, i);
1777 if (pp->snp_count > 0)
1778 {
1779 fprintf(fd, "%5d ", pp->snp_count);
1780 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1781 fprintf(fd, " ");
1782 else
1783 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1784 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1785 }
1786 else
1787 fprintf(fd, " ");
1788 fprintf(fd, "%s", IObuff);
1789 }
1790 fclose(sfd);
1791 }
1792 fprintf(fd, "\n");
1793 }
1794 }
1795}
1796
1797/*
1798 * Return TRUE when a function defined in the current script should be
1799 * profiled.
1800 */
1801 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001802prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001803{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001804 if (current_SID > 0)
1805 return SCRIPT_ITEM(current_SID).sn_pr_force;
1806 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001807}
1808
1809# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810#endif
1811
1812/*
1813 * If 'autowrite' option set, try to write the file.
1814 * Careful: autocommands may make "buf" invalid!
1815 *
1816 * return FAIL for failure, OK otherwise
1817 */
1818 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001819autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001821 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001822 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001823
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824 if (!(p_aw || p_awa) || !p_write
1825#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001826 /* never autowrite a "nofile" or "nowrite" buffer */
1827 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001829 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001830 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001831 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001832 r = buf_write_all(buf, forceit);
1833
1834 /* Writing may succeed but the buffer still changed, e.g., when there is a
1835 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001836 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001837 r = FAIL;
1838 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839}
1840
1841/*
1842 * flush all buffers, except the ones that are readonly
1843 */
1844 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001845autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846{
1847 buf_T *buf;
1848
1849 if (!(p_aw || p_awa) || !p_write)
1850 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001851 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852 if (bufIsChanged(buf) && !buf->b_p_ro)
1853 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001854#ifdef FEAT_AUTOCMD
1855 bufref_T bufref;
1856
1857 set_bufref(&bufref, buf);
1858#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859 (void)buf_write_all(buf, FALSE);
1860#ifdef FEAT_AUTOCMD
1861 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001862 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001863 buf = firstbuf;
1864#endif
1865 }
1866}
1867
1868/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001869 * Return TRUE if buffer was changed and cannot be abandoned.
1870 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001873check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001875 int forceit = (flags & CCGD_FORCEIT);
1876#ifdef FEAT_AUTOCMD
1877 bufref_T bufref;
1878
1879 set_bufref(&bufref, buf);
1880#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001881
Bram Moolenaar071d4272004-06-13 20:20:40 +00001882 if ( !forceit
1883 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001884 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1885 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886 {
1887#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1888 if ((p_confirm || cmdmod.confirm) && p_write)
1889 {
1890 buf_T *buf2;
1891 int count = 0;
1892
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001893 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001894 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 if (bufIsChanged(buf2)
1896 && (buf2->b_ffname != NULL
1897# ifdef FEAT_BROWSE
1898 || cmdmod.browse
1899# endif
1900 ))
1901 ++count;
1902# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001903 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 /* Autocommand deleted buffer, oops! It's not changed now. */
1905 return FALSE;
1906# endif
1907 dialog_changed(buf, count > 1);
1908# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001909 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910 /* Autocommand deleted buffer, oops! It's not changed now. */
1911 return FALSE;
1912# endif
1913 return bufIsChanged(buf);
1914 }
1915#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001916 if (flags & CCGD_EXCMD)
1917 EMSG(_(e_nowrtmsg));
1918 else
1919 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920 return TRUE;
1921 }
1922 return FALSE;
1923}
1924
1925#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1926
1927#if defined(FEAT_BROWSE) || defined(PROTO)
1928/*
1929 * When wanting to write a file without a file name, ask the user for a name.
1930 */
1931 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001932browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933{
1934 if (buf->b_fname == NULL)
1935 {
1936 char_u *fname;
1937
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001938 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1939 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 if (fname != NULL)
1941 {
1942 if (setfname(buf, fname, NULL, TRUE) == OK)
1943 buf->b_flags |= BF_NOTEDITED;
1944 vim_free(fname);
1945 }
1946 }
1947}
1948#endif
1949
1950/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001951 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 * Must check 'write' option first!
1953 */
1954 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001955dialog_changed(
1956 buf_T *buf,
1957 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001959 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960 int ret;
1961 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001962 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001964 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 (buf->b_fname != NULL) ?
1966 buf->b_fname : (char_u *)_("Untitled"));
1967 if (checkall)
1968 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1969 else
1970 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1971
Bram Moolenaar8218f602012-04-25 17:32:18 +02001972 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1973 * function. */
1974 ea.append = ea.forceit = FALSE;
1975
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976 if (ret == VIM_YES)
1977 {
1978#ifdef FEAT_BROWSE
1979 /* May get file name, when there is none */
1980 browse_save_fname(buf);
1981#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001982 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1983 buf->b_fname, buf->b_ffname, FALSE) == OK)
1984 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001985 (void)buf_write_all(buf, FALSE);
1986 }
1987 else if (ret == VIM_NO)
1988 {
1989 unchanged(buf, TRUE);
1990 }
1991 else if (ret == VIM_ALL)
1992 {
1993 /*
1994 * Write all modified files that can be written.
1995 * Skip readonly buffers, these need to be confirmed
1996 * individually.
1997 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001998 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999 {
2000 if (bufIsChanged(buf2)
2001 && (buf2->b_ffname != NULL
2002#ifdef FEAT_BROWSE
2003 || cmdmod.browse
2004#endif
2005 )
2006 && !buf2->b_p_ro)
2007 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002008#ifdef FEAT_AUTOCMD
2009 bufref_T bufref;
2010
2011 set_bufref(&bufref, buf2);
2012#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013#ifdef FEAT_BROWSE
2014 /* May get file name, when there is none */
2015 browse_save_fname(buf2);
2016#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02002017 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
2018 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
2019 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002020 (void)buf_write_all(buf2, FALSE);
2021#ifdef FEAT_AUTOCMD
2022 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002023 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002024 buf2 = firstbuf;
2025#endif
2026 }
2027 }
2028 }
2029 else if (ret == VIM_DISCARDALL)
2030 {
2031 /*
2032 * mark all buffers as unchanged
2033 */
Bram Moolenaar29323592016-07-24 22:04:11 +02002034 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002035 unchanged(buf2, TRUE);
2036 }
2037}
2038#endif
2039
2040/*
2041 * Return TRUE if the buffer "buf" can be abandoned, either by making it
2042 * hidden, autowriting it or unloading it.
2043 */
2044 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002045can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002046{
2047 return ( P_HID(buf)
2048 || !bufIsChanged(buf)
2049 || buf->b_nwindows > 1
2050 || autowrite(buf, forceit) == OK
2051 || forceit);
2052}
2053
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002054static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002055
2056/*
2057 * Add a buffer number to "bufnrs", unless it's already there.
2058 */
2059 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002060add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002061{
2062 int i;
2063
2064 for (i = 0; i < *bufnump; ++i)
2065 if (bufnrs[i] == nr)
2066 return;
2067 bufnrs[*bufnump] = nr;
2068 *bufnump = *bufnump + 1;
2069}
2070
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071/*
2072 * Return TRUE if any buffer was changed and cannot be abandoned.
2073 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01002074 * When "unload" is true the current buffer is unloaded instead of making it
2075 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002076 */
2077 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002078check_changed_any(
2079 int hidden, /* Only check hidden buffers */
2080 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002082 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002083 buf_T *buf;
2084 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002085 int i;
2086 int bufnum = 0;
2087 int bufcount = 0;
2088 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002089#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002090 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 win_T *wp;
2092#endif
2093
Bram Moolenaar29323592016-07-24 22:04:11 +02002094 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002095 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002097 if (bufcount == 0)
2098 return FALSE;
2099
2100 bufnrs = (int *)alloc(sizeof(int) * bufcount);
2101 if (bufnrs == NULL)
2102 return FALSE;
2103
2104 /* curbuf */
2105 bufnrs[bufnum++] = curbuf->b_fnum;
2106#ifdef FEAT_WINDOWS
2107 /* buf in curtab */
2108 FOR_ALL_WINDOWS(wp)
2109 if (wp->w_buffer != curbuf)
2110 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2111
2112 /* buf in other tab */
Bram Moolenaar29323592016-07-24 22:04:11 +02002113 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002114 if (tp != curtab)
2115 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
2116 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2117#endif
2118 /* any other buf */
Bram Moolenaar29323592016-07-24 22:04:11 +02002119 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002120 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
2121
2122 for (i = 0; i < bufnum; ++i)
2123 {
2124 buf = buflist_findnr(bufnrs[i]);
2125 if (buf == NULL)
2126 continue;
2127 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
2128 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002129 bufref_T bufref;
2130
2131 set_bufref(&bufref, buf);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002132 /* Try auto-writing the buffer. If this fails but the buffer no
2133 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002134 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
2135 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002136 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002137 break; /* didn't save - still changes */
2138 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002139 }
2140
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002141 if (i >= bufnum)
2142 goto theend;
2143
2144 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145 exiting = FALSE;
2146#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2147 /*
2148 * When ":confirm" used, don't give an error message.
2149 */
2150 if (!(p_confirm || cmdmod.confirm))
2151#endif
2152 {
2153 /* There must be a wait_return for this message, do_buffer()
2154 * may cause a redraw. But wait_return() is a no-op when vgetc()
2155 * is busy (Quit used from window menu), then make sure we don't
2156 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002157 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002158 {
2159 msg_row = cmdline_row;
2160 msg_col = 0;
2161 msg_didout = FALSE;
2162 }
2163 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002164 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 {
2166 save = no_wait_return;
2167 no_wait_return = FALSE;
2168 wait_return(FALSE);
2169 no_wait_return = save;
2170 }
2171 }
2172
2173#ifdef FEAT_WINDOWS
2174 /* Try to find a window that contains the buffer. */
2175 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002176 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002177 if (wp->w_buffer == buf)
2178 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002179# ifdef FEAT_AUTOCMD
2180 bufref_T bufref;
2181
2182 set_bufref(&bufref, buf);
2183# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002184 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185# ifdef FEAT_AUTOCMD
2186 /* Paranoia: did autocms wipe out the buffer with changes? */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002187 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002188 {
2189 goto theend;
2190 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002191# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002192 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002193 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002194buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195#endif
2196
2197 /* Open the changed buffer in the current window. */
2198 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002199 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002201theend:
2202 vim_free(bufnrs);
2203 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002204}
2205
2206/*
2207 * return FAIL if there is no file name, OK if there is one
2208 * give error message for FAIL
2209 */
2210 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002211check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002212{
2213 if (curbuf->b_ffname == NULL)
2214 {
2215 EMSG(_(e_noname));
2216 return FAIL;
2217 }
2218 return OK;
2219}
2220
2221/*
2222 * flush the contents of a buffer, unless it has no file name
2223 *
2224 * return FAIL for failure, OK otherwise
2225 */
2226 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002227buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228{
2229 int retval;
2230#ifdef FEAT_AUTOCMD
2231 buf_T *old_curbuf = curbuf;
2232#endif
2233
2234 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2235 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2236 FALSE, forceit, TRUE, FALSE));
2237#ifdef FEAT_AUTOCMD
2238 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002239 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01002240 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002241 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002242 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002243#endif
2244 return retval;
2245}
2246
2247/*
2248 * Code to handle the argument list.
2249 */
2250
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002251static char_u *do_one_arg(char_u *str);
2252static int do_arglist(char_u *str, int what, int after);
2253static void alist_check_arg_idx(void);
2254static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002255#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002256static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002257#endif
2258#define AL_SET 1
2259#define AL_ADD 2
2260#define AL_DEL 3
2261
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002263 * Isolate one argument, taking backticks.
2264 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 * Return a pointer to the start of the next argument.
2266 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002267 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002268do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269{
2270 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 int inbacktick;
2272
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273 inbacktick = FALSE;
2274 for (p = str; *str; ++str)
2275 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002276 /* When the backslash is used for escaping the special meaning of a
2277 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278 if (rem_backslash(str))
2279 {
2280 *p++ = *str++;
2281 *p++ = *str;
2282 }
2283 else
2284 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002285 /* An item ends at a space not in backticks */
2286 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002288 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002290 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002291 }
2292 }
2293 str = skipwhite(str);
2294 *p = NUL;
2295
2296 return str;
2297}
2298
Bram Moolenaar86b68352004-12-27 21:59:20 +00002299/*
2300 * Separate the arguments in "str" and return a list of pointers in the
2301 * growarray "gap".
2302 */
2303 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002304get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002305{
2306 ga_init2(gap, (int)sizeof(char_u *), 20);
2307 while (*str != NUL)
2308 {
2309 if (ga_grow(gap, 1) == FAIL)
2310 {
2311 ga_clear(gap);
2312 return FAIL;
2313 }
2314 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2315
2316 /* Isolate one argument, change it in-place, put a NUL after it. */
2317 str = do_one_arg(str);
2318 }
2319 return OK;
2320}
2321
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002322#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002323/*
2324 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002325 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002326 * Return FAIL or OK.
2327 */
2328 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002329get_arglist_exp(
2330 char_u *str,
2331 int *fcountp,
2332 char_u ***fnamesp,
2333 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002334{
2335 garray_T ga;
2336 int i;
2337
2338 if (get_arglist(&ga, str) == FAIL)
2339 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002340 if (wig == TRUE)
2341 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2342 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2343 else
2344 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2345 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2346
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002347 ga_clear(&ga);
2348 return i;
2349}
2350#endif
2351
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2353/*
2354 * Redefine the argument list.
2355 */
2356 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002357set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358{
2359 do_arglist(str, AL_SET, 0);
2360}
2361#endif
2362
2363/*
2364 * "what" == AL_SET: Redefine the argument list to 'str'.
2365 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2366 * "what" == AL_DEL: remove files in 'str' from the argument list.
2367 *
2368 * Return FAIL for failure, OK otherwise.
2369 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002371do_arglist(
2372 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002373 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002374 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375{
2376 garray_T new_ga;
2377 int exp_count;
2378 char_u **exp_files;
2379 int i;
2380#ifdef FEAT_LISTCMDS
2381 char_u *p;
2382 int match;
2383#endif
2384
2385 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002386 * Set default argument for ":argadd" command.
2387 */
2388 if (what == AL_ADD && *str == NUL)
2389 {
2390 if (curbuf->b_ffname == NULL)
2391 return FAIL;
2392 str = curbuf->b_fname;
2393 }
2394
2395 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002396 * Collect all file name arguments in "new_ga".
2397 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002398 if (get_arglist(&new_ga, str) == FAIL)
2399 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002400
2401#ifdef FEAT_LISTCMDS
2402 if (what == AL_DEL)
2403 {
2404 regmatch_T regmatch;
2405 int didone;
2406
2407 /*
2408 * Delete the items: use each item as a regexp and find a match in the
2409 * argument list.
2410 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002411 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2413 {
2414 p = ((char_u **)new_ga.ga_data)[i];
2415 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2416 if (p == NULL)
2417 break;
2418 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2419 if (regmatch.regprog == NULL)
2420 {
2421 vim_free(p);
2422 break;
2423 }
2424
2425 didone = FALSE;
2426 for (match = 0; match < ARGCOUNT; ++match)
2427 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2428 (colnr_T)0))
2429 {
2430 didone = TRUE;
2431 vim_free(ARGLIST[match].ae_fname);
2432 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2433 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2434 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435 if (curwin->w_arg_idx > match)
2436 --curwin->w_arg_idx;
2437 --match;
2438 }
2439
Bram Moolenaar473de612013-06-08 18:19:48 +02002440 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002441 vim_free(p);
2442 if (!didone)
2443 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2444 }
2445 ga_clear(&new_ga);
2446 }
2447 else
2448#endif
2449 {
2450 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2451 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2452 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002453 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454 {
2455 EMSG(_(e_nomatch));
2456 return FAIL;
2457 }
2458
2459#ifdef FEAT_LISTCMDS
2460 if (what == AL_ADD)
2461 {
2462 (void)alist_add_list(exp_count, exp_files, after);
2463 vim_free(exp_files);
2464 }
2465 else /* what == AL_SET */
2466#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002467 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 }
2469
2470 alist_check_arg_idx();
2471
2472 return OK;
2473}
2474
2475/*
2476 * Check the validity of the arg_idx for each other window.
2477 */
2478 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002479alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480{
2481#ifdef FEAT_WINDOWS
2482 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002483 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484
Bram Moolenaarf740b292006-02-16 22:11:02 +00002485 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002486 if (win->w_alist == curwin->w_alist)
2487 check_arg_idx(win);
2488#else
2489 check_arg_idx(curwin);
2490#endif
2491}
2492
2493/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002494 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002495 * index.
2496 */
2497 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002498editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002499{
2500 return !(win->w_arg_idx >= WARGCOUNT(win)
2501 || (win->w_buffer->b_fnum
2502 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2503 && (win->w_buffer->b_ffname == NULL
2504 || !(fullpathcmp(
2505 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2506 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2507}
2508
2509/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510 * Check if window "win" is editing the w_arg_idx file in its argument list.
2511 */
2512 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002513check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002514{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002515 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516 {
2517 /* We are not editing the current entry in the argument list.
2518 * Set "arg_had_last" if we are editing the last one. */
2519 win->w_arg_idx_invalid = TRUE;
2520 if (win->w_arg_idx != WARGCOUNT(win) - 1
2521 && arg_had_last == FALSE
2522#ifdef FEAT_WINDOWS
2523 && ALIST(win) == &global_alist
2524#endif
2525 && GARGCOUNT > 0
2526 && win->w_arg_idx < GARGCOUNT
2527 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2528 || (win->w_buffer->b_ffname != NULL
2529 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2530 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2531 arg_had_last = TRUE;
2532 }
2533 else
2534 {
2535 /* We are editing the current entry in the argument list.
2536 * Set "arg_had_last" if it's also the last one */
2537 win->w_arg_idx_invalid = FALSE;
2538 if (win->w_arg_idx == WARGCOUNT(win) - 1
2539#ifdef FEAT_WINDOWS
2540 && win->w_alist == &global_alist
2541#endif
2542 )
2543 arg_had_last = TRUE;
2544 }
2545}
2546
2547/*
2548 * ":args", ":argslocal" and ":argsglobal".
2549 */
2550 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002551ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552{
2553 int i;
2554
2555 if (eap->cmdidx != CMD_args)
2556 {
2557#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2558 alist_unlink(ALIST(curwin));
2559 if (eap->cmdidx == CMD_argglobal)
2560 ALIST(curwin) = &global_alist;
2561 else /* eap->cmdidx == CMD_arglocal */
2562 alist_new();
2563#else
2564 ex_ni(eap);
2565 return;
2566#endif
2567 }
2568
2569 if (!ends_excmd(*eap->arg))
2570 {
2571 /*
2572 * ":args file ..": define new argument list, handle like ":next"
2573 * Also for ":argslocal file .." and ":argsglobal file ..".
2574 */
2575 ex_next(eap);
2576 }
2577 else
2578#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2579 if (eap->cmdidx == CMD_args)
2580#endif
2581 {
2582 /*
2583 * ":args": list arguments.
2584 */
2585 if (ARGCOUNT > 0)
2586 {
2587 /* Overwrite the command, for a short list there is no scrolling
2588 * required and no wait_return(). */
2589 gotocmdline(TRUE);
2590 for (i = 0; i < ARGCOUNT; ++i)
2591 {
2592 if (i == curwin->w_arg_idx)
2593 msg_putchar('[');
2594 msg_outtrans(alist_name(&ARGLIST[i]));
2595 if (i == curwin->w_arg_idx)
2596 msg_putchar(']');
2597 msg_putchar(' ');
2598 }
2599 }
2600 }
2601#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2602 else if (eap->cmdidx == CMD_arglocal)
2603 {
2604 garray_T *gap = &curwin->w_alist->al_ga;
2605
2606 /*
2607 * ":argslocal": make a local copy of the global argument list.
2608 */
2609 if (ga_grow(gap, GARGCOUNT) == OK)
2610 for (i = 0; i < GARGCOUNT; ++i)
2611 if (GARGLIST[i].ae_fname != NULL)
2612 {
2613 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2614 vim_strsave(GARGLIST[i].ae_fname);
2615 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2616 GARGLIST[i].ae_fnum;
2617 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618 }
2619 }
2620#endif
2621}
2622
2623/*
2624 * ":previous", ":sprevious", ":Next" and ":sNext".
2625 */
2626 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002627ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628{
2629 /* If past the last one already, go to the last one. */
2630 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2631 do_argfile(eap, ARGCOUNT - 1);
2632 else
2633 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2634}
2635
2636/*
2637 * ":rewind", ":first", ":sfirst" and ":srewind".
2638 */
2639 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002640ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641{
2642 do_argfile(eap, 0);
2643}
2644
2645/*
2646 * ":last" and ":slast".
2647 */
2648 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002649ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650{
2651 do_argfile(eap, ARGCOUNT - 1);
2652}
2653
2654/*
2655 * ":argument" and ":sargument".
2656 */
2657 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002658ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002659{
2660 int i;
2661
2662 if (eap->addr_count > 0)
2663 i = eap->line2 - 1;
2664 else
2665 i = curwin->w_arg_idx;
2666 do_argfile(eap, i);
2667}
2668
2669/*
2670 * Edit file "argn" of the argument lists.
2671 */
2672 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002673do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674{
2675 int other;
2676 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002677 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678
2679 if (argn < 0 || argn >= ARGCOUNT)
2680 {
2681 if (ARGCOUNT <= 1)
2682 EMSG(_("E163: There is only one file to edit"));
2683 else if (argn < 0)
2684 EMSG(_("E164: Cannot go before first file"));
2685 else
2686 EMSG(_("E165: Cannot go beyond last file"));
2687 }
2688 else
2689 {
2690 setpcmark();
2691#ifdef FEAT_GUI
2692 need_mouse_correct = TRUE;
2693#endif
2694
2695#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002696 /* split window or create new tab page first */
2697 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 {
2699 if (win_split(0, 0) == FAIL)
2700 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002701 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702 }
2703 else
2704#endif
2705 {
2706 /*
2707 * if 'hidden' set, only check for changed file when re-editing
2708 * the same buffer
2709 */
2710 other = TRUE;
2711 if (P_HID(curbuf))
2712 {
2713 p = fix_fname(alist_name(&ARGLIST[argn]));
2714 other = otherfile(p);
2715 vim_free(p);
2716 }
2717 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002718 && check_changed(curbuf, CCGD_AW
2719 | (other ? 0 : CCGD_MULTWIN)
2720 | (eap->forceit ? CCGD_FORCEIT : 0)
2721 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 return;
2723 }
2724
2725 curwin->w_arg_idx = argn;
2726 if (argn == ARGCOUNT - 1
2727#ifdef FEAT_WINDOWS
2728 && curwin->w_alist == &global_alist
2729#endif
2730 )
2731 arg_had_last = TRUE;
2732
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002733 /* Edit the file; always use the last known line number.
2734 * When it fails (e.g. Abort for already edited file) restore the
2735 * argument index. */
2736 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002738 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2739 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002740 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002741 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002742 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743 setmark('\'');
2744 }
2745}
2746
2747/*
2748 * ":next", and commands that behave like it.
2749 */
2750 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002751ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002752{
2753 int i;
2754
2755 /*
2756 * check for changed buffer now, if this fails the argument list is not
2757 * redefined.
2758 */
2759 if ( P_HID(curbuf)
2760 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002761 || !check_changed(curbuf, CCGD_AW
2762 | (eap->forceit ? CCGD_FORCEIT : 0)
2763 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 {
2765 if (*eap->arg != NUL) /* redefine file list */
2766 {
2767 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2768 return;
2769 i = 0;
2770 }
2771 else
2772 i = curwin->w_arg_idx + (int)eap->line2;
2773 do_argfile(eap, i);
2774 }
2775}
2776
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002777#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002778/*
2779 * ":argedit"
2780 */
2781 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002782ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783{
2784 int fnum;
2785 int i;
2786 char_u *s;
2787
2788 /* Add the argument to the buffer list and get the buffer number. */
2789 fnum = buflist_add(eap->arg, BLN_LISTED);
2790
2791 /* Check if this argument is already in the argument list. */
2792 for (i = 0; i < ARGCOUNT; ++i)
2793 if (ARGLIST[i].ae_fnum == fnum)
2794 break;
2795 if (i == ARGCOUNT)
2796 {
2797 /* Can't find it, add it to the argument list. */
2798 s = vim_strsave(eap->arg);
2799 if (s == NULL)
2800 return;
2801 i = alist_add_list(1, &s,
2802 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2803 if (i < 0)
2804 return;
2805 curwin->w_arg_idx = i;
2806 }
2807
2808 alist_check_arg_idx();
2809
2810 /* Edit the argument. */
2811 do_argfile(eap, i);
2812}
2813
2814/*
2815 * ":argadd"
2816 */
2817 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002818ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819{
2820 do_arglist(eap->arg, AL_ADD,
2821 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2822#ifdef FEAT_TITLE
2823 maketitle();
2824#endif
2825}
2826
2827/*
2828 * ":argdelete"
2829 */
2830 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002831ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832{
2833 int i;
2834 int n;
2835
2836 if (eap->addr_count > 0)
2837 {
2838 /* ":1,4argdel": Delete all arguments in the range. */
2839 if (eap->line2 > ARGCOUNT)
2840 eap->line2 = ARGCOUNT;
2841 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002842 if (*eap->arg != NUL)
2843 /* Can't have both a range and an argument. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844 EMSG(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002845 else if (n <= 0)
2846 {
2847 /* Don't give an error for ":%argdel" if the list is empty. */
2848 if (eap->line1 != 1 || eap->line2 != 0)
2849 EMSG(_(e_invrange));
2850 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851 else
2852 {
2853 for (i = eap->line1; i <= eap->line2; ++i)
2854 vim_free(ARGLIST[i - 1].ae_fname);
2855 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2856 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2857 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002858 if (curwin->w_arg_idx >= eap->line2)
2859 curwin->w_arg_idx -= n;
2860 else if (curwin->w_arg_idx > eap->line1)
2861 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002862 if (ARGCOUNT == 0)
2863 curwin->w_arg_idx = 0;
2864 else if (curwin->w_arg_idx >= ARGCOUNT)
2865 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002866 }
2867 }
2868 else if (*eap->arg == NUL)
2869 EMSG(_(e_argreq));
2870 else
2871 do_arglist(eap->arg, AL_DEL, 0);
2872#ifdef FEAT_TITLE
2873 maketitle();
2874#endif
2875}
2876
2877/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002878 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879 */
2880 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002881ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002882{
2883 int i;
2884#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002885 win_T *wp;
2886 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002888 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002889 int next_fnum = 0;
2890#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2891 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002893 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002894#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002895 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002896 int qf_idx;
2897#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898
2899#ifndef FEAT_WINDOWS
2900 if (eap->cmdidx == CMD_windo)
2901 {
2902 ex_ni(eap);
2903 return;
2904 }
2905#endif
2906
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002907#ifndef FEAT_QUICKFIX
2908 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2909 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2910 {
2911 ex_ni(eap);
2912 return;
2913 }
2914#endif
2915
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002917 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002918 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2919 * great speed improvement. */
2920 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002921#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002922#ifdef FEAT_CLIPBOARD
2923 start_global_changes();
2924#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925
2926 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002927 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002929 || !check_changed(curbuf, CCGD_AW
2930 | (eap->forceit ? CCGD_FORCEIT : 0)
2931 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002934 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002936 wp = firstwin;
2937 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002939 switch (eap->cmdidx)
2940 {
2941#ifdef FEAT_WINDOWS
2942 case CMD_windo:
2943 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2944 i++;
2945 break;
2946 case CMD_tabdo:
2947 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2948 i++;
2949 break;
2950#endif
2951 case CMD_argdo:
2952 i = eap->line1 - 1;
2953 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002954 default:
2955 break;
2956 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002957 /* set pcmark now */
2958 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002959 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002960 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002961 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002962 || !buf->b_p_bl); buf = buf->b_next)
2963 if (buf->b_fnum > eap->line2)
2964 {
2965 buf = NULL;
2966 break;
2967 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002968 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002969 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002970 }
2971#ifdef FEAT_QUICKFIX
2972 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2973 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2974 {
2975 qf_size = qf_get_size(eap);
2976 if (qf_size <= 0 || eap->line1 > qf_size)
2977 buf = NULL;
2978 else
2979 {
2980 ex_cc(eap);
2981
2982 buf = curbuf;
2983 i = eap->line1 - 1;
2984 if (eap->addr_count <= 0)
2985 /* default is all the quickfix/location list entries */
2986 eap->line2 = qf_size;
2987 }
2988 }
2989#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990 else
2991 setpcmark();
2992 listcmd_busy = TRUE; /* avoids setting pcmark below */
2993
Bram Moolenaare25bb902015-02-27 20:33:37 +01002994 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002995 {
2996 if (eap->cmdidx == CMD_argdo)
2997 {
2998 /* go to argument "i" */
2999 if (i == ARGCOUNT)
3000 break;
3001 /* Don't call do_argfile() when already there, it will try
3002 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00003003 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003004 {
3005 /* Clear 'shm' to avoid that the file message overwrites
3006 * any output from the command. */
3007 p_shm_save = vim_strsave(p_shm);
3008 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003009 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003010 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3011 vim_free(p_shm_save);
3012 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003013 if (curwin->w_arg_idx != i)
3014 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015 }
3016#ifdef FEAT_WINDOWS
3017 else if (eap->cmdidx == CMD_windo)
3018 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003019 /* go to window "wp" */
3020 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003022 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00003023 if (curwin != wp)
3024 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003025 wp = curwin->w_next;
3026 }
3027 else if (eap->cmdidx == CMD_tabdo)
3028 {
3029 /* go to window "tp" */
3030 if (!valid_tabpage(tp))
3031 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003032 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003033 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034 }
3035#endif
3036 else if (eap->cmdidx == CMD_bufdo)
3037 {
3038 /* Remember the number of the next listed buffer, in case
3039 * ":bwipe" is used or autocommands do something strange. */
3040 next_fnum = -1;
3041 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
3042 if (buf->b_p_bl)
3043 {
3044 next_fnum = buf->b_fnum;
3045 break;
3046 }
3047 }
3048
Bram Moolenaara162bc52015-01-07 16:54:21 +01003049 ++i;
3050
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051 /* execute the command */
3052 do_cmdline(eap->arg, eap->getline, eap->cookie,
3053 DOCMD_VERBOSE + DOCMD_NOWAIT);
3054
3055 if (eap->cmdidx == CMD_bufdo)
3056 {
3057 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01003058 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059 break;
3060 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02003061 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062 if (buf->b_fnum == next_fnum)
3063 break;
3064 if (buf == NULL)
3065 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003066
3067 /* Go to the next buffer. Clear 'shm' to avoid that the file
3068 * message overwrites any output from the command. */
3069 p_shm_save = vim_strsave(p_shm);
3070 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003072 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3073 vim_free(p_shm_save);
3074
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003075 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 if (curbuf->b_fnum != next_fnum)
3077 break;
3078 }
3079
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003080#ifdef FEAT_QUICKFIX
3081 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
3082 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3083 {
3084 if (i >= qf_size || i >= eap->line2)
3085 break;
3086
3087 qf_idx = qf_get_cur_idx(eap);
3088
3089 ex_cnext(eap);
3090
3091 /* If jumping to the next quickfix entry fails, quit here */
3092 if (qf_get_cur_idx(eap) == qf_idx)
3093 break;
3094 }
3095#endif
3096
Bram Moolenaar071d4272004-06-13 20:20:40 +00003097 if (eap->cmdidx == CMD_windo)
3098 {
3099 validate_cursor(); /* cursor may have moved */
3100#ifdef FEAT_SCROLLBIND
3101 /* required when 'scrollbind' has been set */
3102 if (curwin->w_p_scb)
3103 do_check_scrollbind(TRUE);
3104#endif
3105 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01003106
3107#ifdef FEAT_WINDOWS
3108 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
3109 if (i+1 > eap->line2)
3110 break;
3111#endif
3112 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
3113 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114 }
3115 listcmd_busy = FALSE;
3116 }
3117
3118#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003119 if (save_ei != NULL)
3120 {
3121 au_event_restore(save_ei);
3122 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
3123 curbuf->b_fname, TRUE, curbuf);
3124 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003125#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02003126#ifdef FEAT_CLIPBOARD
3127 end_global_changes();
3128#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129}
3130
3131/*
3132 * Add files[count] to the arglist of the current window after arg "after".
3133 * The file names in files[count] must have been allocated and are taken over.
3134 * Files[] itself is not taken over.
3135 * Returns index of first added argument. Returns -1 when failed (out of mem).
3136 */
3137 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003138alist_add_list(
3139 int count,
3140 char_u **files,
3141 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142{
3143 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003144 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145
3146 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
3147 {
3148 if (after < 0)
3149 after = 0;
3150 if (after > ARGCOUNT)
3151 after = ARGCOUNT;
3152 if (after < ARGCOUNT)
3153 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
3154 (ARGCOUNT - after) * sizeof(aentry_T));
3155 for (i = 0; i < count; ++i)
3156 {
3157 ARGLIST[after + i].ae_fname = files[i];
3158 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
3159 }
3160 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003161 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3162 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163 return after;
3164 }
3165
3166 for (i = 0; i < count; ++i)
3167 vim_free(files[i]);
3168 return -1;
3169}
3170
3171#endif /* FEAT_LISTCMDS */
3172
3173#ifdef FEAT_EVAL
3174/*
3175 * ":compiler[!] {name}"
3176 */
3177 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003178ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179{
3180 char_u *buf;
3181 char_u *old_cur_comp = NULL;
3182 char_u *p;
3183
3184 if (*eap->arg == NUL)
3185 {
3186 /* List all compiler scripts. */
3187 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3188 /* ) keep the indenter happy... */
3189 }
3190 else
3191 {
3192 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3193 if (buf != NULL)
3194 {
3195 if (eap->forceit)
3196 {
3197 /* ":compiler! {name}" sets global options */
3198 do_cmdline_cmd((char_u *)
3199 "command -nargs=* CompilerSet set <args>");
3200 }
3201 else
3202 {
3203 /* ":compiler! {name}" sets local options.
3204 * To remain backwards compatible "current_compiler" is always
3205 * used. A user's compiler plugin may set it, the distributed
3206 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003207 * "b:current_compiler" and restore "current_compiler".
3208 * Explicitly prepend "g:" to make it work in a function. */
3209 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210 if (old_cur_comp != NULL)
3211 old_cur_comp = vim_strsave(old_cur_comp);
3212 do_cmdline_cmd((char_u *)
3213 "command -nargs=* CompilerSet setlocal <args>");
3214 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003215 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003216 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003217
3218 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003219 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3221 vim_free(buf);
3222
3223 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3224
3225 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003226 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 if (p != NULL)
3228 set_internal_string_var((char_u *)"b:current_compiler", p);
3229
3230 /* Restore "current_compiler" for ":compiler {name}". */
3231 if (!eap->forceit)
3232 {
3233 if (old_cur_comp != NULL)
3234 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003235 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236 old_cur_comp);
3237 vim_free(old_cur_comp);
3238 }
3239 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003240 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241 }
3242 }
3243 }
3244}
3245#endif
3246
3247/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003248 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249 */
3250 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003251ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003252{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003253 char_u *arg = eap->arg;
3254 char_u *p = skiptowhite(arg);
3255 int len = (int)(p - arg);
3256 int flags = eap->forceit ? DIP_ALL : 0;
3257
3258 if (STRNCMP(arg, "START", len) == 0)
3259 {
3260 flags += DIP_START + DIP_NORTP;
3261 arg = skipwhite(arg + len);
3262 }
3263 else if (STRNCMP(arg, "OPT", len) == 0)
3264 {
3265 flags += DIP_OPT + DIP_NORTP;
3266 arg = skipwhite(arg + len);
3267 }
3268 else if (STRNCMP(arg, "PACK", len) == 0)
3269 {
3270 flags += DIP_START + DIP_OPT + DIP_NORTP;
3271 arg = skipwhite(arg + len);
3272 }
3273 else if (STRNCMP(arg, "ALL", len) == 0)
3274 {
3275 flags += DIP_START + DIP_OPT;
3276 arg = skipwhite(arg + len);
3277 }
3278
3279 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280}
3281
Bram Moolenaar071d4272004-06-13 20:20:40 +00003282 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003283source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003285 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003286}
3287
3288/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003289 * Find the file "name" in all directories in "path" and invoke
3290 * "callback(fname, cookie)".
3291 * "name" can contain wildcards.
3292 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3293 * When "flags" has DIP_DIR: find directories instead of files.
3294 * When "flags" has DIP_ERR: give an error message if there is no match.
3295 *
3296 * return FAIL when no file could be sourced, OK otherwise.
3297 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003298 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003299do_in_path(
3300 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003301 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003302 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003303 void (*callback)(char_u *fname, void *ck),
3304 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003305{
3306 char_u *rtp;
3307 char_u *np;
3308 char_u *buf;
3309 char_u *rtp_copy;
3310 char_u *tail;
3311 int num_files;
3312 char_u **files;
3313 int i;
3314 int did_one = FALSE;
3315#ifdef AMIGA
3316 struct Process *proc = (struct Process *)FindTask(0L);
3317 APTR save_winptr = proc->pr_WindowPtr;
3318
3319 /* Avoid a requester here for a volume that doesn't exist. */
3320 proc->pr_WindowPtr = (APTR)-1L;
3321#endif
3322
3323 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3324 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003325 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 buf = alloc(MAXPATHL);
3327 if (buf != NULL && rtp_copy != NULL)
3328 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003329 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003330 {
3331 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003332 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003333 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003334 verbose_leave();
3335 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003336
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 /* Loop over all entries in 'runtimepath'. */
3338 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003339 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02003341 size_t buflen;
3342
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343 /* Copy the path from 'runtimepath' to buf[]. */
3344 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02003345 buflen = STRLEN(buf);
3346
3347 /* Skip after or non-after directories. */
3348 if (flags & (DIP_NOAFTER | DIP_AFTER))
3349 {
3350 int is_after = buflen >= 5
3351 && STRCMP(buf + buflen - 5, "after") == 0;
3352
3353 if ((is_after && (flags & DIP_NOAFTER))
3354 || (!is_after && (flags & DIP_AFTER)))
3355 continue;
3356 }
3357
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003358 if (name == NULL)
3359 {
3360 (*callback)(buf, (void *) &cookie);
3361 if (!did_one)
3362 did_one = (cookie == NULL);
3363 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02003364 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003365 {
3366 add_pathsep(buf);
3367 tail = buf + STRLEN(buf);
3368
3369 /* Loop over all patterns in "name" */
3370 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003371 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372 {
3373 /* Append the pattern from "name" to buf[]. */
3374 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3375 "\t ");
3376
3377 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003378 {
3379 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003380 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003381 verbose_leave();
3382 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383
3384 /* Expand wildcards, invoke the callback for each match. */
3385 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003386 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387 {
3388 for (i = 0; i < num_files; ++i)
3389 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003390 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003391 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003392 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003393 break;
3394 }
3395 FreeWild(num_files, files);
3396 }
3397 }
3398 }
3399 }
3400 }
3401 vim_free(buf);
3402 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003403 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003404 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003405 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3406
3407 if (flags & DIP_ERR)
3408 EMSG3(_(e_dirnotf), basepath, name);
3409 else if (p_verbose > 0)
3410 {
3411 verbose_enter();
3412 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3413 verbose_leave();
3414 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003415 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003416
3417#ifdef AMIGA
3418 proc->pr_WindowPtr = save_winptr;
3419#endif
3420
3421 return did_one ? OK : FAIL;
3422}
3423
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003424/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003425 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003426 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003427 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3428 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003429 * Returns OK when at least one match found, FAIL otherwise.
3430 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003431 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003432 * passed by reference in this case, setting it to NULL indicates that callback
3433 * has done its job.
3434 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003435 static int
3436do_in_path_and_pp(
3437 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003438 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003439 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003440 void (*callback)(char_u *fname, void *ck),
3441 void *cookie)
3442{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003443 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003444 char_u *s;
3445 int len;
3446 char *start_dir = "pack/*/start/*/%s";
3447 char *opt_dir = "pack/*/opt/*/%s";
3448
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003449 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003450 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003451
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003452 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003453 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003454 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003455 s = alloc(len);
3456 if (s == NULL)
3457 return FAIL;
3458 vim_snprintf((char *)s, len, start_dir, name);
3459 done = do_in_path(p_pp, s, flags, callback, cookie);
3460 vim_free(s);
3461 }
3462
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003463 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003464 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003465 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003466 s = alloc(len);
3467 if (s == NULL)
3468 return FAIL;
3469 vim_snprintf((char *)s, len, opt_dir, name);
3470 done = do_in_path(p_pp, s, flags, callback, cookie);
3471 vim_free(s);
3472 }
3473
3474 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003475}
3476
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003477/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003478 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
3479 */
3480 int
3481do_in_runtimepath(
3482 char_u *name,
3483 int flags,
3484 void (*callback)(char_u *fname, void *ck),
3485 void *cookie)
3486{
3487 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
3488}
3489
3490/*
3491 * Source the file "name" from all directories in 'runtimepath'.
3492 * "name" can contain wildcards.
3493 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3494 *
3495 * return FAIL when no file could be sourced, OK otherwise.
3496 */
3497 int
3498source_runtime(char_u *name, int flags)
3499{
3500 return source_in_path(p_rtp, name, flags);
3501}
3502
3503/*
3504 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
3505 */
3506 int
3507source_in_path(char_u *path, char_u *name, int flags)
3508{
3509 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
3510}
3511
3512
3513/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003514 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003515 */
3516 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003517source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003518{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003519 int num_files;
3520 char_u **files;
3521 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003522
Bram Moolenaarf3654822016-03-04 22:12:23 +01003523 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003524 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003525 for (i = 0; i < num_files; ++i)
3526 (void)do_source(files[i], FALSE, DOSO_NONE);
3527 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003528 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003529}
3530
Bram Moolenaar49b27322016-04-05 21:13:00 +02003531/* used for "cookie" of add_pack_plugin() */
3532static int APP_ADD_DIR;
3533static int APP_LOAD;
3534static int APP_BOTH;
3535
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003536 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003537add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003538{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003539 char_u *p4, *p3, *p2, *p1, *p;
3540 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003541 int c;
3542 char_u *new_rtp;
3543 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003544 size_t oldlen;
3545 size_t addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003546 char_u *afterdir;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003547 size_t afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003548 char_u *ffname = fix_fname(fname);
Bram Moolenaarfef524b2016-07-02 22:07:22 +02003549 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003550 char_u *buf = NULL;
3551 char_u *rtp_ffname;
3552 int match;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003553
Bram Moolenaar91715872016-03-03 17:13:03 +01003554 if (ffname == NULL)
3555 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003556 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003557 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003558 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003559 p4 = p3 = p2 = p1 = get_past_head(ffname);
Bram Moolenaar91acfff2017-03-12 19:22:36 +01003560 for (p = p1; *p; MB_PTR_ADV(p))
Bram Moolenaarf3654822016-03-04 22:12:23 +01003561 if (vim_ispathsep_nocolon(*p))
3562 {
3563 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3564 }
3565
3566 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003567 * rtp/pack/name/start/name
3568 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003569 *
3570 * find the part up to "pack" in 'runtimepath' */
3571 c = *p4;
3572 *p4 = NUL;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003573
3574 /* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3575 fname_len = STRLEN(ffname);
3576 insp = p_rtp;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003577 buf = alloc(MAXPATHL);
3578 if (buf == NULL)
3579 goto theend;
3580 while (*insp != NUL)
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003581 {
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003582 copy_option_part(&insp, buf, MAXPATHL, ",");
3583 add_pathsep(buf);
3584 rtp_ffname = fix_fname(buf);
3585 if (rtp_ffname == NULL)
3586 goto theend;
3587 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
3588 vim_free(rtp_ffname);
3589 if (match)
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003590 break;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003591 }
3592
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003593 if (*insp == NUL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003594 /* not found, append at the end */
3595 insp = p_rtp + STRLEN(p_rtp);
3596 else
Bram Moolenaarf3654822016-03-04 22:12:23 +01003597 /* append after the matching directory. */
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003598 --insp;
Bram Moolenaarf3654822016-03-04 22:12:23 +01003599 *p4 = c;
3600
Bram Moolenaara5702442016-05-24 19:37:29 +02003601 /* check if rtp/pack/name/start/name/after exists */
3602 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3603 if (afterdir != NULL && mch_isdir(afterdir))
3604 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3605
Bram Moolenaarb0550662016-05-31 21:37:36 +02003606 oldlen = STRLEN(p_rtp);
3607 addlen = STRLEN(ffname) + 1; /* add one for comma */
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003608 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1));
3609 /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003610 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003611 goto theend;
3612 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003613 mch_memmove(new_rtp, p_rtp, keep);
3614 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003615 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003616 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003617 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003618 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003619 if (afterlen > 0)
3620 {
3621 STRCAT(new_rtp, ",");
3622 STRCAT(new_rtp, afterdir);
3623 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003624 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3625 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003626 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003627 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003628
Bram Moolenaar49b27322016-04-05 21:13:00 +02003629 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003630 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003631 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003632 static char *ftpat = "%s/ftdetect/*.vim";
3633 int len;
3634 char_u *pat;
3635
3636 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3637 pat = alloc(len);
3638 if (pat == NULL)
3639 goto theend;
3640 vim_snprintf((char *)pat, len, plugpat, ffname);
3641 source_all_matches(pat);
3642
3643#ifdef FEAT_AUTOCMD
3644 {
3645 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3646
3647 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3648 * found when it loads. */
3649 if (cmd != NULL && eval_to_number(cmd) > 0)
3650 {
3651 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3652 vim_snprintf((char *)pat, len, ftpat, ffname);
3653 source_all_matches(pat);
3654 do_cmdline_cmd((char_u *)"augroup END");
3655 }
3656 vim_free(cmd);
3657 }
3658#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003659 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003660 }
3661
3662theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003663 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003664 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003665}
3666
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003667/*
3668 * Add all packages in the "start" directory to 'runtimepath'.
3669 */
3670 void
3671add_pack_start_dirs(void)
3672{
3673 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3674 add_pack_plugin, &APP_ADD_DIR);
3675}
3676
3677/*
3678 * Load plugins from all packages in the "start" directory.
3679 */
3680 void
3681load_start_packages(void)
3682{
3683 did_source_packages = TRUE;
3684 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3685 add_pack_plugin, &APP_LOAD);
3686}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003687
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003688/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003689 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003690 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003691 */
3692 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003693ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003694{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003695 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003696 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02003697 /* First do a round to add all directories to 'runtimepath', then load
3698 * the plugins. This allows for plugins to use an autoload directory
3699 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003700 add_pack_start_dirs();
3701 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003702 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003703}
3704
3705/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003706 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003707 */
3708 void
3709ex_packadd(exarg_T *eap)
3710{
3711 static char *plugpat = "pack/*/opt/%s";
3712 int len;
3713 char *pat;
3714
3715 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3716 pat = (char *)alloc(len);
3717 if (pat == NULL)
3718 return;
3719 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003720 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003721 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003722 vim_free(pat);
3723}
3724
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3726/*
3727 * ":options"
3728 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003730ex_options(
3731 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732{
3733 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3734}
3735#endif
3736
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003737#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
3738
3739# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
3740/*
3741 * Detect Python 3 or 2, and initialize 'pyxversion'.
3742 */
3743 void
3744init_pyxversion(void)
3745{
3746 if (p_pyx == 0)
3747 {
3748 if (python3_enabled(FALSE))
3749 p_pyx = 3;
3750 else if (python_enabled(FALSE))
3751 p_pyx = 2;
3752 }
3753}
3754# endif
3755
3756/*
3757 * Does a file contain one of the following strings at the beginning of any
3758 * line?
3759 * "#!(any string)python2" => returns 2
3760 * "#!(any string)python3" => returns 3
3761 * "# requires python 2.x" => returns 2
3762 * "# requires python 3.x" => returns 3
3763 * otherwise return 0.
3764 */
3765 static int
3766requires_py_version(char_u *filename)
3767{
3768 FILE *file;
3769 int requires_py_version = 0;
3770 int i, lines;
3771
3772 lines = (int)p_mls;
3773 if (lines < 0)
3774 lines = 5;
3775
3776 file = mch_fopen((char *)filename, "r");
3777 if (file != NULL)
3778 {
3779 for (i = 0; i < lines; i++)
3780 {
3781 if (vim_fgets(IObuff, IOSIZE, file))
3782 break;
3783 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
3784 {
3785 /* Check shebang. */
3786 if (strstr((char *)IObuff + 2, "python2") != NULL)
3787 {
3788 requires_py_version = 2;
3789 break;
3790 }
3791 if (strstr((char *)IObuff + 2, "python3") != NULL)
3792 {
3793 requires_py_version = 3;
3794 break;
3795 }
3796 }
3797 IObuff[21] = '\0';
3798 if (STRCMP("# requires python 2.x", IObuff) == 0)
3799 {
3800 requires_py_version = 2;
3801 break;
3802 }
3803 if (STRCMP("# requires python 3.x", IObuff) == 0)
3804 {
3805 requires_py_version = 3;
3806 break;
3807 }
3808 }
3809 fclose(file);
3810 }
3811 return requires_py_version;
3812}
3813
3814
3815/*
3816 * Source a python file using the requested python version.
3817 */
3818 static void
3819source_pyx_file(exarg_T *eap, char_u *fname)
3820{
3821 exarg_T ex;
3822 int v = requires_py_version(fname);
3823
3824# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3825 init_pyxversion();
3826# endif
3827 if (v == 0)
3828 {
3829# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3830 /* user didn't choose a preference, 'pyx' is used */
3831 v = p_pyx;
3832# elif defined(FEAT_PYTHON)
3833 v = 2;
3834# elif defined(FEAT_PYTHON3)
3835 v = 3;
3836# endif
3837 }
3838
3839 /*
3840 * now source, if required python version is not supported show
3841 * unobtrusive message.
3842 */
3843 if (eap == NULL)
3844 vim_memset(&ex, 0, sizeof(ex));
3845 else
3846 ex = *eap;
3847 ex.arg = fname;
3848 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
3849
3850 if (v == 2)
3851 {
3852# ifdef FEAT_PYTHON
3853 ex_pyfile(&ex);
3854# else
3855 vim_snprintf((char *)IObuff, IOSIZE,
3856 _("W20: Required python version 2.x not supported, ignoring file: %s"),
3857 fname);
3858 MSG(IObuff);
3859# endif
3860 return;
3861 }
3862 else
3863 {
3864# ifdef FEAT_PYTHON3
3865 ex_py3file(&ex);
3866# else
3867 vim_snprintf((char *)IObuff, IOSIZE,
3868 _("W21: Required python version 3.x not supported, ignoring file: %s"),
3869 fname);
3870 MSG(IObuff);
3871# endif
3872 return;
3873 }
3874}
3875
3876/*
3877 * ":pyxfile {fname}"
3878 */
3879 void
3880ex_pyxfile(exarg_T *eap)
3881{
3882 source_pyx_file(eap, eap->arg);
3883}
3884
3885/*
3886 * ":pyx"
3887 */
3888 void
3889ex_pyx(exarg_T *eap)
3890{
3891# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3892 init_pyxversion();
3893 if (p_pyx == 2)
3894 ex_python(eap);
3895 else
3896 ex_py3(eap);
3897# elif defined(FEAT_PYTHON)
3898 ex_python(eap);
3899# elif defined(FEAT_PYTHON3)
3900 ex_py3(eap);
3901# endif
3902}
3903
3904/*
3905 * ":pyxdo"
3906 */
3907 void
3908ex_pyxdo(exarg_T *eap)
3909{
3910# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3911 init_pyxversion();
3912 if (p_pyx == 2)
3913 ex_pydo(eap);
3914 else
3915 ex_py3do(eap);
3916# elif defined(FEAT_PYTHON)
3917 ex_pydo(eap);
3918# elif defined(FEAT_PYTHON3)
3919 ex_py3do(eap);
3920# endif
3921}
3922
3923#endif
3924
Bram Moolenaar071d4272004-06-13 20:20:40 +00003925/*
3926 * ":source {fname}"
3927 */
3928 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003929ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003930{
3931#ifdef FEAT_BROWSE
3932 if (cmdmod.browse)
3933 {
3934 char_u *fname = NULL;
3935
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003936 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003937 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3938 if (fname != NULL)
3939 {
3940 cmd_source(fname, eap);
3941 vim_free(fname);
3942 }
3943 }
3944 else
3945#endif
3946 cmd_source(eap->arg, eap);
3947}
3948
3949 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003950cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003951{
3952 if (*fname == NUL)
3953 EMSG(_(e_argreq));
3954
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003956 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003957 * Need to execute the commands directly. This is required at least
3958 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003959 * - ":g" command busy
3960 * - after ":argdo", ":windo" or ":bufdo"
3961 * - another command follows
3962 * - inside a loop
3963 */
3964 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3965#ifdef FEAT_EVAL
3966 || eap->cstack->cs_idx >= 0
3967#endif
3968 );
3969
3970 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003971 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003972 EMSG2(_(e_notopen), fname);
3973}
3974
3975/*
3976 * ":source" and associated commands.
3977 */
3978/*
3979 * Structure used to store info for each sourced file.
3980 * It is shared between do_source() and getsourceline().
3981 * This is required, because it needs to be handed to do_cmdline() and
3982 * sourcing can be done recursively.
3983 */
3984struct source_cookie
3985{
3986 FILE *fp; /* opened file for sourcing */
3987 char_u *nextline; /* if not NULL: line that was read ahead */
3988 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003989#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003990 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3991 int error; /* TRUE if LF found after CR-LF */
3992#endif
3993#ifdef FEAT_EVAL
3994 linenr_T breakpoint; /* next line with breakpoint or zero */
3995 char_u *fname; /* name of sourced file */
3996 int dbg_tick; /* debug_tick when breakpoint was set */
3997 int level; /* top nesting level of sourced file */
3998#endif
3999#ifdef FEAT_MBYTE
4000 vimconv_T conv; /* type of conversion */
4001#endif
4002};
4003
4004#ifdef FEAT_EVAL
4005/*
4006 * Return the address holding the next breakpoint line for a source cookie.
4007 */
4008 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004009source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004010{
4011 return &((struct source_cookie *)cookie)->breakpoint;
4012}
4013
4014/*
4015 * Return the address holding the debug tick for a source cookie.
4016 */
4017 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004018source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004019{
4020 return &((struct source_cookie *)cookie)->dbg_tick;
4021}
4022
4023/*
4024 * Return the nesting level for a source cookie.
4025 */
4026 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004027source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028{
4029 return ((struct source_cookie *)cookie)->level;
4030}
4031#endif
4032
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004033static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004034
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004035#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
4036# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004037static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004038
4039/*
4040 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004041 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042 */
4043 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004044fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004045{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004046# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01004047 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
4048# else
4049 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004050# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004051
4052 if (fd_tmp == -1)
4053 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004054
4055# ifdef HAVE_FD_CLOEXEC
4056 {
4057 int fdflags = fcntl(fd_tmp, F_GETFD);
4058 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02004059 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004060 }
4061# endif
4062
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063 return fdopen(fd_tmp, READBIN);
4064}
4065#endif
4066
4067
4068/*
4069 * do_source: Read the file "fname" and execute its lines as EX commands.
4070 *
4071 * This function may be called recursively!
4072 *
4073 * return FAIL if file could not be opened, OK otherwise
4074 */
4075 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004076do_source(
4077 char_u *fname,
4078 int check_other, /* check for .vimrc and _vimrc */
4079 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004080{
4081 struct source_cookie cookie;
4082 char_u *save_sourcing_name;
4083 linenr_T save_sourcing_lnum;
4084 char_u *p;
4085 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00004086 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004087 int retval = FAIL;
4088#ifdef FEAT_EVAL
4089 scid_T save_current_SID;
4090 static scid_T last_current_SID = 0;
4091 void *save_funccalp;
4092 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004093 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02004095 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096 int stat_ok;
4097# endif
4098#endif
4099#ifdef STARTUPTIME
4100 struct timeval tv_rel;
4101 struct timeval tv_start;
4102#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004103#ifdef FEAT_PROFILE
4104 proftime_T wait_start;
4105#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106
Bram Moolenaar071d4272004-06-13 20:20:40 +00004107 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 if (p == NULL)
4109 return retval;
4110 fname_exp = fix_fname(p);
4111 vim_free(p);
4112 if (fname_exp == NULL)
4113 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 if (mch_isdir(fname_exp))
4115 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00004116 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004117 goto theend;
4118 }
4119
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004120#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004121 /* Apply SourceCmd autocommands, they should get the file and source it. */
4122 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
4123 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
4124 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004125 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004126# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004127 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004128# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004129 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004130# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004131 goto theend;
4132 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004133
4134 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004135 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
4136#endif
4137
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004138#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004139 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
4140#else
4141 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
4142#endif
4143 if (cookie.fp == NULL && check_other)
4144 {
4145 /*
4146 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
4147 * and ".exrc" by "_exrc" or vice versa.
4148 */
4149 p = gettail(fname_exp);
4150 if ((*p == '.' || *p == '_')
4151 && (STRICMP(p + 1, "vimrc") == 0
4152 || STRICMP(p + 1, "gvimrc") == 0
4153 || STRICMP(p + 1, "exrc") == 0))
4154 {
4155 if (*p == '_')
4156 *p = '.';
4157 else
4158 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004159#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004160 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
4161#else
4162 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
4163#endif
4164 }
4165 }
4166
4167 if (cookie.fp == NULL)
4168 {
4169 if (p_verbose > 0)
4170 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004171 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004173 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004174 else
4175 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00004176 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004177 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178 }
4179 goto theend;
4180 }
4181
4182 /*
4183 * The file exists.
4184 * - In verbose mode, give a message.
4185 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
4186 */
4187 if (p_verbose > 1)
4188 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004189 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004190 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004191 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192 else
4193 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00004194 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004195 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004196 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004197 if (is_vimrc == DOSO_VIMRC)
4198 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
4199 else if (is_vimrc == DOSO_GVIMRC)
4200 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201
4202#ifdef USE_CRNL
4203 /* If no automatic file format: Set default to CR-NL. */
4204 if (*p_ffs == NUL)
4205 cookie.fileformat = EOL_DOS;
4206 else
4207 cookie.fileformat = EOL_UNKNOWN;
4208 cookie.error = FALSE;
4209#endif
4210
4211#ifdef USE_CR
4212 /* If no automatic file format: Set default to CR. */
4213 if (*p_ffs == NUL)
4214 cookie.fileformat = EOL_MAC;
4215 else
4216 cookie.fileformat = EOL_UNKNOWN;
4217 cookie.error = FALSE;
4218#endif
4219
4220 cookie.nextline = NULL;
4221 cookie.finished = FALSE;
4222
4223#ifdef FEAT_EVAL
4224 /*
4225 * Check if this script has a breakpoint.
4226 */
4227 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
4228 cookie.fname = fname_exp;
4229 cookie.dbg_tick = debug_tick;
4230
4231 cookie.level = ex_nesting_level;
4232#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233
4234 /*
4235 * Keep the sourcing name/lnum, for recursive calls.
4236 */
4237 save_sourcing_name = sourcing_name;
4238 sourcing_name = fname_exp;
4239 save_sourcing_lnum = sourcing_lnum;
4240 sourcing_lnum = 0;
4241
Bram Moolenaar73881402009-02-04 16:50:47 +00004242#ifdef FEAT_MBYTE
4243 cookie.conv.vc_type = CONV_NONE; /* no conversion */
4244
4245 /* Read the first line so we can check for a UTF-8 BOM. */
4246 firstline = getsourceline(0, (void *)&cookie, 0);
4247 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
4248 && firstline[1] == 0xbb && firstline[2] == 0xbf)
4249 {
4250 /* Found BOM; setup conversion, skip over BOM and recode the line. */
4251 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
4252 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00004253 if (p == NULL)
4254 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00004255 if (p != NULL)
4256 {
4257 vim_free(firstline);
4258 firstline = p;
4259 }
4260 }
4261#endif
4262
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004264 if (time_fd != NULL)
4265 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004266#endif
4267
4268#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00004269# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004270 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004271 prof_child_enter(&wait_start); /* entering a child now */
4272# endif
4273
4274 /* Don't use local function variables, if called from a function.
4275 * Also starts profiling timer for nested script. */
4276 save_funccalp = save_funccal();
4277
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278 /*
4279 * Check if this script was sourced before to finds its SID.
4280 * If it's new, generate a new SID.
4281 */
4282 save_current_SID = current_SID;
4283# ifdef UNIX
4284 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
4285# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004286 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
4287 {
4288 si = &SCRIPT_ITEM(current_SID);
4289 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004290 && (
4291# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00004292 /* Compare dev/ino when possible, it catches symbolic
4293 * links. Also compare file names, the inode may change
4294 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004295 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004296 && (si->sn_dev == st.st_dev
4297 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004299 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004300 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004301 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004302 if (current_SID == 0)
4303 {
4304 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004305 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
4306 == FAIL)
4307 goto almosttheend;
4308 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00004310 ++script_items.ga_len;
4311 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
4312# ifdef FEAT_PROFILE
4313 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004315 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004316 si = &SCRIPT_ITEM(current_SID);
4317 si->sn_name = fname_exp;
4318 fname_exp = NULL;
4319# ifdef UNIX
4320 if (stat_ok)
4321 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004322 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004323 si->sn_dev = st.st_dev;
4324 si->sn_ino = st.st_ino;
4325 }
4326 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004327 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004328# endif
4329
Bram Moolenaar071d4272004-06-13 20:20:40 +00004330 /* Allocate the local script variables to use for this script. */
4331 new_script_vars(current_SID);
4332 }
4333
Bram Moolenaar05159a02005-02-26 23:04:13 +00004334# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004335 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004336 {
4337 int forceit;
4338
4339 /* Check if we do profiling for this script. */
4340 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
4341 {
4342 script_do_profile(si);
4343 si->sn_pr_force = forceit;
4344 }
4345 if (si->sn_prof_on)
4346 {
4347 ++si->sn_pr_count;
4348 profile_start(&si->sn_pr_start);
4349 profile_zero(&si->sn_pr_children);
4350 }
4351 }
4352# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004353#endif
4354
4355 /*
4356 * Call do_cmdline, which will call getsourceline() to get the lines.
4357 */
Bram Moolenaar73881402009-02-04 16:50:47 +00004358 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004361
4362#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004363 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004364 {
4365 /* Get "si" again, "script_items" may have been reallocated. */
4366 si = &SCRIPT_ITEM(current_SID);
4367 if (si->sn_prof_on)
4368 {
4369 profile_end(&si->sn_pr_start);
4370 profile_sub_wait(&wait_start, &si->sn_pr_start);
4371 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004372 profile_self(&si->sn_pr_self, &si->sn_pr_start,
4373 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004374 }
4375 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004376#endif
4377
4378 if (got_int)
4379 EMSG(_(e_interr));
4380 sourcing_name = save_sourcing_name;
4381 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382 if (p_verbose > 1)
4383 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004384 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00004385 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004386 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004387 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004388 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004389 }
4390#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004391 if (time_fd != NULL)
4392 {
4393 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
4394 time_msg((char *)IObuff, &tv_start);
4395 time_pop(&tv_rel);
4396 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397#endif
4398
4399#ifdef FEAT_EVAL
4400 /*
4401 * After a "finish" in debug mode, need to break at first command of next
4402 * sourced file.
4403 */
4404 if (save_debug_break_level > ex_nesting_level
4405 && debug_break_level == ex_nesting_level)
4406 ++debug_break_level;
4407#endif
4408
Bram Moolenaar05159a02005-02-26 23:04:13 +00004409#ifdef FEAT_EVAL
4410almosttheend:
4411 current_SID = save_current_SID;
4412 restore_funccal(save_funccalp);
4413# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004414 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004415 prof_child_exit(&wait_start); /* leaving a child now */
4416# endif
4417#endif
4418 fclose(cookie.fp);
4419 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004420 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004421#ifdef FEAT_MBYTE
4422 convert_setup(&cookie.conv, NULL, NULL);
4423#endif
4424
Bram Moolenaar071d4272004-06-13 20:20:40 +00004425theend:
4426 vim_free(fname_exp);
4427 return retval;
4428}
4429
4430#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004431
Bram Moolenaar071d4272004-06-13 20:20:40 +00004432/*
4433 * ":scriptnames"
4434 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004436ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437{
4438 int i;
4439
Bram Moolenaar05159a02005-02-26 23:04:13 +00004440 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4441 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004442 {
4443 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4444 NameBuff, MAXPATHL, TRUE);
4445 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004446 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447}
4448
4449# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4450/*
4451 * Fix slashes in the list of script names for 'shellslash'.
4452 */
4453 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004454scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455{
4456 int i;
4457
Bram Moolenaar05159a02005-02-26 23:04:13 +00004458 for (i = 1; i <= script_items.ga_len; ++i)
4459 if (SCRIPT_ITEM(i).sn_name != NULL)
4460 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004461}
4462# endif
4463
4464/*
4465 * Get a pointer to a script name. Used for ":verbose set".
4466 */
4467 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004468get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004469{
4470 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004471 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004473 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004474 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004475 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004476 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004477 return (char_u *)_("environment variable");
4478 if (id == SID_ERROR)
4479 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004480 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004481}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004482
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004483# if defined(EXITFREE) || defined(PROTO)
4484 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004485free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004486{
4487 int i;
4488
4489 for (i = script_items.ga_len; i > 0; --i)
4490 vim_free(SCRIPT_ITEM(i).sn_name);
4491 ga_clear(&script_items);
4492}
4493# endif
4494
Bram Moolenaar071d4272004-06-13 20:20:40 +00004495#endif
4496
4497#if defined(USE_CR) || defined(PROTO)
4498
4499# if defined(__MSL__) && (__MSL__ >= 22)
4500/*
4501 * Newer version of the Metrowerks library handle DOS and UNIX files
4502 * without help.
4503 * Test with earlier versions, MSL 2.2 is the library supplied with
4504 * Codewarrior Pro 2.
4505 */
4506 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004507fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508{
4509 return fgets(s, n, stream);
4510}
4511# else
4512/*
4513 * Version of fgets() which also works for lines ending in a <CR> only
4514 * (Macintosh format).
4515 * For older versions of the Metrowerks library.
4516 * At least CodeWarrior 9 needed this code.
4517 */
4518 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004519fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004520{
4521 int c = 0;
4522 int char_read = 0;
4523
4524 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4525 {
4526 c = fgetc(stream);
4527 s[char_read++] = c;
4528 /* If the file is in DOS format, we need to skip a NL after a CR. I
4529 * thought it was the other way around, but this appears to work... */
4530 if (c == '\n')
4531 {
4532 c = fgetc(stream);
4533 if (c != '\r')
4534 ungetc(c, stream);
4535 }
4536 }
4537
4538 s[char_read] = 0;
4539 if (char_read == 0)
4540 return NULL;
4541
4542 if (feof(stream) && char_read == 1)
4543 return NULL;
4544
4545 return s;
4546}
4547# endif
4548#endif
4549
4550/*
4551 * Get one full line from a sourced file.
4552 * Called by do_cmdline() when it's called from do_source().
4553 *
4554 * Return a pointer to the line in allocated memory.
4555 * Return NULL for end-of-file or some error.
4556 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004558getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559{
4560 struct source_cookie *sp = (struct source_cookie *)cookie;
4561 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004562 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563
4564#ifdef FEAT_EVAL
4565 /* If breakpoints have been added/deleted need to check for it. */
4566 if (sp->dbg_tick < debug_tick)
4567 {
4568 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4569 sp->dbg_tick = debug_tick;
4570 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004571# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004572 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004573 script_line_end();
4574# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004575#endif
4576 /*
4577 * Get current line. If there is a read-ahead line, use it, otherwise get
4578 * one now.
4579 */
4580 if (sp->finished)
4581 line = NULL;
4582 else if (sp->nextline == NULL)
4583 line = get_one_sourceline(sp);
4584 else
4585 {
4586 line = sp->nextline;
4587 sp->nextline = NULL;
4588 ++sourcing_lnum;
4589 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004590#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004591 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004592 script_line_start();
4593#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594
4595 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4596 * contain the 'C' flag. */
4597 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4598 {
4599 /* compensate for the one line read-ahead */
4600 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004601
4602 /* Get the next line and concatenate it when it starts with a
4603 * backslash. We always need to read the next line, keep it in
4604 * sp->nextline. */
4605 sp->nextline = get_one_sourceline(sp);
4606 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004608 garray_T ga;
4609
Bram Moolenaarb549a732012-02-22 18:29:33 +01004610 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004611 ga_concat(&ga, line);
4612 ga_concat(&ga, p + 1);
4613 for (;;)
4614 {
4615 vim_free(sp->nextline);
4616 sp->nextline = get_one_sourceline(sp);
4617 if (sp->nextline == NULL)
4618 break;
4619 p = skipwhite(sp->nextline);
4620 if (*p != '\\')
4621 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004622 /* Adjust the growsize to the current length to speed up
4623 * concatenating many lines. */
4624 if (ga.ga_len > 400)
4625 {
4626 if (ga.ga_len > 8000)
4627 ga.ga_growsize = 8000;
4628 else
4629 ga.ga_growsize = ga.ga_len;
4630 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004631 ga_concat(&ga, p + 1);
4632 }
4633 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004634 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004635 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636 }
4637 }
4638
4639#ifdef FEAT_MBYTE
4640 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4641 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004642 char_u *s;
4643
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644 /* Convert the encoding of the script line. */
4645 s = string_convert(&sp->conv, line, NULL);
4646 if (s != NULL)
4647 {
4648 vim_free(line);
4649 line = s;
4650 }
4651 }
4652#endif
4653
4654#ifdef FEAT_EVAL
4655 /* Did we encounter a breakpoint? */
4656 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4657 {
4658 dbg_breakpoint(sp->fname, sourcing_lnum);
4659 /* Find next breakpoint. */
4660 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4661 sp->dbg_tick = debug_tick;
4662 }
4663#endif
4664
4665 return line;
4666}
4667
4668 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004669get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004670{
4671 garray_T ga;
4672 int len;
4673 int c;
4674 char_u *buf;
4675#ifdef USE_CRNL
4676 int has_cr; /* CR-LF found */
4677#endif
4678#ifdef USE_CR
4679 char_u *scan;
4680#endif
4681 int have_read = FALSE;
4682
4683 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004684 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004685
4686 /*
4687 * Loop until there is a finished line (or end-of-file).
4688 */
4689 sourcing_lnum++;
4690 for (;;)
4691 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004692 /* make room to read at least 120 (more) characters */
4693 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004694 break;
4695 buf = (char_u *)ga.ga_data;
4696
4697#ifdef USE_CR
4698 if (sp->fileformat == EOL_MAC)
4699 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004700 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4701 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702 break;
4703 }
4704 else
4705#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004706 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4707 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004709 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004710#ifdef USE_CRNL
4711 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4712 * CTRL-Z by its own, or after a NL. */
4713 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4714 && sp->fileformat == EOL_DOS
4715 && buf[len - 1] == Ctrl_Z)
4716 {
4717 buf[len - 1] = NUL;
4718 break;
4719 }
4720#endif
4721
4722#ifdef USE_CR
4723 /* If the read doesn't stop on a new line, and there's
4724 * some CR then we assume a Mac format */
4725 if (sp->fileformat == EOL_UNKNOWN)
4726 {
4727 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4728 sp->fileformat = EOL_MAC;
4729 else
4730 sp->fileformat = EOL_UNIX;
4731 }
4732
4733 if (sp->fileformat == EOL_MAC)
4734 {
4735 scan = vim_strchr(buf, '\r');
4736
4737 if (scan != NULL)
4738 {
4739 *scan = '\n';
4740 if (*(scan + 1) != 0)
4741 {
4742 *(scan + 1) = 0;
4743 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4744 }
4745 }
4746 len = STRLEN(buf);
4747 }
4748#endif
4749
4750 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004751 ga.ga_len = len;
4752
4753 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004754 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004755 continue;
4756
4757 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4758 {
4759#ifdef USE_CRNL
4760 has_cr = (len >= 2 && buf[len - 2] == '\r');
4761 if (sp->fileformat == EOL_UNKNOWN)
4762 {
4763 if (has_cr)
4764 sp->fileformat = EOL_DOS;
4765 else
4766 sp->fileformat = EOL_UNIX;
4767 }
4768
4769 if (sp->fileformat == EOL_DOS)
4770 {
4771 if (has_cr) /* replace trailing CR */
4772 {
4773 buf[len - 2] = '\n';
4774 --len;
4775 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004776 }
4777 else /* lines like ":map xx yy^M" will have failed */
4778 {
4779 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004780 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01004781 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004782 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004783 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004784 sp->error = TRUE;
4785 sp->fileformat = EOL_UNIX;
4786 }
4787 }
4788#endif
4789 /* The '\n' is escaped if there is an odd number of ^V's just
4790 * before it, first set "c" just before the 'V's and then check
4791 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4792 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4793 ;
4794 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4795 {
4796 sourcing_lnum++;
4797 continue;
4798 }
4799
4800 buf[len - 1] = NUL; /* remove the NL */
4801 }
4802
4803 /*
4804 * Check for ^C here now and then, so recursive :so can be broken.
4805 */
4806 line_breakcheck();
4807 break;
4808 }
4809
4810 if (have_read)
4811 return (char_u *)ga.ga_data;
4812
4813 vim_free(ga.ga_data);
4814 return NULL;
4815}
4816
Bram Moolenaar05159a02005-02-26 23:04:13 +00004817#if defined(FEAT_PROFILE) || defined(PROTO)
4818/*
4819 * Called when starting to read a script line.
4820 * "sourcing_lnum" must be correct!
4821 * When skipping lines it may not actually be executed, but we won't find out
4822 * until later and we need to store the time now.
4823 */
4824 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004825script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004826{
4827 scriptitem_T *si;
4828 sn_prl_T *pp;
4829
4830 if (current_SID <= 0 || current_SID > script_items.ga_len)
4831 return;
4832 si = &SCRIPT_ITEM(current_SID);
4833 if (si->sn_prof_on && sourcing_lnum >= 1)
4834 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004835 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004836 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004837 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004838 si->sn_prl_idx = sourcing_lnum - 1;
4839 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4840 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4841 {
4842 /* Zero counters for a line that was not used before. */
4843 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4844 pp->snp_count = 0;
4845 profile_zero(&pp->sn_prl_total);
4846 profile_zero(&pp->sn_prl_self);
4847 ++si->sn_prl_ga.ga_len;
4848 }
4849 si->sn_prl_execed = FALSE;
4850 profile_start(&si->sn_prl_start);
4851 profile_zero(&si->sn_prl_children);
4852 profile_get_wait(&si->sn_prl_wait);
4853 }
4854}
4855
4856/*
4857 * Called when actually executing a function line.
4858 */
4859 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004860script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004861{
4862 scriptitem_T *si;
4863
4864 if (current_SID <= 0 || current_SID > script_items.ga_len)
4865 return;
4866 si = &SCRIPT_ITEM(current_SID);
4867 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4868 si->sn_prl_execed = TRUE;
4869}
4870
4871/*
4872 * Called when done with a function line.
4873 */
4874 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004875script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004876{
4877 scriptitem_T *si;
4878 sn_prl_T *pp;
4879
4880 if (current_SID <= 0 || current_SID > script_items.ga_len)
4881 return;
4882 si = &SCRIPT_ITEM(current_SID);
4883 if (si->sn_prof_on && si->sn_prl_idx >= 0
4884 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4885 {
4886 if (si->sn_prl_execed)
4887 {
4888 pp = &PRL_ITEM(si, si->sn_prl_idx);
4889 ++pp->snp_count;
4890 profile_end(&si->sn_prl_start);
4891 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004892 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004893 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4894 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004895 }
4896 si->sn_prl_idx = -1;
4897 }
4898}
4899#endif
4900
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901/*
4902 * ":scriptencoding": Set encoding conversion for a sourced script.
4903 * Without the multi-byte feature it's simply ignored.
4904 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004906ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907{
4908#ifdef FEAT_MBYTE
4909 struct source_cookie *sp;
4910 char_u *name;
4911
4912 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4913 {
4914 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4915 return;
4916 }
4917
4918 if (*eap->arg != NUL)
4919 {
4920 name = enc_canonize(eap->arg);
4921 if (name == NULL) /* out of memory */
4922 return;
4923 }
4924 else
4925 name = eap->arg;
4926
4927 /* Setup for conversion from the specified encoding to 'encoding'. */
4928 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4929 convert_setup(&sp->conv, name, p_enc);
4930
4931 if (name != eap->arg)
4932 vim_free(name);
4933#endif
4934}
4935
4936#if defined(FEAT_EVAL) || defined(PROTO)
4937/*
4938 * ":finish": Mark a sourced file as finished.
4939 */
4940 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004941ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942{
4943 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4944 do_finish(eap, FALSE);
4945 else
4946 EMSG(_("E168: :finish used outside of a sourced file"));
4947}
4948
4949/*
4950 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4951 * Also called for a pending finish at the ":endtry" or after returning from
4952 * an extra do_cmdline(). "reanimate" is used in the latter case.
4953 */
4954 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004955do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956{
4957 int idx;
4958
4959 if (reanimate)
4960 ((struct source_cookie *)getline_cookie(eap->getline,
4961 eap->cookie))->finished = FALSE;
4962
4963 /*
4964 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4965 * not in its finally clause (which then is to be executed next) is found.
4966 * In this case, make the ":finish" pending for execution at the ":endtry".
4967 * Otherwise, finish normally.
4968 */
4969 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4970 if (idx >= 0)
4971 {
4972 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4973 report_make_pending(CSTP_FINISH, NULL);
4974 }
4975 else
4976 ((struct source_cookie *)getline_cookie(eap->getline,
4977 eap->cookie))->finished = TRUE;
4978}
4979
4980
4981/*
4982 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4983 * message for missing ":endif".
4984 * Return FALSE when not sourcing a file.
4985 */
4986 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004987source_finished(
4988 char_u *(*fgetline)(int, void *, int),
4989 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004990{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004991 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004992 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004993 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004994}
4995#endif
4996
4997#if defined(FEAT_LISTCMDS) || defined(PROTO)
4998/*
4999 * ":checktime [buffer]"
5000 */
5001 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005002ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005003{
5004 buf_T *buf;
5005 int save_no_check_timestamps = no_check_timestamps;
5006
5007 no_check_timestamps = 0;
5008 if (eap->addr_count == 0) /* default is all buffers */
5009 check_timestamps(FALSE);
5010 else
5011 {
5012 buf = buflist_findnr((int)eap->line2);
5013 if (buf != NULL) /* cannot happen? */
5014 (void)buf_check_timestamp(buf, FALSE);
5015 }
5016 no_check_timestamps = save_no_check_timestamps;
5017}
5018#endif
5019
Bram Moolenaar071d4272004-06-13 20:20:40 +00005020#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5021 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005022# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005023static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005024
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005025 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005026get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005027{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005028 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005029
Bram Moolenaar48e330a2016-02-23 14:53:34 +01005030 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005031 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005032
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005033# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00005034 if (loc != NULL)
5035 {
5036 char_u *p;
5037
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005038 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
5039 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005040 p = vim_strchr(loc, '=');
5041 if (p != NULL)
5042 {
5043 loc = ++p;
5044 while (*p != NUL) /* remove trailing newline */
5045 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005046 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00005047 {
5048 *p = NUL;
5049 break;
5050 }
5051 ++p;
5052 }
5053 }
5054 }
5055# endif
5056
5057 return loc;
5058}
5059#endif
5060
5061
5062#ifdef WIN32
5063/*
5064 * On MS-Windows locale names are strings like "German_Germany.1252", but
5065 * gettext expects "de". Try to translate one into another here for a few
5066 * supported languages.
5067 */
5068 static char_u *
5069gettext_lang(char_u *name)
5070{
5071 int i;
5072 static char *(mtable[]) = {
5073 "afrikaans", "af",
5074 "czech", "cs",
5075 "dutch", "nl",
5076 "german", "de",
5077 "english_united kingdom", "en_GB",
5078 "spanish", "es",
5079 "french", "fr",
5080 "italian", "it",
5081 "japanese", "ja",
5082 "korean", "ko",
5083 "norwegian", "no",
5084 "polish", "pl",
5085 "russian", "ru",
5086 "slovak", "sk",
5087 "swedish", "sv",
5088 "ukrainian", "uk",
5089 "chinese_china", "zh_CN",
5090 "chinese_taiwan", "zh_TW",
5091 NULL};
5092
5093 for (i = 0; mtable[i] != NULL; i += 2)
5094 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005095 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005096 return name;
5097}
5098#endif
5099
5100#if defined(FEAT_MULTI_LANG) || defined(PROTO)
5101/*
5102 * Obtain the current messages language. Used to set the default for
5103 * 'helplang'. May return NULL or an empty string.
5104 */
5105 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005106get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005107{
5108 char_u *p;
5109
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005110# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005111# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005112 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005113# else
5114 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005115 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
5116 * and LC_MONETARY may be set differently for a Japanese working in the
5117 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005118 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005119# endif
5120# else
5121 p = mch_getenv((char_u *)"LC_ALL");
5122 if (p == NULL || *p == NUL)
5123 {
5124 p = mch_getenv((char_u *)"LC_MESSAGES");
5125 if (p == NULL || *p == NUL)
5126 p = mch_getenv((char_u *)"LANG");
5127 }
5128# endif
5129# ifdef WIN32
5130 p = gettext_lang(p);
5131# endif
5132 return p;
5133}
5134#endif
5135
Bram Moolenaardef9e822004-12-31 20:58:58 +00005136/* Complicated #if; matches with where get_mess_env() is used below. */
5137#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5138 && defined(LC_MESSAGES))) \
5139 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5140 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
5141 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01005142static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143
5144/*
5145 * Get the language used for messages from the environment.
5146 */
5147 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005148get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005149{
5150 char_u *p;
5151
5152 p = mch_getenv((char_u *)"LC_ALL");
5153 if (p == NULL || *p == NUL)
5154 {
5155 p = mch_getenv((char_u *)"LC_MESSAGES");
5156 if (p == NULL || *p == NUL)
5157 {
5158 p = mch_getenv((char_u *)"LANG");
5159 if (p != NULL && VIM_ISDIGIT(*p))
5160 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005161# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005162 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005163 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005164# endif
5165 }
5166 }
5167 return p;
5168}
5169#endif
5170
5171#if defined(FEAT_EVAL) || defined(PROTO)
5172
5173/*
5174 * Set the "v:lang" variable according to the current locale setting.
5175 * Also do "v:lc_time"and "v:ctype".
5176 */
5177 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005178set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179{
5180 char_u *loc;
5181
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005182# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005183 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005184# else
5185 /* setlocale() not supported: use the default value */
5186 loc = (char_u *)"C";
5187# endif
5188 set_vim_var_string(VV_CTYPE, loc, -1);
5189
5190 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
5191 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005192# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005193 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005194# else
5195 loc = get_mess_env();
5196# endif
5197 set_vim_var_string(VV_LANG, loc, -1);
5198
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005199# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005200 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005201# endif
5202 set_vim_var_string(VV_LC_TIME, loc, -1);
5203}
5204#endif
5205
5206#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5207 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
5208/*
5209 * ":language": Set the language (locale).
5210 */
5211 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005212ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005213{
5214 char *loc;
5215 char_u *p;
5216 char_u *name;
5217 int what = LC_ALL;
5218 char *whatstr = "";
5219#ifdef LC_MESSAGES
5220# define VIM_LC_MESSAGES LC_MESSAGES
5221#else
5222# define VIM_LC_MESSAGES 6789
5223#endif
5224
5225 name = eap->arg;
5226
5227 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
5228 * Allow abbreviation, but require at least 3 characters to avoid
5229 * confusion with a two letter language name "me" or "ct". */
5230 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01005231 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005232 {
5233 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
5234 {
5235 what = VIM_LC_MESSAGES;
5236 name = skipwhite(p);
5237 whatstr = "messages ";
5238 }
5239 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
5240 {
5241 what = LC_CTYPE;
5242 name = skipwhite(p);
5243 whatstr = "ctype ";
5244 }
5245 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
5246 {
5247 what = LC_TIME;
5248 name = skipwhite(p);
5249 whatstr = "time ";
5250 }
5251 }
5252
5253 if (*name == NUL)
5254 {
5255#ifndef LC_MESSAGES
5256 if (what == VIM_LC_MESSAGES)
5257 p = get_mess_env();
5258 else
5259#endif
5260 p = (char_u *)setlocale(what, NULL);
5261 if (p == NULL || *p == NUL)
5262 p = (char_u *)"Unknown";
5263 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
5264 }
5265 else
5266 {
5267#ifndef LC_MESSAGES
5268 if (what == VIM_LC_MESSAGES)
5269 loc = "";
5270 else
5271#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005272 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005273 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005274#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
5275 /* Make sure strtod() uses a decimal point, not a comma. */
5276 setlocale(LC_NUMERIC, "C");
5277#endif
5278 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005279 if (loc == NULL)
5280 EMSG2(_("E197: Cannot set language to \"%s\""), name);
5281 else
5282 {
5283#ifdef HAVE_NL_MSG_CAT_CNTR
5284 /* Need to do this for GNU gettext, otherwise cached translations
5285 * will be used again. */
5286 extern int _nl_msg_cat_cntr;
5287
5288 ++_nl_msg_cat_cntr;
5289#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00005290 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
5292
5293 if (what != LC_TIME)
5294 {
5295 /* Tell gettext() what to translate to. It apparently doesn't
5296 * use the currently effective locale. Also do this when
5297 * FEAT_GETTEXT isn't defined, so that shell commands use this
5298 * value. */
5299 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005300 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005301 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02005302
5303 /* Clear $LANGUAGE because GNU gettext uses it. */
5304 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005305# ifdef WIN32
5306 /* Apparently MS-Windows printf() may cause a crash when
5307 * we give it 8-bit text while it's expecting text in the
5308 * current locale. This call avoids that. */
5309 setlocale(LC_CTYPE, "C");
5310# endif
5311 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005312 if (what != LC_CTYPE)
5313 {
5314 char_u *mname;
5315#ifdef WIN32
5316 mname = gettext_lang(name);
5317#else
5318 mname = name;
5319#endif
5320 vim_setenv((char_u *)"LC_MESSAGES", mname);
5321#ifdef FEAT_MULTI_LANG
5322 set_helplang_default(mname);
5323#endif
5324 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005325 }
5326
5327# ifdef FEAT_EVAL
5328 /* Set v:lang, v:lc_time and v:ctype to the final result. */
5329 set_lang_var();
5330# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02005331# ifdef FEAT_TITLE
5332 maketitle();
5333# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005334 }
5335 }
5336}
5337
5338# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005339
5340static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01005341
5342# ifndef WIN32
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005343static int did_init_locales = FALSE;
5344
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005345/* Return an array of strings for all available locales + NULL for the
5346 * last element. Return NULL in case of error. */
5347 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005348find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005349{
5350 garray_T locales_ga;
5351 char_u *loc;
5352
5353 /* Find all available locales by running command "locale -a". If this
5354 * doesn't work we won't have completion. */
5355 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02005356 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005357 if (locale_a == NULL)
5358 return NULL;
5359 ga_init2(&locales_ga, sizeof(char_u *), 20);
5360
5361 /* Transform locale_a string where each locale is separated by "\n"
5362 * into an array of locale strings. */
5363 loc = (char_u *)strtok((char *)locale_a, "\n");
5364
5365 while (loc != NULL)
5366 {
5367 if (ga_grow(&locales_ga, 1) == FAIL)
5368 break;
5369 loc = vim_strsave(loc);
5370 if (loc == NULL)
5371 break;
5372
5373 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
5374 loc = (char_u *)strtok(NULL, "\n");
5375 }
5376 vim_free(locale_a);
5377 if (ga_grow(&locales_ga, 1) == FAIL)
5378 {
5379 ga_clear(&locales_ga);
5380 return NULL;
5381 }
5382 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
5383 return (char_u **)locales_ga.ga_data;
5384}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01005385# endif
5386
5387/*
5388 * Lazy initialization of all available locales.
5389 */
5390 static void
5391init_locales(void)
5392{
5393# ifndef WIN32
5394 if (!did_init_locales)
5395 {
5396 did_init_locales = TRUE;
5397 locales = find_locales();
5398 }
5399# endif
5400}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005401
5402# if defined(EXITFREE) || defined(PROTO)
5403 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005404free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005405{
5406 int i;
5407 if (locales != NULL)
5408 {
5409 for (i = 0; locales[i] != NULL; i++)
5410 vim_free(locales[i]);
5411 vim_free(locales);
5412 locales = NULL;
5413 }
5414}
5415# endif
5416
Bram Moolenaar071d4272004-06-13 20:20:40 +00005417/*
5418 * Function given to ExpandGeneric() to obtain the possible arguments of the
5419 * ":language" command.
5420 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005421 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005422get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005423{
5424 if (idx == 0)
5425 return (char_u *)"messages";
5426 if (idx == 1)
5427 return (char_u *)"ctype";
5428 if (idx == 2)
5429 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005430
5431 init_locales();
5432 if (locales == NULL)
5433 return NULL;
5434 return locales[idx - 3];
5435}
5436
5437/*
5438 * Function given to ExpandGeneric() to obtain the available locales.
5439 */
5440 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005441get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005442{
5443 init_locales();
5444 if (locales == NULL)
5445 return NULL;
5446 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005447}
5448# endif
5449
5450#endif