blob: 8df67536c55c0b74bd386ef0a3072d1c402a9c50 [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) \
1096 / (double)fr.QuadPart) * 1000);
1097# else
1098# define GET_TIMEDIFF(timer, now) \
1099 (timer->tr_due.tv_sec - now.tv_sec) * 1000 \
1100 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1101# 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));
1146
1147 if (timer == NULL)
1148 return NULL;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001149 if (++last_timer_id < 0)
1150 /* Overflow! Might cause duplicates... */
1151 last_timer_id = 0;
1152 timer->tr_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001153 insert_timer(timer);
1154 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001155 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001156 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001157
1158 profile_setlimit(msec, &timer->tr_due);
1159 return timer;
1160}
1161
1162/*
1163 * Invoke the callback of "timer".
1164 */
1165 static void
1166timer_callback(timer_T *timer)
1167{
1168 typval_T rettv;
1169 int dummy;
1170 typval_T argv[2];
1171
1172 argv[0].v_type = VAR_NUMBER;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001173 argv[0].vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001174 argv[1].v_type = VAR_UNKNOWN;
1175
1176 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
Bram Moolenaardf48fb42016-07-22 21:50:18 +02001177 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar975b5272016-03-15 23:10:59 +01001178 timer->tr_partial, NULL);
1179 clear_tv(&rettv);
1180}
1181
1182/*
1183 * Call timers that are due.
1184 * Return the time in msec until the next timer is due.
1185 */
1186 long
Bram Moolenaarcf089462016-06-12 21:18:43 +02001187check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001188{
1189 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001190 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001191 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001192 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001193 proftime_T now;
1194 int did_one = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001195 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001196# ifdef WIN3264
1197 LARGE_INTEGER fr;
1198
1199 QueryPerformanceFrequency(&fr);
1200# endif
Bram Moolenaar75537a92016-09-05 22:45:28 +02001201 profile_start(&now);
1202 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001203 {
Bram Moolenaar75537a92016-09-05 22:45:28 +02001204 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001205
Bram Moolenaar75537a92016-09-05 22:45:28 +02001206 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
1207 continue;
1208 this_due = GET_TIMEDIFF(timer, now);
1209 if (this_due <= 1)
1210 {
1211 timer->tr_firing = TRUE;
1212 timer_callback(timer);
1213 timer->tr_firing = FALSE;
1214 timer_next = timer->tr_next;
1215 did_one = TRUE;
1216
1217 /* Only fire the timer again if it repeats and stop_timer() wasn't
1218 * called while inside the callback (tr_id == -1). */
1219 if (timer->tr_repeat != 0 && timer->tr_id != -1)
1220 {
1221 profile_setlimit(timer->tr_interval, &timer->tr_due);
1222 this_due = GET_TIMEDIFF(timer, now);
1223 if (this_due < 1)
1224 this_due = 1;
1225 if (timer->tr_repeat > 0)
1226 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001227 }
Bram Moolenaar75537a92016-09-05 22:45:28 +02001228 else
1229 {
1230 this_due = -1;
1231 remove_timer(timer);
1232 free_timer(timer);
1233 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001234 }
Bram Moolenaar75537a92016-09-05 22:45:28 +02001235 if (this_due > 0 && (next_due == -1 || next_due > this_due))
1236 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001237 }
1238
1239 if (did_one)
1240 redraw_after_callback();
1241
Bram Moolenaar75537a92016-09-05 22:45:28 +02001242 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001243}
1244
1245/*
1246 * Find a timer by ID. Returns NULL if not found;
1247 */
1248 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +02001249find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001250{
1251 timer_T *timer;
1252
Bram Moolenaar75537a92016-09-05 22:45:28 +02001253 if (id >= 0)
1254 {
1255 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1256 if (timer->tr_id == id)
1257 return timer;
1258 }
1259 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001260}
1261
1262
1263/*
1264 * Stop a timer and delete it.
1265 */
1266 void
1267stop_timer(timer_T *timer)
1268{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001269 if (timer->tr_firing)
1270 /* Free the timer after the callback returns. */
1271 timer->tr_id = -1;
1272 else
1273 {
1274 remove_timer(timer);
1275 free_timer(timer);
1276 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001277}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001278
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001279 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001280stop_all_timers(void)
1281{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001282 timer_T *timer;
1283 timer_T *timer_next;
1284
1285 for (timer = first_timer; timer != NULL; timer = timer_next)
1286 {
1287 timer_next = timer->tr_next;
1288 stop_timer(timer);
1289 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001290}
1291
1292 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001293add_timer_info(typval_T *rettv, timer_T *timer)
1294{
1295 list_T *list = rettv->vval.v_list;
1296 dict_T *dict = dict_alloc();
1297 dictitem_T *di;
1298 long remaining;
1299 proftime_T now;
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001300# ifdef WIN3264
1301 LARGE_INTEGER fr;
1302#endif
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001303
1304 if (dict == NULL)
1305 return;
1306 list_append_dict(list, dict);
1307
Bram Moolenaar75537a92016-09-05 22:45:28 +02001308 dict_add_nr_str(dict, "id", timer->tr_id, NULL);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001309 dict_add_nr_str(dict, "time", (long)timer->tr_interval, NULL);
1310
1311 profile_start(&now);
1312# ifdef WIN3264
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001313 QueryPerformanceFrequency(&fr);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001314# endif
Bram Moolenaar75537a92016-09-05 22:45:28 +02001315 remaining = GET_TIMEDIFF(timer, now);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001316 dict_add_nr_str(dict, "remaining", (long)remaining, NULL);
1317
1318 dict_add_nr_str(dict, "repeat",
1319 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1), NULL);
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001320 dict_add_nr_str(dict, "paused", (long)(timer->tr_paused), NULL);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001321
1322 di = dictitem_alloc((char_u *)"callback");
1323 if (di != NULL)
1324 {
1325 if (dict_add(dict, di) == FAIL)
1326 vim_free(di);
1327 else if (timer->tr_partial != NULL)
1328 {
1329 di->di_tv.v_type = VAR_PARTIAL;
1330 di->di_tv.vval.v_partial = timer->tr_partial;
1331 ++timer->tr_partial->pt_refcount;
1332 }
1333 else
1334 {
1335 di->di_tv.v_type = VAR_FUNC;
1336 di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
1337 }
1338 di->di_tv.v_lock = 0;
1339 }
1340}
1341
1342 void
1343add_timer_info_all(typval_T *rettv)
1344{
1345 timer_T *timer;
1346
1347 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001348 if (timer->tr_id != -1)
1349 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001350}
1351
Bram Moolenaare3188e22016-05-31 21:13:04 +02001352/*
1353 * Mark references in partials of timers.
1354 */
1355 int
1356set_ref_in_timer(int copyID)
1357{
1358 int abort = FALSE;
1359 timer_T *timer;
1360 typval_T tv;
1361
1362 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1363 {
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +02001364 if (timer->tr_partial != NULL)
1365 {
1366 tv.v_type = VAR_PARTIAL;
1367 tv.vval.v_partial = timer->tr_partial;
1368 }
1369 else
1370 {
1371 tv.v_type = VAR_FUNC;
1372 tv.vval.v_string = timer->tr_callback;
1373 }
Bram Moolenaare3188e22016-05-31 21:13:04 +02001374 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1375 }
1376 return abort;
1377}
Bram Moolenaar623e2632016-07-30 22:47:56 +02001378
1379# if defined(EXITFREE) || defined(PROTO)
1380 void
1381timer_free_all()
1382{
1383 timer_T *timer;
1384
1385 while (first_timer != NULL)
1386 {
1387 timer = first_timer;
1388 remove_timer(timer);
1389 free_timer(timer);
1390 }
1391}
1392# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +01001393# endif
1394
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001395#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1396# if defined(HAVE_MATH_H)
1397# include <math.h>
1398# endif
1399
1400/*
1401 * Divide the time "tm" by "count" and store in "tm2".
1402 */
1403 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001404profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001405{
1406 if (count == 0)
1407 profile_zero(tm2);
1408 else
1409 {
1410# ifdef WIN3264
1411 tm2->QuadPart = tm->QuadPart / count;
1412# else
1413 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1414
1415 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001416 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001417# endif
1418 }
1419}
1420#endif
1421
Bram Moolenaar76929292008-01-06 19:07:36 +00001422# if defined(FEAT_PROFILE) || defined(PROTO)
1423/*
1424 * Functions for profiling.
1425 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001426static void script_do_profile(scriptitem_T *si);
1427static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001428static proftime_T prof_wait_time;
1429
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001430/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001431 * Add the time "tm2" to "tm".
1432 */
1433 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001434profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001435{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001436# ifdef WIN3264
1437 tm->QuadPart += tm2->QuadPart;
1438# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001439 tm->tv_usec += tm2->tv_usec;
1440 tm->tv_sec += tm2->tv_sec;
1441 if (tm->tv_usec >= 1000000)
1442 {
1443 tm->tv_usec -= 1000000;
1444 ++tm->tv_sec;
1445 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001446# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001447}
1448
1449/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001450 * Add the "self" time from the total time and the children's time.
1451 */
1452 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001453profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001454{
1455 /* Check that the result won't be negative. Can happen with recursive
1456 * calls. */
1457#ifdef WIN3264
1458 if (total->QuadPart <= children->QuadPart)
1459 return;
1460#else
1461 if (total->tv_sec < children->tv_sec
1462 || (total->tv_sec == children->tv_sec
1463 && total->tv_usec <= children->tv_usec))
1464 return;
1465#endif
1466 profile_add(self, total);
1467 profile_sub(self, children);
1468}
1469
1470/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001471 * Get the current waittime.
1472 */
1473 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001474profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001475{
1476 *tm = prof_wait_time;
1477}
1478
1479/*
1480 * Subtract the passed waittime since "tm" from "tma".
1481 */
1482 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001483profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001484{
1485 proftime_T tm3 = prof_wait_time;
1486
1487 profile_sub(&tm3, tm);
1488 profile_sub(tma, &tm3);
1489}
1490
1491/*
1492 * Return TRUE if "tm1" and "tm2" are equal.
1493 */
1494 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001495profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001496{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001497# ifdef WIN3264
1498 return (tm1->QuadPart == tm2->QuadPart);
1499# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001500 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001501# endif
1502}
1503
1504/*
1505 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1506 */
1507 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001508profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001509{
1510# ifdef WIN3264
1511 return (int)(tm2->QuadPart - tm1->QuadPart);
1512# else
1513 if (tm1->tv_sec == tm2->tv_sec)
1514 return tm2->tv_usec - tm1->tv_usec;
1515 return tm2->tv_sec - tm1->tv_sec;
1516# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001517}
1518
Bram Moolenaar05159a02005-02-26 23:04:13 +00001519static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001520static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001521
1522/*
1523 * ":profile cmd args"
1524 */
1525 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001526ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001527{
1528 char_u *e;
1529 int len;
1530
1531 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001532 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001533 e = skipwhite(e);
1534
1535 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1536 {
1537 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001538 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001539 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001540 profile_zero(&prof_wait_time);
1541 set_vim_var_nr(VV_PROFILING, 1L);
1542 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001543 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001544 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001545 else if (STRCMP(eap->arg, "pause") == 0)
1546 {
1547 if (do_profiling == PROF_YES)
1548 profile_start(&pause_time);
1549 do_profiling = PROF_PAUSED;
1550 }
1551 else if (STRCMP(eap->arg, "continue") == 0)
1552 {
1553 if (do_profiling == PROF_PAUSED)
1554 {
1555 profile_end(&pause_time);
1556 profile_add(&prof_wait_time, &pause_time);
1557 }
1558 do_profiling = PROF_YES;
1559 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001560 else
1561 {
1562 /* The rest is similar to ":breakadd". */
1563 ex_breakadd(eap);
1564 }
1565}
1566
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001567/* Command line expansion for :profile. */
1568static enum
1569{
1570 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001571 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001572} pexpand_what;
1573
1574static char *pexpand_cmds[] = {
1575 "start",
1576#define PROFCMD_START 0
1577 "pause",
1578#define PROFCMD_PAUSE 1
1579 "continue",
1580#define PROFCMD_CONTINUE 2
1581 "func",
1582#define PROFCMD_FUNC 3
1583 "file",
1584#define PROFCMD_FILE 4
1585 NULL
1586#define PROFCMD_LAST 5
1587};
1588
1589/*
1590 * Function given to ExpandGeneric() to obtain the profile command
1591 * specific expansion.
1592 */
1593 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001594get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001595{
1596 switch (pexpand_what)
1597 {
1598 case PEXP_SUBCMD:
1599 return (char_u *)pexpand_cmds[idx];
1600 /* case PEXP_FUNC: TODO */
1601 default:
1602 return NULL;
1603 }
1604}
1605
1606/*
1607 * Handle command line completion for :profile command.
1608 */
1609 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001610set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001611{
1612 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001613
1614 /* Default: expand subcommands. */
1615 xp->xp_context = EXPAND_PROFILE;
1616 pexpand_what = PEXP_SUBCMD;
1617 xp->xp_pattern = arg;
1618
1619 end_subcmd = skiptowhite(arg);
1620 if (*end_subcmd == NUL)
1621 return;
1622
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001623 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001624 {
1625 xp->xp_context = EXPAND_FILES;
1626 xp->xp_pattern = skipwhite(end_subcmd);
1627 return;
1628 }
1629
1630 /* TODO: expand function names after "func" */
1631 xp->xp_context = EXPAND_NOTHING;
1632}
1633
Bram Moolenaar05159a02005-02-26 23:04:13 +00001634/*
1635 * Dump the profiling info.
1636 */
1637 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001638profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001639{
1640 FILE *fd;
1641
1642 if (profile_fname != NULL)
1643 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001644 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001645 if (fd == NULL)
1646 EMSG2(_(e_notopen), profile_fname);
1647 else
1648 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001649 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001650 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001651 fclose(fd);
1652 }
1653 }
1654}
1655
1656/*
1657 * Start profiling script "fp".
1658 */
1659 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001660script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001661{
1662 si->sn_pr_count = 0;
1663 profile_zero(&si->sn_pr_total);
1664 profile_zero(&si->sn_pr_self);
1665
1666 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1667 si->sn_prl_idx = -1;
1668 si->sn_prof_on = TRUE;
1669 si->sn_pr_nest = 0;
1670}
1671
1672/*
1673 * save time when starting to invoke another script or function.
1674 */
1675 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001676script_prof_save(
1677 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001678{
1679 scriptitem_T *si;
1680
1681 if (current_SID > 0 && current_SID <= script_items.ga_len)
1682 {
1683 si = &SCRIPT_ITEM(current_SID);
1684 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1685 profile_start(&si->sn_pr_child);
1686 }
1687 profile_get_wait(tm);
1688}
1689
1690/*
1691 * Count time spent in children after invoking another script or function.
1692 */
1693 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001694script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001695{
1696 scriptitem_T *si;
1697
1698 if (current_SID > 0 && current_SID <= script_items.ga_len)
1699 {
1700 si = &SCRIPT_ITEM(current_SID);
1701 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1702 {
1703 profile_end(&si->sn_pr_child);
1704 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1705 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1706 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1707 }
1708 }
1709}
1710
1711static proftime_T inchar_time;
1712
1713/*
1714 * Called when starting to wait for the user to type a character.
1715 */
1716 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001717prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001718{
1719 profile_start(&inchar_time);
1720}
1721
1722/*
1723 * Called when finished waiting for the user to type a character.
1724 */
1725 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001726prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001727{
1728 profile_end(&inchar_time);
1729 profile_add(&prof_wait_time, &inchar_time);
1730}
1731
1732/*
1733 * Dump the profiling results for all scripts in file "fd".
1734 */
1735 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001736script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001737{
1738 int id;
1739 scriptitem_T *si;
1740 int i;
1741 FILE *sfd;
1742 sn_prl_T *pp;
1743
1744 for (id = 1; id <= script_items.ga_len; ++id)
1745 {
1746 si = &SCRIPT_ITEM(id);
1747 if (si->sn_prof_on)
1748 {
1749 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1750 if (si->sn_pr_count == 1)
1751 fprintf(fd, "Sourced 1 time\n");
1752 else
1753 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1754 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1755 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1756 fprintf(fd, "\n");
1757 fprintf(fd, "count total (s) self (s)\n");
1758
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001759 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001760 if (sfd == NULL)
1761 fprintf(fd, "Cannot open file!\n");
1762 else
1763 {
1764 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1765 {
1766 if (vim_fgets(IObuff, IOSIZE, sfd))
1767 break;
1768 pp = &PRL_ITEM(si, i);
1769 if (pp->snp_count > 0)
1770 {
1771 fprintf(fd, "%5d ", pp->snp_count);
1772 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1773 fprintf(fd, " ");
1774 else
1775 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1776 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1777 }
1778 else
1779 fprintf(fd, " ");
1780 fprintf(fd, "%s", IObuff);
1781 }
1782 fclose(sfd);
1783 }
1784 fprintf(fd, "\n");
1785 }
1786 }
1787}
1788
1789/*
1790 * Return TRUE when a function defined in the current script should be
1791 * profiled.
1792 */
1793 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001794prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001795{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001796 if (current_SID > 0)
1797 return SCRIPT_ITEM(current_SID).sn_pr_force;
1798 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001799}
1800
1801# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802#endif
1803
1804/*
1805 * If 'autowrite' option set, try to write the file.
1806 * Careful: autocommands may make "buf" invalid!
1807 *
1808 * return FAIL for failure, OK otherwise
1809 */
1810 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001811autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001813 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001814 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001815
Bram Moolenaar071d4272004-06-13 20:20:40 +00001816 if (!(p_aw || p_awa) || !p_write
1817#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001818 /* never autowrite a "nofile" or "nowrite" buffer */
1819 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001821 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001823 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001824 r = buf_write_all(buf, forceit);
1825
1826 /* Writing may succeed but the buffer still changed, e.g., when there is a
1827 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001828 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001829 r = FAIL;
1830 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831}
1832
1833/*
1834 * flush all buffers, except the ones that are readonly
1835 */
1836 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001837autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838{
1839 buf_T *buf;
1840
1841 if (!(p_aw || p_awa) || !p_write)
1842 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001843 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 if (bufIsChanged(buf) && !buf->b_p_ro)
1845 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001846#ifdef FEAT_AUTOCMD
1847 bufref_T bufref;
1848
1849 set_bufref(&bufref, buf);
1850#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851 (void)buf_write_all(buf, FALSE);
1852#ifdef FEAT_AUTOCMD
1853 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001854 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001855 buf = firstbuf;
1856#endif
1857 }
1858}
1859
1860/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001861 * Return TRUE if buffer was changed and cannot be abandoned.
1862 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001863 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001865check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001867 int forceit = (flags & CCGD_FORCEIT);
1868#ifdef FEAT_AUTOCMD
1869 bufref_T bufref;
1870
1871 set_bufref(&bufref, buf);
1872#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001873
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874 if ( !forceit
1875 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001876 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1877 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001878 {
1879#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1880 if ((p_confirm || cmdmod.confirm) && p_write)
1881 {
1882 buf_T *buf2;
1883 int count = 0;
1884
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001885 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001886 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 if (bufIsChanged(buf2)
1888 && (buf2->b_ffname != NULL
1889# ifdef FEAT_BROWSE
1890 || cmdmod.browse
1891# endif
1892 ))
1893 ++count;
1894# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001895 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896 /* Autocommand deleted buffer, oops! It's not changed now. */
1897 return FALSE;
1898# endif
1899 dialog_changed(buf, count > 1);
1900# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001901 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001902 /* Autocommand deleted buffer, oops! It's not changed now. */
1903 return FALSE;
1904# endif
1905 return bufIsChanged(buf);
1906 }
1907#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001908 if (flags & CCGD_EXCMD)
1909 EMSG(_(e_nowrtmsg));
1910 else
1911 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912 return TRUE;
1913 }
1914 return FALSE;
1915}
1916
1917#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1918
1919#if defined(FEAT_BROWSE) || defined(PROTO)
1920/*
1921 * When wanting to write a file without a file name, ask the user for a name.
1922 */
1923 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001924browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925{
1926 if (buf->b_fname == NULL)
1927 {
1928 char_u *fname;
1929
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001930 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1931 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 if (fname != NULL)
1933 {
1934 if (setfname(buf, fname, NULL, TRUE) == OK)
1935 buf->b_flags |= BF_NOTEDITED;
1936 vim_free(fname);
1937 }
1938 }
1939}
1940#endif
1941
1942/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001943 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944 * Must check 'write' option first!
1945 */
1946 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001947dialog_changed(
1948 buf_T *buf,
1949 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001950{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001951 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 int ret;
1953 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001954 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001956 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957 (buf->b_fname != NULL) ?
1958 buf->b_fname : (char_u *)_("Untitled"));
1959 if (checkall)
1960 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1961 else
1962 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1963
Bram Moolenaar8218f602012-04-25 17:32:18 +02001964 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1965 * function. */
1966 ea.append = ea.forceit = FALSE;
1967
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968 if (ret == VIM_YES)
1969 {
1970#ifdef FEAT_BROWSE
1971 /* May get file name, when there is none */
1972 browse_save_fname(buf);
1973#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001974 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1975 buf->b_fname, buf->b_ffname, FALSE) == OK)
1976 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001977 (void)buf_write_all(buf, FALSE);
1978 }
1979 else if (ret == VIM_NO)
1980 {
1981 unchanged(buf, TRUE);
1982 }
1983 else if (ret == VIM_ALL)
1984 {
1985 /*
1986 * Write all modified files that can be written.
1987 * Skip readonly buffers, these need to be confirmed
1988 * individually.
1989 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001990 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001991 {
1992 if (bufIsChanged(buf2)
1993 && (buf2->b_ffname != NULL
1994#ifdef FEAT_BROWSE
1995 || cmdmod.browse
1996#endif
1997 )
1998 && !buf2->b_p_ro)
1999 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002000#ifdef FEAT_AUTOCMD
2001 bufref_T bufref;
2002
2003 set_bufref(&bufref, buf2);
2004#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002005#ifdef FEAT_BROWSE
2006 /* May get file name, when there is none */
2007 browse_save_fname(buf2);
2008#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02002009 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
2010 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
2011 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002012 (void)buf_write_all(buf2, FALSE);
2013#ifdef FEAT_AUTOCMD
2014 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002015 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002016 buf2 = firstbuf;
2017#endif
2018 }
2019 }
2020 }
2021 else if (ret == VIM_DISCARDALL)
2022 {
2023 /*
2024 * mark all buffers as unchanged
2025 */
Bram Moolenaar29323592016-07-24 22:04:11 +02002026 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002027 unchanged(buf2, TRUE);
2028 }
2029}
2030#endif
2031
2032/*
2033 * Return TRUE if the buffer "buf" can be abandoned, either by making it
2034 * hidden, autowriting it or unloading it.
2035 */
2036 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002037can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002038{
2039 return ( P_HID(buf)
2040 || !bufIsChanged(buf)
2041 || buf->b_nwindows > 1
2042 || autowrite(buf, forceit) == OK
2043 || forceit);
2044}
2045
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002046static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002047
2048/*
2049 * Add a buffer number to "bufnrs", unless it's already there.
2050 */
2051 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002052add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002053{
2054 int i;
2055
2056 for (i = 0; i < *bufnump; ++i)
2057 if (bufnrs[i] == nr)
2058 return;
2059 bufnrs[*bufnump] = nr;
2060 *bufnump = *bufnump + 1;
2061}
2062
Bram Moolenaar071d4272004-06-13 20:20:40 +00002063/*
2064 * Return TRUE if any buffer was changed and cannot be abandoned.
2065 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01002066 * When "unload" is true the current buffer is unloaded instead of making it
2067 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068 */
2069 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002070check_changed_any(
2071 int hidden, /* Only check hidden buffers */
2072 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002074 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075 buf_T *buf;
2076 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002077 int i;
2078 int bufnum = 0;
2079 int bufcount = 0;
2080 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002082 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002083 win_T *wp;
2084#endif
2085
Bram Moolenaar29323592016-07-24 22:04:11 +02002086 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002087 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002089 if (bufcount == 0)
2090 return FALSE;
2091
2092 bufnrs = (int *)alloc(sizeof(int) * bufcount);
2093 if (bufnrs == NULL)
2094 return FALSE;
2095
2096 /* curbuf */
2097 bufnrs[bufnum++] = curbuf->b_fnum;
2098#ifdef FEAT_WINDOWS
2099 /* buf in curtab */
2100 FOR_ALL_WINDOWS(wp)
2101 if (wp->w_buffer != curbuf)
2102 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2103
2104 /* buf in other tab */
Bram Moolenaar29323592016-07-24 22:04:11 +02002105 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002106 if (tp != curtab)
2107 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
2108 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2109#endif
2110 /* any other buf */
Bram Moolenaar29323592016-07-24 22:04:11 +02002111 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002112 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
2113
2114 for (i = 0; i < bufnum; ++i)
2115 {
2116 buf = buflist_findnr(bufnrs[i]);
2117 if (buf == NULL)
2118 continue;
2119 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
2120 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002121 bufref_T bufref;
2122
2123 set_bufref(&bufref, buf);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002124 /* Try auto-writing the buffer. If this fails but the buffer no
2125 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002126 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
2127 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002128 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002129 break; /* didn't save - still changes */
2130 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 }
2132
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002133 if (i >= bufnum)
2134 goto theend;
2135
2136 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137 exiting = FALSE;
2138#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2139 /*
2140 * When ":confirm" used, don't give an error message.
2141 */
2142 if (!(p_confirm || cmdmod.confirm))
2143#endif
2144 {
2145 /* There must be a wait_return for this message, do_buffer()
2146 * may cause a redraw. But wait_return() is a no-op when vgetc()
2147 * is busy (Quit used from window menu), then make sure we don't
2148 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002149 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002150 {
2151 msg_row = cmdline_row;
2152 msg_col = 0;
2153 msg_didout = FALSE;
2154 }
2155 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002156 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002157 {
2158 save = no_wait_return;
2159 no_wait_return = FALSE;
2160 wait_return(FALSE);
2161 no_wait_return = save;
2162 }
2163 }
2164
2165#ifdef FEAT_WINDOWS
2166 /* Try to find a window that contains the buffer. */
2167 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002168 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002169 if (wp->w_buffer == buf)
2170 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002171# ifdef FEAT_AUTOCMD
2172 bufref_T bufref;
2173
2174 set_bufref(&bufref, buf);
2175# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002176 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002177# ifdef FEAT_AUTOCMD
2178 /* Paranoia: did autocms wipe out the buffer with changes? */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002179 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002180 {
2181 goto theend;
2182 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002184 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002186buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002187#endif
2188
2189 /* Open the changed buffer in the current window. */
2190 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002191 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002192
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002193theend:
2194 vim_free(bufnrs);
2195 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002196}
2197
2198/*
2199 * return FAIL if there is no file name, OK if there is one
2200 * give error message for FAIL
2201 */
2202 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002203check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002204{
2205 if (curbuf->b_ffname == NULL)
2206 {
2207 EMSG(_(e_noname));
2208 return FAIL;
2209 }
2210 return OK;
2211}
2212
2213/*
2214 * flush the contents of a buffer, unless it has no file name
2215 *
2216 * return FAIL for failure, OK otherwise
2217 */
2218 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002219buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220{
2221 int retval;
2222#ifdef FEAT_AUTOCMD
2223 buf_T *old_curbuf = curbuf;
2224#endif
2225
2226 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2227 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2228 FALSE, forceit, TRUE, FALSE));
2229#ifdef FEAT_AUTOCMD
2230 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002231 {
2232 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002233 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002234 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002235#endif
2236 return retval;
2237}
2238
2239/*
2240 * Code to handle the argument list.
2241 */
2242
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002243static char_u *do_one_arg(char_u *str);
2244static int do_arglist(char_u *str, int what, int after);
2245static void alist_check_arg_idx(void);
2246static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002247#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002248static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002249#endif
2250#define AL_SET 1
2251#define AL_ADD 2
2252#define AL_DEL 3
2253
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002255 * Isolate one argument, taking backticks.
2256 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 * Return a pointer to the start of the next argument.
2258 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002259 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002260do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261{
2262 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002263 int inbacktick;
2264
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 inbacktick = FALSE;
2266 for (p = str; *str; ++str)
2267 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002268 /* When the backslash is used for escaping the special meaning of a
2269 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 if (rem_backslash(str))
2271 {
2272 *p++ = *str++;
2273 *p++ = *str;
2274 }
2275 else
2276 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002277 /* An item ends at a space not in backticks */
2278 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002280 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002281 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002282 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 }
2284 }
2285 str = skipwhite(str);
2286 *p = NUL;
2287
2288 return str;
2289}
2290
Bram Moolenaar86b68352004-12-27 21:59:20 +00002291/*
2292 * Separate the arguments in "str" and return a list of pointers in the
2293 * growarray "gap".
2294 */
2295 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002296get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002297{
2298 ga_init2(gap, (int)sizeof(char_u *), 20);
2299 while (*str != NUL)
2300 {
2301 if (ga_grow(gap, 1) == FAIL)
2302 {
2303 ga_clear(gap);
2304 return FAIL;
2305 }
2306 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2307
2308 /* Isolate one argument, change it in-place, put a NUL after it. */
2309 str = do_one_arg(str);
2310 }
2311 return OK;
2312}
2313
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002314#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002315/*
2316 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002317 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002318 * Return FAIL or OK.
2319 */
2320 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002321get_arglist_exp(
2322 char_u *str,
2323 int *fcountp,
2324 char_u ***fnamesp,
2325 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002326{
2327 garray_T ga;
2328 int i;
2329
2330 if (get_arglist(&ga, str) == FAIL)
2331 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002332 if (wig == TRUE)
2333 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2334 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2335 else
2336 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2337 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2338
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002339 ga_clear(&ga);
2340 return i;
2341}
2342#endif
2343
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2345/*
2346 * Redefine the argument list.
2347 */
2348 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002349set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350{
2351 do_arglist(str, AL_SET, 0);
2352}
2353#endif
2354
2355/*
2356 * "what" == AL_SET: Redefine the argument list to 'str'.
2357 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2358 * "what" == AL_DEL: remove files in 'str' from the argument list.
2359 *
2360 * Return FAIL for failure, OK otherwise.
2361 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002363do_arglist(
2364 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002365 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002366 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367{
2368 garray_T new_ga;
2369 int exp_count;
2370 char_u **exp_files;
2371 int i;
2372#ifdef FEAT_LISTCMDS
2373 char_u *p;
2374 int match;
2375#endif
2376
2377 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002378 * Set default argument for ":argadd" command.
2379 */
2380 if (what == AL_ADD && *str == NUL)
2381 {
2382 if (curbuf->b_ffname == NULL)
2383 return FAIL;
2384 str = curbuf->b_fname;
2385 }
2386
2387 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 * Collect all file name arguments in "new_ga".
2389 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002390 if (get_arglist(&new_ga, str) == FAIL)
2391 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392
2393#ifdef FEAT_LISTCMDS
2394 if (what == AL_DEL)
2395 {
2396 regmatch_T regmatch;
2397 int didone;
2398
2399 /*
2400 * Delete the items: use each item as a regexp and find a match in the
2401 * argument list.
2402 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002403 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2405 {
2406 p = ((char_u **)new_ga.ga_data)[i];
2407 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2408 if (p == NULL)
2409 break;
2410 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2411 if (regmatch.regprog == NULL)
2412 {
2413 vim_free(p);
2414 break;
2415 }
2416
2417 didone = FALSE;
2418 for (match = 0; match < ARGCOUNT; ++match)
2419 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2420 (colnr_T)0))
2421 {
2422 didone = TRUE;
2423 vim_free(ARGLIST[match].ae_fname);
2424 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2425 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2426 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002427 if (curwin->w_arg_idx > match)
2428 --curwin->w_arg_idx;
2429 --match;
2430 }
2431
Bram Moolenaar473de612013-06-08 18:19:48 +02002432 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433 vim_free(p);
2434 if (!didone)
2435 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2436 }
2437 ga_clear(&new_ga);
2438 }
2439 else
2440#endif
2441 {
2442 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2443 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2444 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002445 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446 {
2447 EMSG(_(e_nomatch));
2448 return FAIL;
2449 }
2450
2451#ifdef FEAT_LISTCMDS
2452 if (what == AL_ADD)
2453 {
2454 (void)alist_add_list(exp_count, exp_files, after);
2455 vim_free(exp_files);
2456 }
2457 else /* what == AL_SET */
2458#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002459 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 }
2461
2462 alist_check_arg_idx();
2463
2464 return OK;
2465}
2466
2467/*
2468 * Check the validity of the arg_idx for each other window.
2469 */
2470 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002471alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002472{
2473#ifdef FEAT_WINDOWS
2474 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002475 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476
Bram Moolenaarf740b292006-02-16 22:11:02 +00002477 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002478 if (win->w_alist == curwin->w_alist)
2479 check_arg_idx(win);
2480#else
2481 check_arg_idx(curwin);
2482#endif
2483}
2484
2485/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002486 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002487 * index.
2488 */
2489 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002490editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002491{
2492 return !(win->w_arg_idx >= WARGCOUNT(win)
2493 || (win->w_buffer->b_fnum
2494 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2495 && (win->w_buffer->b_ffname == NULL
2496 || !(fullpathcmp(
2497 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2498 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2499}
2500
2501/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 * Check if window "win" is editing the w_arg_idx file in its argument list.
2503 */
2504 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002505check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002506{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002507 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002508 {
2509 /* We are not editing the current entry in the argument list.
2510 * Set "arg_had_last" if we are editing the last one. */
2511 win->w_arg_idx_invalid = TRUE;
2512 if (win->w_arg_idx != WARGCOUNT(win) - 1
2513 && arg_had_last == FALSE
2514#ifdef FEAT_WINDOWS
2515 && ALIST(win) == &global_alist
2516#endif
2517 && GARGCOUNT > 0
2518 && win->w_arg_idx < GARGCOUNT
2519 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2520 || (win->w_buffer->b_ffname != NULL
2521 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2522 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2523 arg_had_last = TRUE;
2524 }
2525 else
2526 {
2527 /* We are editing the current entry in the argument list.
2528 * Set "arg_had_last" if it's also the last one */
2529 win->w_arg_idx_invalid = FALSE;
2530 if (win->w_arg_idx == WARGCOUNT(win) - 1
2531#ifdef FEAT_WINDOWS
2532 && win->w_alist == &global_alist
2533#endif
2534 )
2535 arg_had_last = TRUE;
2536 }
2537}
2538
2539/*
2540 * ":args", ":argslocal" and ":argsglobal".
2541 */
2542 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002543ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002544{
2545 int i;
2546
2547 if (eap->cmdidx != CMD_args)
2548 {
2549#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2550 alist_unlink(ALIST(curwin));
2551 if (eap->cmdidx == CMD_argglobal)
2552 ALIST(curwin) = &global_alist;
2553 else /* eap->cmdidx == CMD_arglocal */
2554 alist_new();
2555#else
2556 ex_ni(eap);
2557 return;
2558#endif
2559 }
2560
2561 if (!ends_excmd(*eap->arg))
2562 {
2563 /*
2564 * ":args file ..": define new argument list, handle like ":next"
2565 * Also for ":argslocal file .." and ":argsglobal file ..".
2566 */
2567 ex_next(eap);
2568 }
2569 else
2570#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2571 if (eap->cmdidx == CMD_args)
2572#endif
2573 {
2574 /*
2575 * ":args": list arguments.
2576 */
2577 if (ARGCOUNT > 0)
2578 {
2579 /* Overwrite the command, for a short list there is no scrolling
2580 * required and no wait_return(). */
2581 gotocmdline(TRUE);
2582 for (i = 0; i < ARGCOUNT; ++i)
2583 {
2584 if (i == curwin->w_arg_idx)
2585 msg_putchar('[');
2586 msg_outtrans(alist_name(&ARGLIST[i]));
2587 if (i == curwin->w_arg_idx)
2588 msg_putchar(']');
2589 msg_putchar(' ');
2590 }
2591 }
2592 }
2593#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2594 else if (eap->cmdidx == CMD_arglocal)
2595 {
2596 garray_T *gap = &curwin->w_alist->al_ga;
2597
2598 /*
2599 * ":argslocal": make a local copy of the global argument list.
2600 */
2601 if (ga_grow(gap, GARGCOUNT) == OK)
2602 for (i = 0; i < GARGCOUNT; ++i)
2603 if (GARGLIST[i].ae_fname != NULL)
2604 {
2605 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2606 vim_strsave(GARGLIST[i].ae_fname);
2607 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2608 GARGLIST[i].ae_fnum;
2609 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610 }
2611 }
2612#endif
2613}
2614
2615/*
2616 * ":previous", ":sprevious", ":Next" and ":sNext".
2617 */
2618 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002619ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620{
2621 /* If past the last one already, go to the last one. */
2622 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2623 do_argfile(eap, ARGCOUNT - 1);
2624 else
2625 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2626}
2627
2628/*
2629 * ":rewind", ":first", ":sfirst" and ":srewind".
2630 */
2631 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002632ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633{
2634 do_argfile(eap, 0);
2635}
2636
2637/*
2638 * ":last" and ":slast".
2639 */
2640 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002641ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642{
2643 do_argfile(eap, ARGCOUNT - 1);
2644}
2645
2646/*
2647 * ":argument" and ":sargument".
2648 */
2649 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002650ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651{
2652 int i;
2653
2654 if (eap->addr_count > 0)
2655 i = eap->line2 - 1;
2656 else
2657 i = curwin->w_arg_idx;
2658 do_argfile(eap, i);
2659}
2660
2661/*
2662 * Edit file "argn" of the argument lists.
2663 */
2664 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002665do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002666{
2667 int other;
2668 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002669 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002670
2671 if (argn < 0 || argn >= ARGCOUNT)
2672 {
2673 if (ARGCOUNT <= 1)
2674 EMSG(_("E163: There is only one file to edit"));
2675 else if (argn < 0)
2676 EMSG(_("E164: Cannot go before first file"));
2677 else
2678 EMSG(_("E165: Cannot go beyond last file"));
2679 }
2680 else
2681 {
2682 setpcmark();
2683#ifdef FEAT_GUI
2684 need_mouse_correct = TRUE;
2685#endif
2686
2687#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002688 /* split window or create new tab page first */
2689 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690 {
2691 if (win_split(0, 0) == FAIL)
2692 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002693 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694 }
2695 else
2696#endif
2697 {
2698 /*
2699 * if 'hidden' set, only check for changed file when re-editing
2700 * the same buffer
2701 */
2702 other = TRUE;
2703 if (P_HID(curbuf))
2704 {
2705 p = fix_fname(alist_name(&ARGLIST[argn]));
2706 other = otherfile(p);
2707 vim_free(p);
2708 }
2709 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002710 && check_changed(curbuf, CCGD_AW
2711 | (other ? 0 : CCGD_MULTWIN)
2712 | (eap->forceit ? CCGD_FORCEIT : 0)
2713 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 return;
2715 }
2716
2717 curwin->w_arg_idx = argn;
2718 if (argn == ARGCOUNT - 1
2719#ifdef FEAT_WINDOWS
2720 && curwin->w_alist == &global_alist
2721#endif
2722 )
2723 arg_had_last = TRUE;
2724
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002725 /* Edit the file; always use the last known line number.
2726 * When it fails (e.g. Abort for already edited file) restore the
2727 * argument index. */
2728 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002730 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2731 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002732 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002733 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002734 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002735 setmark('\'');
2736 }
2737}
2738
2739/*
2740 * ":next", and commands that behave like it.
2741 */
2742 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002743ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744{
2745 int i;
2746
2747 /*
2748 * check for changed buffer now, if this fails the argument list is not
2749 * redefined.
2750 */
2751 if ( P_HID(curbuf)
2752 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002753 || !check_changed(curbuf, CCGD_AW
2754 | (eap->forceit ? CCGD_FORCEIT : 0)
2755 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 {
2757 if (*eap->arg != NUL) /* redefine file list */
2758 {
2759 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2760 return;
2761 i = 0;
2762 }
2763 else
2764 i = curwin->w_arg_idx + (int)eap->line2;
2765 do_argfile(eap, i);
2766 }
2767}
2768
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002769#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002770/*
2771 * ":argedit"
2772 */
2773 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002774ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775{
2776 int fnum;
2777 int i;
2778 char_u *s;
2779
2780 /* Add the argument to the buffer list and get the buffer number. */
2781 fnum = buflist_add(eap->arg, BLN_LISTED);
2782
2783 /* Check if this argument is already in the argument list. */
2784 for (i = 0; i < ARGCOUNT; ++i)
2785 if (ARGLIST[i].ae_fnum == fnum)
2786 break;
2787 if (i == ARGCOUNT)
2788 {
2789 /* Can't find it, add it to the argument list. */
2790 s = vim_strsave(eap->arg);
2791 if (s == NULL)
2792 return;
2793 i = alist_add_list(1, &s,
2794 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2795 if (i < 0)
2796 return;
2797 curwin->w_arg_idx = i;
2798 }
2799
2800 alist_check_arg_idx();
2801
2802 /* Edit the argument. */
2803 do_argfile(eap, i);
2804}
2805
2806/*
2807 * ":argadd"
2808 */
2809 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002810ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811{
2812 do_arglist(eap->arg, AL_ADD,
2813 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2814#ifdef FEAT_TITLE
2815 maketitle();
2816#endif
2817}
2818
2819/*
2820 * ":argdelete"
2821 */
2822 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002823ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824{
2825 int i;
2826 int n;
2827
2828 if (eap->addr_count > 0)
2829 {
2830 /* ":1,4argdel": Delete all arguments in the range. */
2831 if (eap->line2 > ARGCOUNT)
2832 eap->line2 = ARGCOUNT;
2833 n = eap->line2 - eap->line1 + 1;
2834 if (*eap->arg != NUL || n <= 0)
2835 EMSG(_(e_invarg));
2836 else
2837 {
2838 for (i = eap->line1; i <= eap->line2; ++i)
2839 vim_free(ARGLIST[i - 1].ae_fname);
2840 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2841 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2842 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 if (curwin->w_arg_idx >= eap->line2)
2844 curwin->w_arg_idx -= n;
2845 else if (curwin->w_arg_idx > eap->line1)
2846 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002847 if (ARGCOUNT == 0)
2848 curwin->w_arg_idx = 0;
2849 else if (curwin->w_arg_idx >= ARGCOUNT)
2850 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851 }
2852 }
2853 else if (*eap->arg == NUL)
2854 EMSG(_(e_argreq));
2855 else
2856 do_arglist(eap->arg, AL_DEL, 0);
2857#ifdef FEAT_TITLE
2858 maketitle();
2859#endif
2860}
2861
2862/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002863 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002864 */
2865 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002866ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002867{
2868 int i;
2869#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002870 win_T *wp;
2871 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002873 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002874 int next_fnum = 0;
2875#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2876 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002877#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002878 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002879#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002880 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002881 int qf_idx;
2882#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002883
2884#ifndef FEAT_WINDOWS
2885 if (eap->cmdidx == CMD_windo)
2886 {
2887 ex_ni(eap);
2888 return;
2889 }
2890#endif
2891
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002892#ifndef FEAT_QUICKFIX
2893 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2894 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2895 {
2896 ex_ni(eap);
2897 return;
2898 }
2899#endif
2900
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002902 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002903 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2904 * great speed improvement. */
2905 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002907#ifdef FEAT_CLIPBOARD
2908 start_global_changes();
2909#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910
2911 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002912 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002914 || !check_changed(curbuf, CCGD_AW
2915 | (eap->forceit ? CCGD_FORCEIT : 0)
2916 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002918 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002919 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002921 wp = firstwin;
2922 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002924 switch (eap->cmdidx)
2925 {
2926#ifdef FEAT_WINDOWS
2927 case CMD_windo:
2928 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2929 i++;
2930 break;
2931 case CMD_tabdo:
2932 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2933 i++;
2934 break;
2935#endif
2936 case CMD_argdo:
2937 i = eap->line1 - 1;
2938 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002939 default:
2940 break;
2941 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 /* set pcmark now */
2943 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002944 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002945 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002946 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002947 || !buf->b_p_bl); buf = buf->b_next)
2948 if (buf->b_fnum > eap->line2)
2949 {
2950 buf = NULL;
2951 break;
2952 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002953 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002954 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002955 }
2956#ifdef FEAT_QUICKFIX
2957 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2958 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2959 {
2960 qf_size = qf_get_size(eap);
2961 if (qf_size <= 0 || eap->line1 > qf_size)
2962 buf = NULL;
2963 else
2964 {
2965 ex_cc(eap);
2966
2967 buf = curbuf;
2968 i = eap->line1 - 1;
2969 if (eap->addr_count <= 0)
2970 /* default is all the quickfix/location list entries */
2971 eap->line2 = qf_size;
2972 }
2973 }
2974#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002975 else
2976 setpcmark();
2977 listcmd_busy = TRUE; /* avoids setting pcmark below */
2978
Bram Moolenaare25bb902015-02-27 20:33:37 +01002979 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002980 {
2981 if (eap->cmdidx == CMD_argdo)
2982 {
2983 /* go to argument "i" */
2984 if (i == ARGCOUNT)
2985 break;
2986 /* Don't call do_argfile() when already there, it will try
2987 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002988 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002989 {
2990 /* Clear 'shm' to avoid that the file message overwrites
2991 * any output from the command. */
2992 p_shm_save = vim_strsave(p_shm);
2993 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002994 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002995 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2996 vim_free(p_shm_save);
2997 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002998 if (curwin->w_arg_idx != i)
2999 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 }
3001#ifdef FEAT_WINDOWS
3002 else if (eap->cmdidx == CMD_windo)
3003 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003004 /* go to window "wp" */
3005 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003006 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003007 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00003008 if (curwin != wp)
3009 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003010 wp = curwin->w_next;
3011 }
3012 else if (eap->cmdidx == CMD_tabdo)
3013 {
3014 /* go to window "tp" */
3015 if (!valid_tabpage(tp))
3016 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003017 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003018 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003019 }
3020#endif
3021 else if (eap->cmdidx == CMD_bufdo)
3022 {
3023 /* Remember the number of the next listed buffer, in case
3024 * ":bwipe" is used or autocommands do something strange. */
3025 next_fnum = -1;
3026 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
3027 if (buf->b_p_bl)
3028 {
3029 next_fnum = buf->b_fnum;
3030 break;
3031 }
3032 }
3033
Bram Moolenaara162bc52015-01-07 16:54:21 +01003034 ++i;
3035
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036 /* execute the command */
3037 do_cmdline(eap->arg, eap->getline, eap->cookie,
3038 DOCMD_VERBOSE + DOCMD_NOWAIT);
3039
3040 if (eap->cmdidx == CMD_bufdo)
3041 {
3042 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01003043 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044 break;
3045 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02003046 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003047 if (buf->b_fnum == next_fnum)
3048 break;
3049 if (buf == NULL)
3050 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003051
3052 /* Go to the next buffer. Clear 'shm' to avoid that the file
3053 * message overwrites any output from the command. */
3054 p_shm_save = vim_strsave(p_shm);
3055 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003057 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3058 vim_free(p_shm_save);
3059
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003060 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061 if (curbuf->b_fnum != next_fnum)
3062 break;
3063 }
3064
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003065#ifdef FEAT_QUICKFIX
3066 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
3067 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3068 {
3069 if (i >= qf_size || i >= eap->line2)
3070 break;
3071
3072 qf_idx = qf_get_cur_idx(eap);
3073
3074 ex_cnext(eap);
3075
3076 /* If jumping to the next quickfix entry fails, quit here */
3077 if (qf_get_cur_idx(eap) == qf_idx)
3078 break;
3079 }
3080#endif
3081
Bram Moolenaar071d4272004-06-13 20:20:40 +00003082 if (eap->cmdidx == CMD_windo)
3083 {
3084 validate_cursor(); /* cursor may have moved */
3085#ifdef FEAT_SCROLLBIND
3086 /* required when 'scrollbind' has been set */
3087 if (curwin->w_p_scb)
3088 do_check_scrollbind(TRUE);
3089#endif
3090 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01003091
3092#ifdef FEAT_WINDOWS
3093 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
3094 if (i+1 > eap->line2)
3095 break;
3096#endif
3097 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
3098 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003099 }
3100 listcmd_busy = FALSE;
3101 }
3102
3103#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003104 if (save_ei != NULL)
3105 {
3106 au_event_restore(save_ei);
3107 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
3108 curbuf->b_fname, TRUE, curbuf);
3109 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003110#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02003111#ifdef FEAT_CLIPBOARD
3112 end_global_changes();
3113#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114}
3115
3116/*
3117 * Add files[count] to the arglist of the current window after arg "after".
3118 * The file names in files[count] must have been allocated and are taken over.
3119 * Files[] itself is not taken over.
3120 * Returns index of first added argument. Returns -1 when failed (out of mem).
3121 */
3122 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003123alist_add_list(
3124 int count,
3125 char_u **files,
3126 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003127{
3128 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003129 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130
3131 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
3132 {
3133 if (after < 0)
3134 after = 0;
3135 if (after > ARGCOUNT)
3136 after = ARGCOUNT;
3137 if (after < ARGCOUNT)
3138 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
3139 (ARGCOUNT - after) * sizeof(aentry_T));
3140 for (i = 0; i < count; ++i)
3141 {
3142 ARGLIST[after + i].ae_fname = files[i];
3143 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
3144 }
3145 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003146 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3147 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148 return after;
3149 }
3150
3151 for (i = 0; i < count; ++i)
3152 vim_free(files[i]);
3153 return -1;
3154}
3155
3156#endif /* FEAT_LISTCMDS */
3157
3158#ifdef FEAT_EVAL
3159/*
3160 * ":compiler[!] {name}"
3161 */
3162 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003163ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003164{
3165 char_u *buf;
3166 char_u *old_cur_comp = NULL;
3167 char_u *p;
3168
3169 if (*eap->arg == NUL)
3170 {
3171 /* List all compiler scripts. */
3172 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3173 /* ) keep the indenter happy... */
3174 }
3175 else
3176 {
3177 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3178 if (buf != NULL)
3179 {
3180 if (eap->forceit)
3181 {
3182 /* ":compiler! {name}" sets global options */
3183 do_cmdline_cmd((char_u *)
3184 "command -nargs=* CompilerSet set <args>");
3185 }
3186 else
3187 {
3188 /* ":compiler! {name}" sets local options.
3189 * To remain backwards compatible "current_compiler" is always
3190 * used. A user's compiler plugin may set it, the distributed
3191 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003192 * "b:current_compiler" and restore "current_compiler".
3193 * Explicitly prepend "g:" to make it work in a function. */
3194 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003195 if (old_cur_comp != NULL)
3196 old_cur_comp = vim_strsave(old_cur_comp);
3197 do_cmdline_cmd((char_u *)
3198 "command -nargs=* CompilerSet setlocal <args>");
3199 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003200 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003201 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003202
3203 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003204 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003205 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3206 vim_free(buf);
3207
3208 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3209
3210 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003211 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 if (p != NULL)
3213 set_internal_string_var((char_u *)"b:current_compiler", p);
3214
3215 /* Restore "current_compiler" for ":compiler {name}". */
3216 if (!eap->forceit)
3217 {
3218 if (old_cur_comp != NULL)
3219 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003220 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221 old_cur_comp);
3222 vim_free(old_cur_comp);
3223 }
3224 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003225 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 }
3227 }
3228 }
3229}
3230#endif
3231
3232/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003233 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234 */
3235 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003236ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003238 char_u *arg = eap->arg;
3239 char_u *p = skiptowhite(arg);
3240 int len = (int)(p - arg);
3241 int flags = eap->forceit ? DIP_ALL : 0;
3242
3243 if (STRNCMP(arg, "START", len) == 0)
3244 {
3245 flags += DIP_START + DIP_NORTP;
3246 arg = skipwhite(arg + len);
3247 }
3248 else if (STRNCMP(arg, "OPT", len) == 0)
3249 {
3250 flags += DIP_OPT + DIP_NORTP;
3251 arg = skipwhite(arg + len);
3252 }
3253 else if (STRNCMP(arg, "PACK", len) == 0)
3254 {
3255 flags += DIP_START + DIP_OPT + DIP_NORTP;
3256 arg = skipwhite(arg + len);
3257 }
3258 else if (STRNCMP(arg, "ALL", len) == 0)
3259 {
3260 flags += DIP_START + DIP_OPT;
3261 arg = skipwhite(arg + len);
3262 }
3263
3264 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265}
3266
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003268source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003270 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271}
3272
3273/*
3274 * Source the file "name" from all directories in 'runtimepath'.
3275 * "name" can contain wildcards.
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003276 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
Bram Moolenaar91715872016-03-03 17:13:03 +01003277 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278 * return FAIL when no file could be sourced, OK otherwise.
3279 */
3280 int
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003281source_runtime(char_u *name, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003282{
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003283 return do_in_runtimepath(name, flags, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284}
3285
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003286/*
3287 * Find the file "name" in all directories in "path" and invoke
3288 * "callback(fname, cookie)".
3289 * "name" can contain wildcards.
3290 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3291 * When "flags" has DIP_DIR: find directories instead of files.
3292 * When "flags" has DIP_ERR: give an error message if there is no match.
3293 *
3294 * return FAIL when no file could be sourced, OK otherwise.
3295 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003296 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003297do_in_path(
3298 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003299 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003300 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003301 void (*callback)(char_u *fname, void *ck),
3302 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303{
3304 char_u *rtp;
3305 char_u *np;
3306 char_u *buf;
3307 char_u *rtp_copy;
3308 char_u *tail;
3309 int num_files;
3310 char_u **files;
3311 int i;
3312 int did_one = FALSE;
3313#ifdef AMIGA
3314 struct Process *proc = (struct Process *)FindTask(0L);
3315 APTR save_winptr = proc->pr_WindowPtr;
3316
3317 /* Avoid a requester here for a volume that doesn't exist. */
3318 proc->pr_WindowPtr = (APTR)-1L;
3319#endif
3320
3321 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3322 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003323 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 buf = alloc(MAXPATHL);
3325 if (buf != NULL && rtp_copy != NULL)
3326 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003327 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003328 {
3329 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003330 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003331 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003332 verbose_leave();
3333 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003334
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335 /* Loop over all entries in 'runtimepath'. */
3336 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003337 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02003339 size_t buflen;
3340
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 /* Copy the path from 'runtimepath' to buf[]. */
3342 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02003343 buflen = STRLEN(buf);
3344
3345 /* Skip after or non-after directories. */
3346 if (flags & (DIP_NOAFTER | DIP_AFTER))
3347 {
3348 int is_after = buflen >= 5
3349 && STRCMP(buf + buflen - 5, "after") == 0;
3350
3351 if ((is_after && (flags & DIP_NOAFTER))
3352 || (!is_after && (flags & DIP_AFTER)))
3353 continue;
3354 }
3355
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003356 if (name == NULL)
3357 {
3358 (*callback)(buf, (void *) &cookie);
3359 if (!did_one)
3360 did_one = (cookie == NULL);
3361 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02003362 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363 {
3364 add_pathsep(buf);
3365 tail = buf + STRLEN(buf);
3366
3367 /* Loop over all patterns in "name" */
3368 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003369 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 {
3371 /* Append the pattern from "name" to buf[]. */
3372 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3373 "\t ");
3374
3375 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003376 {
3377 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003378 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003379 verbose_leave();
3380 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381
3382 /* Expand wildcards, invoke the callback for each match. */
3383 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003384 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385 {
3386 for (i = 0; i < num_files; ++i)
3387 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003388 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003389 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003390 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003391 break;
3392 }
3393 FreeWild(num_files, files);
3394 }
3395 }
3396 }
3397 }
3398 }
3399 vim_free(buf);
3400 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003401 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003402 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003403 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3404
3405 if (flags & DIP_ERR)
3406 EMSG3(_(e_dirnotf), basepath, name);
3407 else if (p_verbose > 0)
3408 {
3409 verbose_enter();
3410 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3411 verbose_leave();
3412 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003413 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414
3415#ifdef AMIGA
3416 proc->pr_WindowPtr = save_winptr;
3417#endif
3418
3419 return did_one ? OK : FAIL;
3420}
3421
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003422/*
3423 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3424 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003425 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3426 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003427 * Returns OK when at least one match found, FAIL otherwise.
3428 *
3429 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3430 * passed by reference in this case, setting it to NULL indicates that callback
3431 * has done its job.
3432 */
3433 int
3434do_in_runtimepath(
3435 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003436 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003437 void (*callback)(char_u *fname, void *ck),
3438 void *cookie)
3439{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003440 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003441 char_u *s;
3442 int len;
3443 char *start_dir = "pack/*/start/*/%s";
3444 char *opt_dir = "pack/*/opt/*/%s";
3445
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003446 if ((flags & DIP_NORTP) == 0)
3447 done = do_in_path(p_rtp, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003448
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003449 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003450 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003451 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003452 s = alloc(len);
3453 if (s == NULL)
3454 return FAIL;
3455 vim_snprintf((char *)s, len, start_dir, name);
3456 done = do_in_path(p_pp, s, flags, callback, cookie);
3457 vim_free(s);
3458 }
3459
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003460 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003461 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003462 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003463 s = alloc(len);
3464 if (s == NULL)
3465 return FAIL;
3466 vim_snprintf((char *)s, len, opt_dir, name);
3467 done = do_in_path(p_pp, s, flags, callback, cookie);
3468 vim_free(s);
3469 }
3470
3471 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003472}
3473
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003474/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003475 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003476 */
3477 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003478source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003479{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003480 int num_files;
3481 char_u **files;
3482 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003483
Bram Moolenaarf3654822016-03-04 22:12:23 +01003484 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003485 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003486 for (i = 0; i < num_files; ++i)
3487 (void)do_source(files[i], FALSE, DOSO_NONE);
3488 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003489 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003490}
3491
Bram Moolenaar49b27322016-04-05 21:13:00 +02003492/* used for "cookie" of add_pack_plugin() */
3493static int APP_ADD_DIR;
3494static int APP_LOAD;
3495static int APP_BOTH;
3496
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003497 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003498add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003499{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003500 char_u *p4, *p3, *p2, *p1, *p;
3501 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003502 int c;
3503 char_u *new_rtp;
3504 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003505 size_t oldlen;
3506 size_t addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003507 char_u *afterdir;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003508 size_t afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003509 char_u *ffname = fix_fname(fname);
Bram Moolenaarfef524b2016-07-02 22:07:22 +02003510 size_t fname_len;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003511
Bram Moolenaar91715872016-03-03 17:13:03 +01003512 if (ffname == NULL)
3513 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003514 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003515 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003516 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003517 p4 = p3 = p2 = p1 = get_past_head(ffname);
3518 for (p = p1; *p; mb_ptr_adv(p))
3519 if (vim_ispathsep_nocolon(*p))
3520 {
3521 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3522 }
3523
3524 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003525 * rtp/pack/name/start/name
3526 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003527 *
3528 * find the part up to "pack" in 'runtimepath' */
3529 c = *p4;
3530 *p4 = NUL;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003531
3532 /* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3533 fname_len = STRLEN(ffname);
3534 insp = p_rtp;
3535 for (;;)
3536 {
3537 if (vim_fnamencmp(insp, ffname, fname_len) == 0)
3538 break;
3539 insp = vim_strchr(insp, ',');
3540 if (insp == NULL)
3541 break;
3542 ++insp;
3543 }
3544
Bram Moolenaarf3654822016-03-04 22:12:23 +01003545 if (insp == NULL)
3546 /* not found, append at the end */
3547 insp = p_rtp + STRLEN(p_rtp);
3548 else
3549 {
3550 /* append after the matching directory. */
3551 insp += STRLEN(ffname);
3552 while (*insp != NUL && *insp != ',')
3553 ++insp;
3554 }
3555 *p4 = c;
3556
Bram Moolenaara5702442016-05-24 19:37:29 +02003557 /* check if rtp/pack/name/start/name/after exists */
3558 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3559 if (afterdir != NULL && mch_isdir(afterdir))
3560 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3561
Bram Moolenaarb0550662016-05-31 21:37:36 +02003562 oldlen = STRLEN(p_rtp);
3563 addlen = STRLEN(ffname) + 1; /* add one for comma */
3564 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003565 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003566 goto theend;
3567 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003568 mch_memmove(new_rtp, p_rtp, keep);
3569 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003570 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003571 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003572 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003573 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003574 if (afterlen > 0)
3575 {
3576 STRCAT(new_rtp, ",");
3577 STRCAT(new_rtp, afterdir);
3578 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003579 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3580 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003581 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003582 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003583
Bram Moolenaar49b27322016-04-05 21:13:00 +02003584 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003585 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003586 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003587 static char *ftpat = "%s/ftdetect/*.vim";
3588 int len;
3589 char_u *pat;
3590
3591 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3592 pat = alloc(len);
3593 if (pat == NULL)
3594 goto theend;
3595 vim_snprintf((char *)pat, len, plugpat, ffname);
3596 source_all_matches(pat);
3597
3598#ifdef FEAT_AUTOCMD
3599 {
3600 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3601
3602 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3603 * found when it loads. */
3604 if (cmd != NULL && eval_to_number(cmd) > 0)
3605 {
3606 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3607 vim_snprintf((char *)pat, len, ftpat, ffname);
3608 source_all_matches(pat);
3609 do_cmdline_cmd((char_u *)"augroup END");
3610 }
3611 vim_free(cmd);
3612 }
3613#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003614 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003615 }
3616
3617theend:
3618 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003619}
3620
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003621static int did_source_packages = FALSE;
3622
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003623/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003624 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003625 * Find plugins in the package directories and source them.
Bram Moolenaar66459b72016-08-06 19:01:55 +02003626 * "eap" is NULL when invoked during startup.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003627 */
3628 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003629ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003630{
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003631 if (!did_source_packages || (eap != NULL && eap->forceit))
3632 {
3633 did_source_packages = TRUE;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003634
3635 /* First do a round to add all directories to 'runtimepath', then load
3636 * the plugins. This allows for plugins to use an autoload directory
3637 * of another plugin. */
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003638 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003639 add_pack_plugin, &APP_ADD_DIR);
3640 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3641 add_pack_plugin, &APP_LOAD);
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003642 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003643}
3644
3645/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003646 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003647 */
3648 void
3649ex_packadd(exarg_T *eap)
3650{
3651 static char *plugpat = "pack/*/opt/%s";
3652 int len;
3653 char *pat;
3654
3655 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3656 pat = (char *)alloc(len);
3657 if (pat == NULL)
3658 return;
3659 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003660 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003661 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003662 vim_free(pat);
3663}
3664
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3666/*
3667 * ":options"
3668 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003670ex_options(
3671 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672{
3673 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3674}
3675#endif
3676
3677/*
3678 * ":source {fname}"
3679 */
3680 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003681ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682{
3683#ifdef FEAT_BROWSE
3684 if (cmdmod.browse)
3685 {
3686 char_u *fname = NULL;
3687
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003688 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3690 if (fname != NULL)
3691 {
3692 cmd_source(fname, eap);
3693 vim_free(fname);
3694 }
3695 }
3696 else
3697#endif
3698 cmd_source(eap->arg, eap);
3699}
3700
3701 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003702cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003703{
3704 if (*fname == NUL)
3705 EMSG(_(e_argreq));
3706
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003708 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003709 * Need to execute the commands directly. This is required at least
3710 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711 * - ":g" command busy
3712 * - after ":argdo", ":windo" or ":bufdo"
3713 * - another command follows
3714 * - inside a loop
3715 */
3716 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3717#ifdef FEAT_EVAL
3718 || eap->cstack->cs_idx >= 0
3719#endif
3720 );
3721
3722 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003723 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724 EMSG2(_(e_notopen), fname);
3725}
3726
3727/*
3728 * ":source" and associated commands.
3729 */
3730/*
3731 * Structure used to store info for each sourced file.
3732 * It is shared between do_source() and getsourceline().
3733 * This is required, because it needs to be handed to do_cmdline() and
3734 * sourcing can be done recursively.
3735 */
3736struct source_cookie
3737{
3738 FILE *fp; /* opened file for sourcing */
3739 char_u *nextline; /* if not NULL: line that was read ahead */
3740 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003741#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003742 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3743 int error; /* TRUE if LF found after CR-LF */
3744#endif
3745#ifdef FEAT_EVAL
3746 linenr_T breakpoint; /* next line with breakpoint or zero */
3747 char_u *fname; /* name of sourced file */
3748 int dbg_tick; /* debug_tick when breakpoint was set */
3749 int level; /* top nesting level of sourced file */
3750#endif
3751#ifdef FEAT_MBYTE
3752 vimconv_T conv; /* type of conversion */
3753#endif
3754};
3755
3756#ifdef FEAT_EVAL
3757/*
3758 * Return the address holding the next breakpoint line for a source cookie.
3759 */
3760 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003761source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003762{
3763 return &((struct source_cookie *)cookie)->breakpoint;
3764}
3765
3766/*
3767 * Return the address holding the debug tick for a source cookie.
3768 */
3769 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003770source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771{
3772 return &((struct source_cookie *)cookie)->dbg_tick;
3773}
3774
3775/*
3776 * Return the nesting level for a source cookie.
3777 */
3778 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003779source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003780{
3781 return ((struct source_cookie *)cookie)->level;
3782}
3783#endif
3784
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003785static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003786
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003787#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3788# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003789static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790
3791/*
3792 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003793 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794 */
3795 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003796fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003797{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003798# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003799 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3800# else
3801 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003802# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003803
3804 if (fd_tmp == -1)
3805 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003806
3807# ifdef HAVE_FD_CLOEXEC
3808 {
3809 int fdflags = fcntl(fd_tmp, F_GETFD);
3810 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003811 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003812 }
3813# endif
3814
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 return fdopen(fd_tmp, READBIN);
3816}
3817#endif
3818
3819
3820/*
3821 * do_source: Read the file "fname" and execute its lines as EX commands.
3822 *
3823 * This function may be called recursively!
3824 *
3825 * return FAIL if file could not be opened, OK otherwise
3826 */
3827 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003828do_source(
3829 char_u *fname,
3830 int check_other, /* check for .vimrc and _vimrc */
3831 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832{
3833 struct source_cookie cookie;
3834 char_u *save_sourcing_name;
3835 linenr_T save_sourcing_lnum;
3836 char_u *p;
3837 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003838 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839 int retval = FAIL;
3840#ifdef FEAT_EVAL
3841 scid_T save_current_SID;
3842 static scid_T last_current_SID = 0;
3843 void *save_funccalp;
3844 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003845 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003846# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003847 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848 int stat_ok;
3849# endif
3850#endif
3851#ifdef STARTUPTIME
3852 struct timeval tv_rel;
3853 struct timeval tv_start;
3854#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003855#ifdef FEAT_PROFILE
3856 proftime_T wait_start;
3857#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858
Bram Moolenaar071d4272004-06-13 20:20:40 +00003859 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003860 if (p == NULL)
3861 return retval;
3862 fname_exp = fix_fname(p);
3863 vim_free(p);
3864 if (fname_exp == NULL)
3865 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003866 if (mch_isdir(fname_exp))
3867 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003868 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003869 goto theend;
3870 }
3871
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003872#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003873 /* Apply SourceCmd autocommands, they should get the file and source it. */
3874 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3875 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3876 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003877 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003878# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003879 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003880# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003881 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003882# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003883 goto theend;
3884 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003885
3886 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003887 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3888#endif
3889
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003890#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003891 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3892#else
3893 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3894#endif
3895 if (cookie.fp == NULL && check_other)
3896 {
3897 /*
3898 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3899 * and ".exrc" by "_exrc" or vice versa.
3900 */
3901 p = gettail(fname_exp);
3902 if ((*p == '.' || *p == '_')
3903 && (STRICMP(p + 1, "vimrc") == 0
3904 || STRICMP(p + 1, "gvimrc") == 0
3905 || STRICMP(p + 1, "exrc") == 0))
3906 {
3907 if (*p == '_')
3908 *p = '.';
3909 else
3910 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003911#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003912 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3913#else
3914 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3915#endif
3916 }
3917 }
3918
3919 if (cookie.fp == NULL)
3920 {
3921 if (p_verbose > 0)
3922 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003923 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003924 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003925 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003926 else
3927 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003928 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003929 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003930 }
3931 goto theend;
3932 }
3933
3934 /*
3935 * The file exists.
3936 * - In verbose mode, give a message.
3937 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3938 */
3939 if (p_verbose > 1)
3940 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003941 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003942 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003943 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003944 else
3945 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003946 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003947 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003949 if (is_vimrc == DOSO_VIMRC)
3950 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3951 else if (is_vimrc == DOSO_GVIMRC)
3952 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003953
3954#ifdef USE_CRNL
3955 /* If no automatic file format: Set default to CR-NL. */
3956 if (*p_ffs == NUL)
3957 cookie.fileformat = EOL_DOS;
3958 else
3959 cookie.fileformat = EOL_UNKNOWN;
3960 cookie.error = FALSE;
3961#endif
3962
3963#ifdef USE_CR
3964 /* If no automatic file format: Set default to CR. */
3965 if (*p_ffs == NUL)
3966 cookie.fileformat = EOL_MAC;
3967 else
3968 cookie.fileformat = EOL_UNKNOWN;
3969 cookie.error = FALSE;
3970#endif
3971
3972 cookie.nextline = NULL;
3973 cookie.finished = FALSE;
3974
3975#ifdef FEAT_EVAL
3976 /*
3977 * Check if this script has a breakpoint.
3978 */
3979 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3980 cookie.fname = fname_exp;
3981 cookie.dbg_tick = debug_tick;
3982
3983 cookie.level = ex_nesting_level;
3984#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003985
3986 /*
3987 * Keep the sourcing name/lnum, for recursive calls.
3988 */
3989 save_sourcing_name = sourcing_name;
3990 sourcing_name = fname_exp;
3991 save_sourcing_lnum = sourcing_lnum;
3992 sourcing_lnum = 0;
3993
Bram Moolenaar73881402009-02-04 16:50:47 +00003994#ifdef FEAT_MBYTE
3995 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3996
3997 /* Read the first line so we can check for a UTF-8 BOM. */
3998 firstline = getsourceline(0, (void *)&cookie, 0);
3999 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
4000 && firstline[1] == 0xbb && firstline[2] == 0xbf)
4001 {
4002 /* Found BOM; setup conversion, skip over BOM and recode the line. */
4003 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
4004 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00004005 if (p == NULL)
4006 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00004007 if (p != NULL)
4008 {
4009 vim_free(firstline);
4010 firstline = p;
4011 }
4012 }
4013#endif
4014
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004016 if (time_fd != NULL)
4017 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004018#endif
4019
4020#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00004021# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004022 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004023 prof_child_enter(&wait_start); /* entering a child now */
4024# endif
4025
4026 /* Don't use local function variables, if called from a function.
4027 * Also starts profiling timer for nested script. */
4028 save_funccalp = save_funccal();
4029
Bram Moolenaar071d4272004-06-13 20:20:40 +00004030 /*
4031 * Check if this script was sourced before to finds its SID.
4032 * If it's new, generate a new SID.
4033 */
4034 save_current_SID = current_SID;
4035# ifdef UNIX
4036 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
4037# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004038 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
4039 {
4040 si = &SCRIPT_ITEM(current_SID);
4041 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042 && (
4043# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00004044 /* Compare dev/ino when possible, it catches symbolic
4045 * links. Also compare file names, the inode may change
4046 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004047 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004048 && (si->sn_dev == st.st_dev
4049 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004050# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004051 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004052 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004053 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 if (current_SID == 0)
4055 {
4056 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004057 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
4058 == FAIL)
4059 goto almosttheend;
4060 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004061 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00004062 ++script_items.ga_len;
4063 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
4064# ifdef FEAT_PROFILE
4065 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004066# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004067 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004068 si = &SCRIPT_ITEM(current_SID);
4069 si->sn_name = fname_exp;
4070 fname_exp = NULL;
4071# ifdef UNIX
4072 if (stat_ok)
4073 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004074 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004075 si->sn_dev = st.st_dev;
4076 si->sn_ino = st.st_ino;
4077 }
4078 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004079 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004080# endif
4081
Bram Moolenaar071d4272004-06-13 20:20:40 +00004082 /* Allocate the local script variables to use for this script. */
4083 new_script_vars(current_SID);
4084 }
4085
Bram Moolenaar05159a02005-02-26 23:04:13 +00004086# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004087 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004088 {
4089 int forceit;
4090
4091 /* Check if we do profiling for this script. */
4092 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
4093 {
4094 script_do_profile(si);
4095 si->sn_pr_force = forceit;
4096 }
4097 if (si->sn_prof_on)
4098 {
4099 ++si->sn_pr_count;
4100 profile_start(&si->sn_pr_start);
4101 profile_zero(&si->sn_pr_children);
4102 }
4103 }
4104# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004105#endif
4106
4107 /*
4108 * Call do_cmdline, which will call getsourceline() to get the lines.
4109 */
Bram Moolenaar73881402009-02-04 16:50:47 +00004110 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004111 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004113
4114#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004115 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004116 {
4117 /* Get "si" again, "script_items" may have been reallocated. */
4118 si = &SCRIPT_ITEM(current_SID);
4119 if (si->sn_prof_on)
4120 {
4121 profile_end(&si->sn_pr_start);
4122 profile_sub_wait(&wait_start, &si->sn_pr_start);
4123 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004124 profile_self(&si->sn_pr_self, &si->sn_pr_start,
4125 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004126 }
4127 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004128#endif
4129
4130 if (got_int)
4131 EMSG(_(e_interr));
4132 sourcing_name = save_sourcing_name;
4133 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004134 if (p_verbose > 1)
4135 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004136 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00004137 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004139 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004140 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004141 }
4142#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004143 if (time_fd != NULL)
4144 {
4145 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
4146 time_msg((char *)IObuff, &tv_start);
4147 time_pop(&tv_rel);
4148 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004149#endif
4150
4151#ifdef FEAT_EVAL
4152 /*
4153 * After a "finish" in debug mode, need to break at first command of next
4154 * sourced file.
4155 */
4156 if (save_debug_break_level > ex_nesting_level
4157 && debug_break_level == ex_nesting_level)
4158 ++debug_break_level;
4159#endif
4160
Bram Moolenaar05159a02005-02-26 23:04:13 +00004161#ifdef FEAT_EVAL
4162almosttheend:
4163 current_SID = save_current_SID;
4164 restore_funccal(save_funccalp);
4165# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004166 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004167 prof_child_exit(&wait_start); /* leaving a child now */
4168# endif
4169#endif
4170 fclose(cookie.fp);
4171 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004172 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004173#ifdef FEAT_MBYTE
4174 convert_setup(&cookie.conv, NULL, NULL);
4175#endif
4176
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177theend:
4178 vim_free(fname_exp);
4179 return retval;
4180}
4181
4182#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004183
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184/*
4185 * ":scriptnames"
4186 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004188ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004189{
4190 int i;
4191
Bram Moolenaar05159a02005-02-26 23:04:13 +00004192 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4193 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004194 {
4195 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4196 NameBuff, MAXPATHL, TRUE);
4197 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004198 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004199}
4200
4201# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4202/*
4203 * Fix slashes in the list of script names for 'shellslash'.
4204 */
4205 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004206scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207{
4208 int i;
4209
Bram Moolenaar05159a02005-02-26 23:04:13 +00004210 for (i = 1; i <= script_items.ga_len; ++i)
4211 if (SCRIPT_ITEM(i).sn_name != NULL)
4212 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004213}
4214# endif
4215
4216/*
4217 * Get a pointer to a script name. Used for ":verbose set".
4218 */
4219 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004220get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221{
4222 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004223 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004225 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004227 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004229 return (char_u *)_("environment variable");
4230 if (id == SID_ERROR)
4231 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004232 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004234
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004235# if defined(EXITFREE) || defined(PROTO)
4236 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004237free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004238{
4239 int i;
4240
4241 for (i = script_items.ga_len; i > 0; --i)
4242 vim_free(SCRIPT_ITEM(i).sn_name);
4243 ga_clear(&script_items);
4244}
4245# endif
4246
Bram Moolenaar071d4272004-06-13 20:20:40 +00004247#endif
4248
4249#if defined(USE_CR) || defined(PROTO)
4250
4251# if defined(__MSL__) && (__MSL__ >= 22)
4252/*
4253 * Newer version of the Metrowerks library handle DOS and UNIX files
4254 * without help.
4255 * Test with earlier versions, MSL 2.2 is the library supplied with
4256 * Codewarrior Pro 2.
4257 */
4258 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004259fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004260{
4261 return fgets(s, n, stream);
4262}
4263# else
4264/*
4265 * Version of fgets() which also works for lines ending in a <CR> only
4266 * (Macintosh format).
4267 * For older versions of the Metrowerks library.
4268 * At least CodeWarrior 9 needed this code.
4269 */
4270 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004271fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004272{
4273 int c = 0;
4274 int char_read = 0;
4275
4276 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4277 {
4278 c = fgetc(stream);
4279 s[char_read++] = c;
4280 /* If the file is in DOS format, we need to skip a NL after a CR. I
4281 * thought it was the other way around, but this appears to work... */
4282 if (c == '\n')
4283 {
4284 c = fgetc(stream);
4285 if (c != '\r')
4286 ungetc(c, stream);
4287 }
4288 }
4289
4290 s[char_read] = 0;
4291 if (char_read == 0)
4292 return NULL;
4293
4294 if (feof(stream) && char_read == 1)
4295 return NULL;
4296
4297 return s;
4298}
4299# endif
4300#endif
4301
4302/*
4303 * Get one full line from a sourced file.
4304 * Called by do_cmdline() when it's called from do_source().
4305 *
4306 * Return a pointer to the line in allocated memory.
4307 * Return NULL for end-of-file or some error.
4308 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004310getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004311{
4312 struct source_cookie *sp = (struct source_cookie *)cookie;
4313 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004314 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004315
4316#ifdef FEAT_EVAL
4317 /* If breakpoints have been added/deleted need to check for it. */
4318 if (sp->dbg_tick < debug_tick)
4319 {
4320 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4321 sp->dbg_tick = debug_tick;
4322 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004323# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004324 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004325 script_line_end();
4326# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004327#endif
4328 /*
4329 * Get current line. If there is a read-ahead line, use it, otherwise get
4330 * one now.
4331 */
4332 if (sp->finished)
4333 line = NULL;
4334 else if (sp->nextline == NULL)
4335 line = get_one_sourceline(sp);
4336 else
4337 {
4338 line = sp->nextline;
4339 sp->nextline = NULL;
4340 ++sourcing_lnum;
4341 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004342#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004343 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004344 script_line_start();
4345#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346
4347 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4348 * contain the 'C' flag. */
4349 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4350 {
4351 /* compensate for the one line read-ahead */
4352 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004353
4354 /* Get the next line and concatenate it when it starts with a
4355 * backslash. We always need to read the next line, keep it in
4356 * sp->nextline. */
4357 sp->nextline = get_one_sourceline(sp);
4358 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004360 garray_T ga;
4361
Bram Moolenaarb549a732012-02-22 18:29:33 +01004362 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004363 ga_concat(&ga, line);
4364 ga_concat(&ga, p + 1);
4365 for (;;)
4366 {
4367 vim_free(sp->nextline);
4368 sp->nextline = get_one_sourceline(sp);
4369 if (sp->nextline == NULL)
4370 break;
4371 p = skipwhite(sp->nextline);
4372 if (*p != '\\')
4373 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004374 /* Adjust the growsize to the current length to speed up
4375 * concatenating many lines. */
4376 if (ga.ga_len > 400)
4377 {
4378 if (ga.ga_len > 8000)
4379 ga.ga_growsize = 8000;
4380 else
4381 ga.ga_growsize = ga.ga_len;
4382 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004383 ga_concat(&ga, p + 1);
4384 }
4385 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004386 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004387 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004388 }
4389 }
4390
4391#ifdef FEAT_MBYTE
4392 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4393 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004394 char_u *s;
4395
Bram Moolenaar071d4272004-06-13 20:20:40 +00004396 /* Convert the encoding of the script line. */
4397 s = string_convert(&sp->conv, line, NULL);
4398 if (s != NULL)
4399 {
4400 vim_free(line);
4401 line = s;
4402 }
4403 }
4404#endif
4405
4406#ifdef FEAT_EVAL
4407 /* Did we encounter a breakpoint? */
4408 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4409 {
4410 dbg_breakpoint(sp->fname, sourcing_lnum);
4411 /* Find next breakpoint. */
4412 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4413 sp->dbg_tick = debug_tick;
4414 }
4415#endif
4416
4417 return line;
4418}
4419
4420 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004421get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422{
4423 garray_T ga;
4424 int len;
4425 int c;
4426 char_u *buf;
4427#ifdef USE_CRNL
4428 int has_cr; /* CR-LF found */
4429#endif
4430#ifdef USE_CR
4431 char_u *scan;
4432#endif
4433 int have_read = FALSE;
4434
4435 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004436 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437
4438 /*
4439 * Loop until there is a finished line (or end-of-file).
4440 */
4441 sourcing_lnum++;
4442 for (;;)
4443 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004444 /* make room to read at least 120 (more) characters */
4445 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446 break;
4447 buf = (char_u *)ga.ga_data;
4448
4449#ifdef USE_CR
4450 if (sp->fileformat == EOL_MAC)
4451 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004452 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4453 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004454 break;
4455 }
4456 else
4457#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004458 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4459 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004460 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004461 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004462#ifdef USE_CRNL
4463 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4464 * CTRL-Z by its own, or after a NL. */
4465 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4466 && sp->fileformat == EOL_DOS
4467 && buf[len - 1] == Ctrl_Z)
4468 {
4469 buf[len - 1] = NUL;
4470 break;
4471 }
4472#endif
4473
4474#ifdef USE_CR
4475 /* If the read doesn't stop on a new line, and there's
4476 * some CR then we assume a Mac format */
4477 if (sp->fileformat == EOL_UNKNOWN)
4478 {
4479 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4480 sp->fileformat = EOL_MAC;
4481 else
4482 sp->fileformat = EOL_UNIX;
4483 }
4484
4485 if (sp->fileformat == EOL_MAC)
4486 {
4487 scan = vim_strchr(buf, '\r');
4488
4489 if (scan != NULL)
4490 {
4491 *scan = '\n';
4492 if (*(scan + 1) != 0)
4493 {
4494 *(scan + 1) = 0;
4495 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4496 }
4497 }
4498 len = STRLEN(buf);
4499 }
4500#endif
4501
4502 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503 ga.ga_len = len;
4504
4505 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004506 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507 continue;
4508
4509 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4510 {
4511#ifdef USE_CRNL
4512 has_cr = (len >= 2 && buf[len - 2] == '\r');
4513 if (sp->fileformat == EOL_UNKNOWN)
4514 {
4515 if (has_cr)
4516 sp->fileformat = EOL_DOS;
4517 else
4518 sp->fileformat = EOL_UNIX;
4519 }
4520
4521 if (sp->fileformat == EOL_DOS)
4522 {
4523 if (has_cr) /* replace trailing CR */
4524 {
4525 buf[len - 2] = '\n';
4526 --len;
4527 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528 }
4529 else /* lines like ":map xx yy^M" will have failed */
4530 {
4531 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004532 {
4533 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004535 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004536 sp->error = TRUE;
4537 sp->fileformat = EOL_UNIX;
4538 }
4539 }
4540#endif
4541 /* The '\n' is escaped if there is an odd number of ^V's just
4542 * before it, first set "c" just before the 'V's and then check
4543 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4544 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4545 ;
4546 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4547 {
4548 sourcing_lnum++;
4549 continue;
4550 }
4551
4552 buf[len - 1] = NUL; /* remove the NL */
4553 }
4554
4555 /*
4556 * Check for ^C here now and then, so recursive :so can be broken.
4557 */
4558 line_breakcheck();
4559 break;
4560 }
4561
4562 if (have_read)
4563 return (char_u *)ga.ga_data;
4564
4565 vim_free(ga.ga_data);
4566 return NULL;
4567}
4568
Bram Moolenaar05159a02005-02-26 23:04:13 +00004569#if defined(FEAT_PROFILE) || defined(PROTO)
4570/*
4571 * Called when starting to read a script line.
4572 * "sourcing_lnum" must be correct!
4573 * When skipping lines it may not actually be executed, but we won't find out
4574 * until later and we need to store the time now.
4575 */
4576 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004577script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004578{
4579 scriptitem_T *si;
4580 sn_prl_T *pp;
4581
4582 if (current_SID <= 0 || current_SID > script_items.ga_len)
4583 return;
4584 si = &SCRIPT_ITEM(current_SID);
4585 if (si->sn_prof_on && sourcing_lnum >= 1)
4586 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004587 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004588 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004589 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004590 si->sn_prl_idx = sourcing_lnum - 1;
4591 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4592 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4593 {
4594 /* Zero counters for a line that was not used before. */
4595 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4596 pp->snp_count = 0;
4597 profile_zero(&pp->sn_prl_total);
4598 profile_zero(&pp->sn_prl_self);
4599 ++si->sn_prl_ga.ga_len;
4600 }
4601 si->sn_prl_execed = FALSE;
4602 profile_start(&si->sn_prl_start);
4603 profile_zero(&si->sn_prl_children);
4604 profile_get_wait(&si->sn_prl_wait);
4605 }
4606}
4607
4608/*
4609 * Called when actually executing a function line.
4610 */
4611 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004612script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004613{
4614 scriptitem_T *si;
4615
4616 if (current_SID <= 0 || current_SID > script_items.ga_len)
4617 return;
4618 si = &SCRIPT_ITEM(current_SID);
4619 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4620 si->sn_prl_execed = TRUE;
4621}
4622
4623/*
4624 * Called when done with a function line.
4625 */
4626 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004627script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004628{
4629 scriptitem_T *si;
4630 sn_prl_T *pp;
4631
4632 if (current_SID <= 0 || current_SID > script_items.ga_len)
4633 return;
4634 si = &SCRIPT_ITEM(current_SID);
4635 if (si->sn_prof_on && si->sn_prl_idx >= 0
4636 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4637 {
4638 if (si->sn_prl_execed)
4639 {
4640 pp = &PRL_ITEM(si, si->sn_prl_idx);
4641 ++pp->snp_count;
4642 profile_end(&si->sn_prl_start);
4643 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004644 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004645 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4646 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004647 }
4648 si->sn_prl_idx = -1;
4649 }
4650}
4651#endif
4652
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653/*
4654 * ":scriptencoding": Set encoding conversion for a sourced script.
4655 * Without the multi-byte feature it's simply ignored.
4656 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004658ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004659{
4660#ifdef FEAT_MBYTE
4661 struct source_cookie *sp;
4662 char_u *name;
4663
4664 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4665 {
4666 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4667 return;
4668 }
4669
4670 if (*eap->arg != NUL)
4671 {
4672 name = enc_canonize(eap->arg);
4673 if (name == NULL) /* out of memory */
4674 return;
4675 }
4676 else
4677 name = eap->arg;
4678
4679 /* Setup for conversion from the specified encoding to 'encoding'. */
4680 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4681 convert_setup(&sp->conv, name, p_enc);
4682
4683 if (name != eap->arg)
4684 vim_free(name);
4685#endif
4686}
4687
4688#if defined(FEAT_EVAL) || defined(PROTO)
4689/*
4690 * ":finish": Mark a sourced file as finished.
4691 */
4692 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004693ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004694{
4695 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4696 do_finish(eap, FALSE);
4697 else
4698 EMSG(_("E168: :finish used outside of a sourced file"));
4699}
4700
4701/*
4702 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4703 * Also called for a pending finish at the ":endtry" or after returning from
4704 * an extra do_cmdline(). "reanimate" is used in the latter case.
4705 */
4706 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004707do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708{
4709 int idx;
4710
4711 if (reanimate)
4712 ((struct source_cookie *)getline_cookie(eap->getline,
4713 eap->cookie))->finished = FALSE;
4714
4715 /*
4716 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4717 * not in its finally clause (which then is to be executed next) is found.
4718 * In this case, make the ":finish" pending for execution at the ":endtry".
4719 * Otherwise, finish normally.
4720 */
4721 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4722 if (idx >= 0)
4723 {
4724 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4725 report_make_pending(CSTP_FINISH, NULL);
4726 }
4727 else
4728 ((struct source_cookie *)getline_cookie(eap->getline,
4729 eap->cookie))->finished = TRUE;
4730}
4731
4732
4733/*
4734 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4735 * message for missing ":endif".
4736 * Return FALSE when not sourcing a file.
4737 */
4738 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004739source_finished(
4740 char_u *(*fgetline)(int, void *, int),
4741 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004743 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004744 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004745 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004746}
4747#endif
4748
4749#if defined(FEAT_LISTCMDS) || defined(PROTO)
4750/*
4751 * ":checktime [buffer]"
4752 */
4753 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004754ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004755{
4756 buf_T *buf;
4757 int save_no_check_timestamps = no_check_timestamps;
4758
4759 no_check_timestamps = 0;
4760 if (eap->addr_count == 0) /* default is all buffers */
4761 check_timestamps(FALSE);
4762 else
4763 {
4764 buf = buflist_findnr((int)eap->line2);
4765 if (buf != NULL) /* cannot happen? */
4766 (void)buf_check_timestamp(buf, FALSE);
4767 }
4768 no_check_timestamps = save_no_check_timestamps;
4769}
4770#endif
4771
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4773 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004774# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004775static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004776
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004777 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004778get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004780 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004781
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004782 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004783 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004784
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004785# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 if (loc != NULL)
4787 {
4788 char_u *p;
4789
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004790 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4791 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004792 p = vim_strchr(loc, '=');
4793 if (p != NULL)
4794 {
4795 loc = ++p;
4796 while (*p != NUL) /* remove trailing newline */
4797 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004798 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004799 {
4800 *p = NUL;
4801 break;
4802 }
4803 ++p;
4804 }
4805 }
4806 }
4807# endif
4808
4809 return loc;
4810}
4811#endif
4812
4813
4814#ifdef WIN32
4815/*
4816 * On MS-Windows locale names are strings like "German_Germany.1252", but
4817 * gettext expects "de". Try to translate one into another here for a few
4818 * supported languages.
4819 */
4820 static char_u *
4821gettext_lang(char_u *name)
4822{
4823 int i;
4824 static char *(mtable[]) = {
4825 "afrikaans", "af",
4826 "czech", "cs",
4827 "dutch", "nl",
4828 "german", "de",
4829 "english_united kingdom", "en_GB",
4830 "spanish", "es",
4831 "french", "fr",
4832 "italian", "it",
4833 "japanese", "ja",
4834 "korean", "ko",
4835 "norwegian", "no",
4836 "polish", "pl",
4837 "russian", "ru",
4838 "slovak", "sk",
4839 "swedish", "sv",
4840 "ukrainian", "uk",
4841 "chinese_china", "zh_CN",
4842 "chinese_taiwan", "zh_TW",
4843 NULL};
4844
4845 for (i = 0; mtable[i] != NULL; i += 2)
4846 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004847 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004848 return name;
4849}
4850#endif
4851
4852#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4853/*
4854 * Obtain the current messages language. Used to set the default for
4855 * 'helplang'. May return NULL or an empty string.
4856 */
4857 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004858get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004859{
4860 char_u *p;
4861
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004862# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004863# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004864 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004865# else
4866 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004867 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4868 * and LC_MONETARY may be set differently for a Japanese working in the
4869 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004870 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004871# endif
4872# else
4873 p = mch_getenv((char_u *)"LC_ALL");
4874 if (p == NULL || *p == NUL)
4875 {
4876 p = mch_getenv((char_u *)"LC_MESSAGES");
4877 if (p == NULL || *p == NUL)
4878 p = mch_getenv((char_u *)"LANG");
4879 }
4880# endif
4881# ifdef WIN32
4882 p = gettext_lang(p);
4883# endif
4884 return p;
4885}
4886#endif
4887
Bram Moolenaardef9e822004-12-31 20:58:58 +00004888/* Complicated #if; matches with where get_mess_env() is used below. */
4889#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4890 && defined(LC_MESSAGES))) \
4891 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4892 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4893 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004894static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004895
4896/*
4897 * Get the language used for messages from the environment.
4898 */
4899 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004900get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901{
4902 char_u *p;
4903
4904 p = mch_getenv((char_u *)"LC_ALL");
4905 if (p == NULL || *p == NUL)
4906 {
4907 p = mch_getenv((char_u *)"LC_MESSAGES");
4908 if (p == NULL || *p == NUL)
4909 {
4910 p = mch_getenv((char_u *)"LANG");
4911 if (p != NULL && VIM_ISDIGIT(*p))
4912 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004913# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004914 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004915 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004916# endif
4917 }
4918 }
4919 return p;
4920}
4921#endif
4922
4923#if defined(FEAT_EVAL) || defined(PROTO)
4924
4925/*
4926 * Set the "v:lang" variable according to the current locale setting.
4927 * Also do "v:lc_time"and "v:ctype".
4928 */
4929 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004930set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004931{
4932 char_u *loc;
4933
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004934# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004935 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004936# else
4937 /* setlocale() not supported: use the default value */
4938 loc = (char_u *)"C";
4939# endif
4940 set_vim_var_string(VV_CTYPE, loc, -1);
4941
4942 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4943 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004944# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004945 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004946# else
4947 loc = get_mess_env();
4948# endif
4949 set_vim_var_string(VV_LANG, loc, -1);
4950
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004951# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004952 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004953# endif
4954 set_vim_var_string(VV_LC_TIME, loc, -1);
4955}
4956#endif
4957
4958#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4959 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4960/*
4961 * ":language": Set the language (locale).
4962 */
4963 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004964ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004965{
4966 char *loc;
4967 char_u *p;
4968 char_u *name;
4969 int what = LC_ALL;
4970 char *whatstr = "";
4971#ifdef LC_MESSAGES
4972# define VIM_LC_MESSAGES LC_MESSAGES
4973#else
4974# define VIM_LC_MESSAGES 6789
4975#endif
4976
4977 name = eap->arg;
4978
4979 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4980 * Allow abbreviation, but require at least 3 characters to avoid
4981 * confusion with a two letter language name "me" or "ct". */
4982 p = skiptowhite(eap->arg);
4983 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4984 {
4985 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4986 {
4987 what = VIM_LC_MESSAGES;
4988 name = skipwhite(p);
4989 whatstr = "messages ";
4990 }
4991 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4992 {
4993 what = LC_CTYPE;
4994 name = skipwhite(p);
4995 whatstr = "ctype ";
4996 }
4997 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4998 {
4999 what = LC_TIME;
5000 name = skipwhite(p);
5001 whatstr = "time ";
5002 }
5003 }
5004
5005 if (*name == NUL)
5006 {
5007#ifndef LC_MESSAGES
5008 if (what == VIM_LC_MESSAGES)
5009 p = get_mess_env();
5010 else
5011#endif
5012 p = (char_u *)setlocale(what, NULL);
5013 if (p == NULL || *p == NUL)
5014 p = (char_u *)"Unknown";
5015 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
5016 }
5017 else
5018 {
5019#ifndef LC_MESSAGES
5020 if (what == VIM_LC_MESSAGES)
5021 loc = "";
5022 else
5023#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005024 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005025 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005026#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
5027 /* Make sure strtod() uses a decimal point, not a comma. */
5028 setlocale(LC_NUMERIC, "C");
5029#endif
5030 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005031 if (loc == NULL)
5032 EMSG2(_("E197: Cannot set language to \"%s\""), name);
5033 else
5034 {
5035#ifdef HAVE_NL_MSG_CAT_CNTR
5036 /* Need to do this for GNU gettext, otherwise cached translations
5037 * will be used again. */
5038 extern int _nl_msg_cat_cntr;
5039
5040 ++_nl_msg_cat_cntr;
5041#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00005042 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005043 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
5044
5045 if (what != LC_TIME)
5046 {
5047 /* Tell gettext() what to translate to. It apparently doesn't
5048 * use the currently effective locale. Also do this when
5049 * FEAT_GETTEXT isn't defined, so that shell commands use this
5050 * value. */
5051 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005052 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02005054
5055 /* Clear $LANGUAGE because GNU gettext uses it. */
5056 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005057# ifdef WIN32
5058 /* Apparently MS-Windows printf() may cause a crash when
5059 * we give it 8-bit text while it's expecting text in the
5060 * current locale. This call avoids that. */
5061 setlocale(LC_CTYPE, "C");
5062# endif
5063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005064 if (what != LC_CTYPE)
5065 {
5066 char_u *mname;
5067#ifdef WIN32
5068 mname = gettext_lang(name);
5069#else
5070 mname = name;
5071#endif
5072 vim_setenv((char_u *)"LC_MESSAGES", mname);
5073#ifdef FEAT_MULTI_LANG
5074 set_helplang_default(mname);
5075#endif
5076 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005077 }
5078
5079# ifdef FEAT_EVAL
5080 /* Set v:lang, v:lc_time and v:ctype to the final result. */
5081 set_lang_var();
5082# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02005083# ifdef FEAT_TITLE
5084 maketitle();
5085# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086 }
5087 }
5088}
5089
5090# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005091
5092static char_u **locales = NULL; /* Array of all available locales */
5093static int did_init_locales = FALSE;
5094
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01005095static void init_locales(void);
5096static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005097
5098/*
5099 * Lazy initialization of all available locales.
5100 */
5101 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005102init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005103{
5104 if (!did_init_locales)
5105 {
5106 did_init_locales = TRUE;
5107 locales = find_locales();
5108 }
5109}
5110
5111/* Return an array of strings for all available locales + NULL for the
5112 * last element. Return NULL in case of error. */
5113 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005114find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005115{
5116 garray_T locales_ga;
5117 char_u *loc;
5118
5119 /* Find all available locales by running command "locale -a". If this
5120 * doesn't work we won't have completion. */
5121 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02005122 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005123 if (locale_a == NULL)
5124 return NULL;
5125 ga_init2(&locales_ga, sizeof(char_u *), 20);
5126
5127 /* Transform locale_a string where each locale is separated by "\n"
5128 * into an array of locale strings. */
5129 loc = (char_u *)strtok((char *)locale_a, "\n");
5130
5131 while (loc != NULL)
5132 {
5133 if (ga_grow(&locales_ga, 1) == FAIL)
5134 break;
5135 loc = vim_strsave(loc);
5136 if (loc == NULL)
5137 break;
5138
5139 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
5140 loc = (char_u *)strtok(NULL, "\n");
5141 }
5142 vim_free(locale_a);
5143 if (ga_grow(&locales_ga, 1) == FAIL)
5144 {
5145 ga_clear(&locales_ga);
5146 return NULL;
5147 }
5148 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
5149 return (char_u **)locales_ga.ga_data;
5150}
5151
5152# if defined(EXITFREE) || defined(PROTO)
5153 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005154free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005155{
5156 int i;
5157 if (locales != NULL)
5158 {
5159 for (i = 0; locales[i] != NULL; i++)
5160 vim_free(locales[i]);
5161 vim_free(locales);
5162 locales = NULL;
5163 }
5164}
5165# endif
5166
Bram Moolenaar071d4272004-06-13 20:20:40 +00005167/*
5168 * Function given to ExpandGeneric() to obtain the possible arguments of the
5169 * ":language" command.
5170 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005171 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005172get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005173{
5174 if (idx == 0)
5175 return (char_u *)"messages";
5176 if (idx == 1)
5177 return (char_u *)"ctype";
5178 if (idx == 2)
5179 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005180
5181 init_locales();
5182 if (locales == NULL)
5183 return NULL;
5184 return locales[idx - 3];
5185}
5186
5187/*
5188 * Function given to ExpandGeneric() to obtain the available locales.
5189 */
5190 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005191get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005192{
5193 init_locales();
5194 if (locales == NULL)
5195 return NULL;
5196 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005197}
5198# endif
5199
5200#endif