blob: 85513af296c79c0e8d9b1a4a4be42d74ef9cac6a [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;
1091static int last_timer_id = 0;
1092
1093/*
1094 * Insert a timer in the list of timers.
1095 */
1096 static void
1097insert_timer(timer_T *timer)
1098{
1099 timer->tr_next = first_timer;
1100 timer->tr_prev = NULL;
1101 if (first_timer != NULL)
1102 first_timer->tr_prev = timer;
1103 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +02001104 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001105}
1106
1107/*
1108 * Take a timer out of the list of timers.
1109 */
1110 static void
1111remove_timer(timer_T *timer)
1112{
1113 if (timer->tr_prev == NULL)
1114 first_timer = timer->tr_next;
1115 else
1116 timer->tr_prev->tr_next = timer->tr_next;
1117 if (timer->tr_next != NULL)
1118 timer->tr_next->tr_prev = timer->tr_prev;
1119}
1120
1121 static void
1122free_timer(timer_T *timer)
1123{
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02001124 free_callback(timer->tr_callback, timer->tr_partial);
Bram Moolenaar975b5272016-03-15 23:10:59 +01001125 vim_free(timer);
1126}
1127
1128/*
1129 * Create a timer and return it. NULL if out of memory.
1130 * Caller should set the callback.
1131 */
1132 timer_T *
1133create_timer(long msec, int repeat)
1134{
1135 timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
1136
1137 if (timer == NULL)
1138 return NULL;
1139 timer->tr_id = ++last_timer_id;
1140 insert_timer(timer);
1141 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001142 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001143 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001144
1145 profile_setlimit(msec, &timer->tr_due);
1146 return timer;
1147}
1148
1149/*
1150 * Invoke the callback of "timer".
1151 */
1152 static void
1153timer_callback(timer_T *timer)
1154{
1155 typval_T rettv;
1156 int dummy;
1157 typval_T argv[2];
1158
1159 argv[0].v_type = VAR_NUMBER;
1160 argv[0].vval.v_number = timer->tr_id;
1161 argv[1].v_type = VAR_UNKNOWN;
1162
1163 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
Bram Moolenaardf48fb42016-07-22 21:50:18 +02001164 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar975b5272016-03-15 23:10:59 +01001165 timer->tr_partial, NULL);
1166 clear_tv(&rettv);
1167}
1168
1169/*
1170 * Call timers that are due.
1171 * Return the time in msec until the next timer is due.
1172 */
1173 long
Bram Moolenaarcf089462016-06-12 21:18:43 +02001174check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001175{
1176 timer_T *timer;
1177 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001178 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001179 proftime_T now;
1180 int did_one = FALSE;
1181# ifdef WIN3264
1182 LARGE_INTEGER fr;
1183
1184 QueryPerformanceFrequency(&fr);
1185# endif
1186 while (!got_int)
1187 {
1188 profile_start(&now);
1189 next_due = -1;
1190 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1191 {
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001192 if (timer->tr_paused)
1193 continue;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001194# ifdef WIN3264
1195 this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
1196 / (double)fr.QuadPart) * 1000);
1197# else
1198 this_due = (timer->tr_due.tv_sec - now.tv_sec) * 1000
1199 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1200# endif
1201 if (this_due <= 1)
1202 {
1203 remove_timer(timer);
1204 timer_callback(timer);
1205 did_one = TRUE;
1206 if (timer->tr_repeat != 0)
1207 {
1208 profile_setlimit(timer->tr_interval, &timer->tr_due);
1209 if (timer->tr_repeat > 0)
1210 --timer->tr_repeat;
1211 insert_timer(timer);
1212 }
1213 else
1214 free_timer(timer);
1215 /* the callback may do anything, start all over */
1216 break;
1217 }
1218 if (next_due == -1 || next_due > this_due)
1219 next_due = this_due;
1220 }
1221 if (timer == NULL)
1222 break;
1223 }
1224
1225 if (did_one)
1226 redraw_after_callback();
1227
1228 return next_due;
1229}
1230
1231/*
1232 * Find a timer by ID. Returns NULL if not found;
1233 */
1234 timer_T *
1235find_timer(int id)
1236{
1237 timer_T *timer;
1238
1239 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1240 if (timer->tr_id == id)
1241 break;
1242 return timer;
1243}
1244
1245
1246/*
1247 * Stop a timer and delete it.
1248 */
1249 void
1250stop_timer(timer_T *timer)
1251{
1252 remove_timer(timer);
1253 free_timer(timer);
1254}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001255
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001256 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001257stop_all_timers(void)
1258{
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001259 while (first_timer != NULL)
1260 stop_timer(first_timer);
1261}
1262
1263 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001264add_timer_info(typval_T *rettv, timer_T *timer)
1265{
1266 list_T *list = rettv->vval.v_list;
1267 dict_T *dict = dict_alloc();
1268 dictitem_T *di;
1269 long remaining;
1270 proftime_T now;
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001271# ifdef WIN3264
1272 LARGE_INTEGER fr;
1273#endif
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001274
1275 if (dict == NULL)
1276 return;
1277 list_append_dict(list, dict);
1278
1279 dict_add_nr_str(dict, "id", (long)timer->tr_id, NULL);
1280 dict_add_nr_str(dict, "time", (long)timer->tr_interval, NULL);
1281
1282 profile_start(&now);
1283# ifdef WIN3264
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001284 QueryPerformanceFrequency(&fr);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001285 remaining = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
1286 / (double)fr.QuadPart) * 1000);
1287# else
1288 remaining = (timer->tr_due.tv_sec - now.tv_sec) * 1000
1289 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1290# endif
1291 dict_add_nr_str(dict, "remaining", (long)remaining, NULL);
1292
1293 dict_add_nr_str(dict, "repeat",
1294 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1), NULL);
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001295 dict_add_nr_str(dict, "paused", (long)(timer->tr_paused), NULL);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001296
1297 di = dictitem_alloc((char_u *)"callback");
1298 if (di != NULL)
1299 {
1300 if (dict_add(dict, di) == FAIL)
1301 vim_free(di);
1302 else if (timer->tr_partial != NULL)
1303 {
1304 di->di_tv.v_type = VAR_PARTIAL;
1305 di->di_tv.vval.v_partial = timer->tr_partial;
1306 ++timer->tr_partial->pt_refcount;
1307 }
1308 else
1309 {
1310 di->di_tv.v_type = VAR_FUNC;
1311 di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
1312 }
1313 di->di_tv.v_lock = 0;
1314 }
1315}
1316
1317 void
1318add_timer_info_all(typval_T *rettv)
1319{
1320 timer_T *timer;
1321
1322 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1323 add_timer_info(rettv, timer);
1324}
1325
Bram Moolenaare3188e22016-05-31 21:13:04 +02001326/*
1327 * Mark references in partials of timers.
1328 */
1329 int
1330set_ref_in_timer(int copyID)
1331{
1332 int abort = FALSE;
1333 timer_T *timer;
1334 typval_T tv;
1335
1336 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1337 {
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +02001338 if (timer->tr_partial != NULL)
1339 {
1340 tv.v_type = VAR_PARTIAL;
1341 tv.vval.v_partial = timer->tr_partial;
1342 }
1343 else
1344 {
1345 tv.v_type = VAR_FUNC;
1346 tv.vval.v_string = timer->tr_callback;
1347 }
Bram Moolenaare3188e22016-05-31 21:13:04 +02001348 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1349 }
1350 return abort;
1351}
Bram Moolenaar623e2632016-07-30 22:47:56 +02001352
1353# if defined(EXITFREE) || defined(PROTO)
1354 void
1355timer_free_all()
1356{
1357 timer_T *timer;
1358
1359 while (first_timer != NULL)
1360 {
1361 timer = first_timer;
1362 remove_timer(timer);
1363 free_timer(timer);
1364 }
1365}
1366# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +01001367# endif
1368
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001369#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1370# if defined(HAVE_MATH_H)
1371# include <math.h>
1372# endif
1373
1374/*
1375 * Divide the time "tm" by "count" and store in "tm2".
1376 */
1377 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001378profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001379{
1380 if (count == 0)
1381 profile_zero(tm2);
1382 else
1383 {
1384# ifdef WIN3264
1385 tm2->QuadPart = tm->QuadPart / count;
1386# else
1387 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1388
1389 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001390 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001391# endif
1392 }
1393}
1394#endif
1395
Bram Moolenaar76929292008-01-06 19:07:36 +00001396# if defined(FEAT_PROFILE) || defined(PROTO)
1397/*
1398 * Functions for profiling.
1399 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001400static void script_do_profile(scriptitem_T *si);
1401static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001402static proftime_T prof_wait_time;
1403
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001404/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001405 * Add the time "tm2" to "tm".
1406 */
1407 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001408profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001409{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001410# ifdef WIN3264
1411 tm->QuadPart += tm2->QuadPart;
1412# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001413 tm->tv_usec += tm2->tv_usec;
1414 tm->tv_sec += tm2->tv_sec;
1415 if (tm->tv_usec >= 1000000)
1416 {
1417 tm->tv_usec -= 1000000;
1418 ++tm->tv_sec;
1419 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001420# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001421}
1422
1423/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001424 * Add the "self" time from the total time and the children's time.
1425 */
1426 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001427profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001428{
1429 /* Check that the result won't be negative. Can happen with recursive
1430 * calls. */
1431#ifdef WIN3264
1432 if (total->QuadPart <= children->QuadPart)
1433 return;
1434#else
1435 if (total->tv_sec < children->tv_sec
1436 || (total->tv_sec == children->tv_sec
1437 && total->tv_usec <= children->tv_usec))
1438 return;
1439#endif
1440 profile_add(self, total);
1441 profile_sub(self, children);
1442}
1443
1444/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001445 * Get the current waittime.
1446 */
1447 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001448profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001449{
1450 *tm = prof_wait_time;
1451}
1452
1453/*
1454 * Subtract the passed waittime since "tm" from "tma".
1455 */
1456 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001457profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001458{
1459 proftime_T tm3 = prof_wait_time;
1460
1461 profile_sub(&tm3, tm);
1462 profile_sub(tma, &tm3);
1463}
1464
1465/*
1466 * Return TRUE if "tm1" and "tm2" are equal.
1467 */
1468 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001469profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001470{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001471# ifdef WIN3264
1472 return (tm1->QuadPart == tm2->QuadPart);
1473# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001474 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001475# endif
1476}
1477
1478/*
1479 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1480 */
1481 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001482profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001483{
1484# ifdef WIN3264
1485 return (int)(tm2->QuadPart - tm1->QuadPart);
1486# else
1487 if (tm1->tv_sec == tm2->tv_sec)
1488 return tm2->tv_usec - tm1->tv_usec;
1489 return tm2->tv_sec - tm1->tv_sec;
1490# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001491}
1492
Bram Moolenaar05159a02005-02-26 23:04:13 +00001493static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001494static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001495
1496/*
1497 * ":profile cmd args"
1498 */
1499 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001500ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001501{
1502 char_u *e;
1503 int len;
1504
1505 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001506 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001507 e = skipwhite(e);
1508
1509 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1510 {
1511 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001512 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001513 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001514 profile_zero(&prof_wait_time);
1515 set_vim_var_nr(VV_PROFILING, 1L);
1516 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001517 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001518 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001519 else if (STRCMP(eap->arg, "pause") == 0)
1520 {
1521 if (do_profiling == PROF_YES)
1522 profile_start(&pause_time);
1523 do_profiling = PROF_PAUSED;
1524 }
1525 else if (STRCMP(eap->arg, "continue") == 0)
1526 {
1527 if (do_profiling == PROF_PAUSED)
1528 {
1529 profile_end(&pause_time);
1530 profile_add(&prof_wait_time, &pause_time);
1531 }
1532 do_profiling = PROF_YES;
1533 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001534 else
1535 {
1536 /* The rest is similar to ":breakadd". */
1537 ex_breakadd(eap);
1538 }
1539}
1540
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001541/* Command line expansion for :profile. */
1542static enum
1543{
1544 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001545 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001546} pexpand_what;
1547
1548static char *pexpand_cmds[] = {
1549 "start",
1550#define PROFCMD_START 0
1551 "pause",
1552#define PROFCMD_PAUSE 1
1553 "continue",
1554#define PROFCMD_CONTINUE 2
1555 "func",
1556#define PROFCMD_FUNC 3
1557 "file",
1558#define PROFCMD_FILE 4
1559 NULL
1560#define PROFCMD_LAST 5
1561};
1562
1563/*
1564 * Function given to ExpandGeneric() to obtain the profile command
1565 * specific expansion.
1566 */
1567 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001568get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001569{
1570 switch (pexpand_what)
1571 {
1572 case PEXP_SUBCMD:
1573 return (char_u *)pexpand_cmds[idx];
1574 /* case PEXP_FUNC: TODO */
1575 default:
1576 return NULL;
1577 }
1578}
1579
1580/*
1581 * Handle command line completion for :profile command.
1582 */
1583 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001584set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001585{
1586 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001587
1588 /* Default: expand subcommands. */
1589 xp->xp_context = EXPAND_PROFILE;
1590 pexpand_what = PEXP_SUBCMD;
1591 xp->xp_pattern = arg;
1592
1593 end_subcmd = skiptowhite(arg);
1594 if (*end_subcmd == NUL)
1595 return;
1596
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001597 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001598 {
1599 xp->xp_context = EXPAND_FILES;
1600 xp->xp_pattern = skipwhite(end_subcmd);
1601 return;
1602 }
1603
1604 /* TODO: expand function names after "func" */
1605 xp->xp_context = EXPAND_NOTHING;
1606}
1607
Bram Moolenaar05159a02005-02-26 23:04:13 +00001608/*
1609 * Dump the profiling info.
1610 */
1611 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001612profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001613{
1614 FILE *fd;
1615
1616 if (profile_fname != NULL)
1617 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001618 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001619 if (fd == NULL)
1620 EMSG2(_(e_notopen), profile_fname);
1621 else
1622 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001623 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001624 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001625 fclose(fd);
1626 }
1627 }
1628}
1629
1630/*
1631 * Start profiling script "fp".
1632 */
1633 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001634script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001635{
1636 si->sn_pr_count = 0;
1637 profile_zero(&si->sn_pr_total);
1638 profile_zero(&si->sn_pr_self);
1639
1640 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1641 si->sn_prl_idx = -1;
1642 si->sn_prof_on = TRUE;
1643 si->sn_pr_nest = 0;
1644}
1645
1646/*
1647 * save time when starting to invoke another script or function.
1648 */
1649 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001650script_prof_save(
1651 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001652{
1653 scriptitem_T *si;
1654
1655 if (current_SID > 0 && current_SID <= script_items.ga_len)
1656 {
1657 si = &SCRIPT_ITEM(current_SID);
1658 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1659 profile_start(&si->sn_pr_child);
1660 }
1661 profile_get_wait(tm);
1662}
1663
1664/*
1665 * Count time spent in children after invoking another script or function.
1666 */
1667 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001668script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001669{
1670 scriptitem_T *si;
1671
1672 if (current_SID > 0 && current_SID <= script_items.ga_len)
1673 {
1674 si = &SCRIPT_ITEM(current_SID);
1675 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1676 {
1677 profile_end(&si->sn_pr_child);
1678 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1679 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1680 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1681 }
1682 }
1683}
1684
1685static proftime_T inchar_time;
1686
1687/*
1688 * Called when starting to wait for the user to type a character.
1689 */
1690 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001691prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001692{
1693 profile_start(&inchar_time);
1694}
1695
1696/*
1697 * Called when finished waiting for the user to type a character.
1698 */
1699 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001700prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001701{
1702 profile_end(&inchar_time);
1703 profile_add(&prof_wait_time, &inchar_time);
1704}
1705
1706/*
1707 * Dump the profiling results for all scripts in file "fd".
1708 */
1709 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001710script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001711{
1712 int id;
1713 scriptitem_T *si;
1714 int i;
1715 FILE *sfd;
1716 sn_prl_T *pp;
1717
1718 for (id = 1; id <= script_items.ga_len; ++id)
1719 {
1720 si = &SCRIPT_ITEM(id);
1721 if (si->sn_prof_on)
1722 {
1723 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1724 if (si->sn_pr_count == 1)
1725 fprintf(fd, "Sourced 1 time\n");
1726 else
1727 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1728 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1729 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1730 fprintf(fd, "\n");
1731 fprintf(fd, "count total (s) self (s)\n");
1732
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001733 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001734 if (sfd == NULL)
1735 fprintf(fd, "Cannot open file!\n");
1736 else
1737 {
1738 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1739 {
1740 if (vim_fgets(IObuff, IOSIZE, sfd))
1741 break;
1742 pp = &PRL_ITEM(si, i);
1743 if (pp->snp_count > 0)
1744 {
1745 fprintf(fd, "%5d ", pp->snp_count);
1746 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1747 fprintf(fd, " ");
1748 else
1749 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1750 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1751 }
1752 else
1753 fprintf(fd, " ");
1754 fprintf(fd, "%s", IObuff);
1755 }
1756 fclose(sfd);
1757 }
1758 fprintf(fd, "\n");
1759 }
1760 }
1761}
1762
1763/*
1764 * Return TRUE when a function defined in the current script should be
1765 * profiled.
1766 */
1767 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001768prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001769{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001770 if (current_SID > 0)
1771 return SCRIPT_ITEM(current_SID).sn_pr_force;
1772 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001773}
1774
1775# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001776#endif
1777
1778/*
1779 * If 'autowrite' option set, try to write the file.
1780 * Careful: autocommands may make "buf" invalid!
1781 *
1782 * return FAIL for failure, OK otherwise
1783 */
1784 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001785autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001786{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001787 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001788 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001789
Bram Moolenaar071d4272004-06-13 20:20:40 +00001790 if (!(p_aw || p_awa) || !p_write
1791#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001792 /* never autowrite a "nofile" or "nowrite" buffer */
1793 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001795 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001797 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001798 r = buf_write_all(buf, forceit);
1799
1800 /* Writing may succeed but the buffer still changed, e.g., when there is a
1801 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001802 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001803 r = FAIL;
1804 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001805}
1806
1807/*
1808 * flush all buffers, except the ones that are readonly
1809 */
1810 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001811autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812{
1813 buf_T *buf;
1814
1815 if (!(p_aw || p_awa) || !p_write)
1816 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001817 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818 if (bufIsChanged(buf) && !buf->b_p_ro)
1819 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001820#ifdef FEAT_AUTOCMD
1821 bufref_T bufref;
1822
1823 set_bufref(&bufref, buf);
1824#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001825 (void)buf_write_all(buf, FALSE);
1826#ifdef FEAT_AUTOCMD
1827 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001828 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829 buf = firstbuf;
1830#endif
1831 }
1832}
1833
1834/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001835 * Return TRUE if buffer was changed and cannot be abandoned.
1836 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001837 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001839check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001840{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001841 int forceit = (flags & CCGD_FORCEIT);
1842#ifdef FEAT_AUTOCMD
1843 bufref_T bufref;
1844
1845 set_bufref(&bufref, buf);
1846#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001847
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848 if ( !forceit
1849 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001850 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1851 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852 {
1853#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1854 if ((p_confirm || cmdmod.confirm) && p_write)
1855 {
1856 buf_T *buf2;
1857 int count = 0;
1858
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001859 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001860 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861 if (bufIsChanged(buf2)
1862 && (buf2->b_ffname != NULL
1863# ifdef FEAT_BROWSE
1864 || cmdmod.browse
1865# endif
1866 ))
1867 ++count;
1868# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001869 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001870 /* Autocommand deleted buffer, oops! It's not changed now. */
1871 return FALSE;
1872# endif
1873 dialog_changed(buf, count > 1);
1874# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001875 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876 /* Autocommand deleted buffer, oops! It's not changed now. */
1877 return FALSE;
1878# endif
1879 return bufIsChanged(buf);
1880 }
1881#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001882 if (flags & CCGD_EXCMD)
1883 EMSG(_(e_nowrtmsg));
1884 else
1885 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886 return TRUE;
1887 }
1888 return FALSE;
1889}
1890
1891#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1892
1893#if defined(FEAT_BROWSE) || defined(PROTO)
1894/*
1895 * When wanting to write a file without a file name, ask the user for a name.
1896 */
1897 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001898browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899{
1900 if (buf->b_fname == NULL)
1901 {
1902 char_u *fname;
1903
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001904 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1905 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001906 if (fname != NULL)
1907 {
1908 if (setfname(buf, fname, NULL, TRUE) == OK)
1909 buf->b_flags |= BF_NOTEDITED;
1910 vim_free(fname);
1911 }
1912 }
1913}
1914#endif
1915
1916/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001917 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918 * Must check 'write' option first!
1919 */
1920 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001921dialog_changed(
1922 buf_T *buf,
1923 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001925 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 int ret;
1927 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001928 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001930 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 (buf->b_fname != NULL) ?
1932 buf->b_fname : (char_u *)_("Untitled"));
1933 if (checkall)
1934 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1935 else
1936 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1937
Bram Moolenaar8218f602012-04-25 17:32:18 +02001938 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1939 * function. */
1940 ea.append = ea.forceit = FALSE;
1941
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942 if (ret == VIM_YES)
1943 {
1944#ifdef FEAT_BROWSE
1945 /* May get file name, when there is none */
1946 browse_save_fname(buf);
1947#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001948 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1949 buf->b_fname, buf->b_ffname, FALSE) == OK)
1950 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001951 (void)buf_write_all(buf, FALSE);
1952 }
1953 else if (ret == VIM_NO)
1954 {
1955 unchanged(buf, TRUE);
1956 }
1957 else if (ret == VIM_ALL)
1958 {
1959 /*
1960 * Write all modified files that can be written.
1961 * Skip readonly buffers, these need to be confirmed
1962 * individually.
1963 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001964 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 {
1966 if (bufIsChanged(buf2)
1967 && (buf2->b_ffname != NULL
1968#ifdef FEAT_BROWSE
1969 || cmdmod.browse
1970#endif
1971 )
1972 && !buf2->b_p_ro)
1973 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001974#ifdef FEAT_AUTOCMD
1975 bufref_T bufref;
1976
1977 set_bufref(&bufref, buf2);
1978#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979#ifdef FEAT_BROWSE
1980 /* May get file name, when there is none */
1981 browse_save_fname(buf2);
1982#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001983 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1984 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1985 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986 (void)buf_write_all(buf2, FALSE);
1987#ifdef FEAT_AUTOCMD
1988 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001989 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001990 buf2 = firstbuf;
1991#endif
1992 }
1993 }
1994 }
1995 else if (ret == VIM_DISCARDALL)
1996 {
1997 /*
1998 * mark all buffers as unchanged
1999 */
Bram Moolenaar29323592016-07-24 22:04:11 +02002000 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002001 unchanged(buf2, TRUE);
2002 }
2003}
2004#endif
2005
2006/*
2007 * Return TRUE if the buffer "buf" can be abandoned, either by making it
2008 * hidden, autowriting it or unloading it.
2009 */
2010 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002011can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002012{
2013 return ( P_HID(buf)
2014 || !bufIsChanged(buf)
2015 || buf->b_nwindows > 1
2016 || autowrite(buf, forceit) == OK
2017 || forceit);
2018}
2019
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002020static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002021
2022/*
2023 * Add a buffer number to "bufnrs", unless it's already there.
2024 */
2025 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002026add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002027{
2028 int i;
2029
2030 for (i = 0; i < *bufnump; ++i)
2031 if (bufnrs[i] == nr)
2032 return;
2033 bufnrs[*bufnump] = nr;
2034 *bufnump = *bufnump + 1;
2035}
2036
Bram Moolenaar071d4272004-06-13 20:20:40 +00002037/*
2038 * Return TRUE if any buffer was changed and cannot be abandoned.
2039 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01002040 * When "unload" is true the current buffer is unloaded instead of making it
2041 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002042 */
2043 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002044check_changed_any(
2045 int hidden, /* Only check hidden buffers */
2046 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002048 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002049 buf_T *buf;
2050 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002051 int i;
2052 int bufnum = 0;
2053 int bufcount = 0;
2054 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002055#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002056 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057 win_T *wp;
2058#endif
2059
Bram Moolenaar29323592016-07-24 22:04:11 +02002060 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002061 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002063 if (bufcount == 0)
2064 return FALSE;
2065
2066 bufnrs = (int *)alloc(sizeof(int) * bufcount);
2067 if (bufnrs == NULL)
2068 return FALSE;
2069
2070 /* curbuf */
2071 bufnrs[bufnum++] = curbuf->b_fnum;
2072#ifdef FEAT_WINDOWS
2073 /* buf in curtab */
2074 FOR_ALL_WINDOWS(wp)
2075 if (wp->w_buffer != curbuf)
2076 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2077
2078 /* buf in other tab */
Bram Moolenaar29323592016-07-24 22:04:11 +02002079 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002080 if (tp != curtab)
2081 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
2082 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2083#endif
2084 /* any other buf */
Bram Moolenaar29323592016-07-24 22:04:11 +02002085 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002086 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
2087
2088 for (i = 0; i < bufnum; ++i)
2089 {
2090 buf = buflist_findnr(bufnrs[i]);
2091 if (buf == NULL)
2092 continue;
2093 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
2094 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002095 bufref_T bufref;
2096
2097 set_bufref(&bufref, buf);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002098 /* Try auto-writing the buffer. If this fails but the buffer no
2099 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002100 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
2101 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002102 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002103 break; /* didn't save - still changes */
2104 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002105 }
2106
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002107 if (i >= bufnum)
2108 goto theend;
2109
2110 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111 exiting = FALSE;
2112#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2113 /*
2114 * When ":confirm" used, don't give an error message.
2115 */
2116 if (!(p_confirm || cmdmod.confirm))
2117#endif
2118 {
2119 /* There must be a wait_return for this message, do_buffer()
2120 * may cause a redraw. But wait_return() is a no-op when vgetc()
2121 * is busy (Quit used from window menu), then make sure we don't
2122 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002123 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124 {
2125 msg_row = cmdline_row;
2126 msg_col = 0;
2127 msg_didout = FALSE;
2128 }
2129 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002130 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 {
2132 save = no_wait_return;
2133 no_wait_return = FALSE;
2134 wait_return(FALSE);
2135 no_wait_return = save;
2136 }
2137 }
2138
2139#ifdef FEAT_WINDOWS
2140 /* Try to find a window that contains the buffer. */
2141 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002142 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143 if (wp->w_buffer == buf)
2144 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002145# ifdef FEAT_AUTOCMD
2146 bufref_T bufref;
2147
2148 set_bufref(&bufref, buf);
2149# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002150 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002151# ifdef FEAT_AUTOCMD
2152 /* Paranoia: did autocms wipe out the buffer with changes? */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002153 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002154 {
2155 goto theend;
2156 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002157# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002158 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002159 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002160buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002161#endif
2162
2163 /* Open the changed buffer in the current window. */
2164 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002165 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002166
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002167theend:
2168 vim_free(bufnrs);
2169 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170}
2171
2172/*
2173 * return FAIL if there is no file name, OK if there is one
2174 * give error message for FAIL
2175 */
2176 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002177check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178{
2179 if (curbuf->b_ffname == NULL)
2180 {
2181 EMSG(_(e_noname));
2182 return FAIL;
2183 }
2184 return OK;
2185}
2186
2187/*
2188 * flush the contents of a buffer, unless it has no file name
2189 *
2190 * return FAIL for failure, OK otherwise
2191 */
2192 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002193buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002194{
2195 int retval;
2196#ifdef FEAT_AUTOCMD
2197 buf_T *old_curbuf = curbuf;
2198#endif
2199
2200 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2201 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2202 FALSE, forceit, TRUE, FALSE));
2203#ifdef FEAT_AUTOCMD
2204 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002205 {
2206 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002207 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002208 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002209#endif
2210 return retval;
2211}
2212
2213/*
2214 * Code to handle the argument list.
2215 */
2216
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002217static char_u *do_one_arg(char_u *str);
2218static int do_arglist(char_u *str, int what, int after);
2219static void alist_check_arg_idx(void);
2220static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002221#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002222static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002223#endif
2224#define AL_SET 1
2225#define AL_ADD 2
2226#define AL_DEL 3
2227
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002229 * Isolate one argument, taking backticks.
2230 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002231 * Return a pointer to the start of the next argument.
2232 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002233 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002234do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002235{
2236 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002237 int inbacktick;
2238
Bram Moolenaar071d4272004-06-13 20:20:40 +00002239 inbacktick = FALSE;
2240 for (p = str; *str; ++str)
2241 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002242 /* When the backslash is used for escaping the special meaning of a
2243 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002244 if (rem_backslash(str))
2245 {
2246 *p++ = *str++;
2247 *p++ = *str;
2248 }
2249 else
2250 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002251 /* An item ends at a space not in backticks */
2252 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002253 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002254 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002256 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 }
2258 }
2259 str = skipwhite(str);
2260 *p = NUL;
2261
2262 return str;
2263}
2264
Bram Moolenaar86b68352004-12-27 21:59:20 +00002265/*
2266 * Separate the arguments in "str" and return a list of pointers in the
2267 * growarray "gap".
2268 */
2269 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002270get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002271{
2272 ga_init2(gap, (int)sizeof(char_u *), 20);
2273 while (*str != NUL)
2274 {
2275 if (ga_grow(gap, 1) == FAIL)
2276 {
2277 ga_clear(gap);
2278 return FAIL;
2279 }
2280 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2281
2282 /* Isolate one argument, change it in-place, put a NUL after it. */
2283 str = do_one_arg(str);
2284 }
2285 return OK;
2286}
2287
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002288#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002289/*
2290 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002291 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002292 * Return FAIL or OK.
2293 */
2294 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002295get_arglist_exp(
2296 char_u *str,
2297 int *fcountp,
2298 char_u ***fnamesp,
2299 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002300{
2301 garray_T ga;
2302 int i;
2303
2304 if (get_arglist(&ga, str) == FAIL)
2305 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002306 if (wig == TRUE)
2307 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2308 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2309 else
2310 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2311 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2312
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002313 ga_clear(&ga);
2314 return i;
2315}
2316#endif
2317
Bram Moolenaar071d4272004-06-13 20:20:40 +00002318#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2319/*
2320 * Redefine the argument list.
2321 */
2322 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002323set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324{
2325 do_arglist(str, AL_SET, 0);
2326}
2327#endif
2328
2329/*
2330 * "what" == AL_SET: Redefine the argument list to 'str'.
2331 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2332 * "what" == AL_DEL: remove files in 'str' from the argument list.
2333 *
2334 * Return FAIL for failure, OK otherwise.
2335 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002337do_arglist(
2338 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002339 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002340 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002341{
2342 garray_T new_ga;
2343 int exp_count;
2344 char_u **exp_files;
2345 int i;
2346#ifdef FEAT_LISTCMDS
2347 char_u *p;
2348 int match;
2349#endif
2350
2351 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002352 * Set default argument for ":argadd" command.
2353 */
2354 if (what == AL_ADD && *str == NUL)
2355 {
2356 if (curbuf->b_ffname == NULL)
2357 return FAIL;
2358 str = curbuf->b_fname;
2359 }
2360
2361 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 * Collect all file name arguments in "new_ga".
2363 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002364 if (get_arglist(&new_ga, str) == FAIL)
2365 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366
2367#ifdef FEAT_LISTCMDS
2368 if (what == AL_DEL)
2369 {
2370 regmatch_T regmatch;
2371 int didone;
2372
2373 /*
2374 * Delete the items: use each item as a regexp and find a match in the
2375 * argument list.
2376 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002377 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2379 {
2380 p = ((char_u **)new_ga.ga_data)[i];
2381 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2382 if (p == NULL)
2383 break;
2384 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2385 if (regmatch.regprog == NULL)
2386 {
2387 vim_free(p);
2388 break;
2389 }
2390
2391 didone = FALSE;
2392 for (match = 0; match < ARGCOUNT; ++match)
2393 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2394 (colnr_T)0))
2395 {
2396 didone = TRUE;
2397 vim_free(ARGLIST[match].ae_fname);
2398 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2399 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2400 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002401 if (curwin->w_arg_idx > match)
2402 --curwin->w_arg_idx;
2403 --match;
2404 }
2405
Bram Moolenaar473de612013-06-08 18:19:48 +02002406 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002407 vim_free(p);
2408 if (!didone)
2409 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2410 }
2411 ga_clear(&new_ga);
2412 }
2413 else
2414#endif
2415 {
2416 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2417 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2418 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002419 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420 {
2421 EMSG(_(e_nomatch));
2422 return FAIL;
2423 }
2424
2425#ifdef FEAT_LISTCMDS
2426 if (what == AL_ADD)
2427 {
2428 (void)alist_add_list(exp_count, exp_files, after);
2429 vim_free(exp_files);
2430 }
2431 else /* what == AL_SET */
2432#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002433 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434 }
2435
2436 alist_check_arg_idx();
2437
2438 return OK;
2439}
2440
2441/*
2442 * Check the validity of the arg_idx for each other window.
2443 */
2444 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002445alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446{
2447#ifdef FEAT_WINDOWS
2448 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002449 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450
Bram Moolenaarf740b292006-02-16 22:11:02 +00002451 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452 if (win->w_alist == curwin->w_alist)
2453 check_arg_idx(win);
2454#else
2455 check_arg_idx(curwin);
2456#endif
2457}
2458
2459/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002460 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002461 * index.
2462 */
2463 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002464editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002465{
2466 return !(win->w_arg_idx >= WARGCOUNT(win)
2467 || (win->w_buffer->b_fnum
2468 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2469 && (win->w_buffer->b_ffname == NULL
2470 || !(fullpathcmp(
2471 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2472 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2473}
2474
2475/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476 * Check if window "win" is editing the w_arg_idx file in its argument list.
2477 */
2478 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002479check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002481 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 {
2483 /* We are not editing the current entry in the argument list.
2484 * Set "arg_had_last" if we are editing the last one. */
2485 win->w_arg_idx_invalid = TRUE;
2486 if (win->w_arg_idx != WARGCOUNT(win) - 1
2487 && arg_had_last == FALSE
2488#ifdef FEAT_WINDOWS
2489 && ALIST(win) == &global_alist
2490#endif
2491 && GARGCOUNT > 0
2492 && win->w_arg_idx < GARGCOUNT
2493 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2494 || (win->w_buffer->b_ffname != NULL
2495 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2496 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2497 arg_had_last = TRUE;
2498 }
2499 else
2500 {
2501 /* We are editing the current entry in the argument list.
2502 * Set "arg_had_last" if it's also the last one */
2503 win->w_arg_idx_invalid = FALSE;
2504 if (win->w_arg_idx == WARGCOUNT(win) - 1
2505#ifdef FEAT_WINDOWS
2506 && win->w_alist == &global_alist
2507#endif
2508 )
2509 arg_had_last = TRUE;
2510 }
2511}
2512
2513/*
2514 * ":args", ":argslocal" and ":argsglobal".
2515 */
2516 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002517ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518{
2519 int i;
2520
2521 if (eap->cmdidx != CMD_args)
2522 {
2523#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2524 alist_unlink(ALIST(curwin));
2525 if (eap->cmdidx == CMD_argglobal)
2526 ALIST(curwin) = &global_alist;
2527 else /* eap->cmdidx == CMD_arglocal */
2528 alist_new();
2529#else
2530 ex_ni(eap);
2531 return;
2532#endif
2533 }
2534
2535 if (!ends_excmd(*eap->arg))
2536 {
2537 /*
2538 * ":args file ..": define new argument list, handle like ":next"
2539 * Also for ":argslocal file .." and ":argsglobal file ..".
2540 */
2541 ex_next(eap);
2542 }
2543 else
2544#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2545 if (eap->cmdidx == CMD_args)
2546#endif
2547 {
2548 /*
2549 * ":args": list arguments.
2550 */
2551 if (ARGCOUNT > 0)
2552 {
2553 /* Overwrite the command, for a short list there is no scrolling
2554 * required and no wait_return(). */
2555 gotocmdline(TRUE);
2556 for (i = 0; i < ARGCOUNT; ++i)
2557 {
2558 if (i == curwin->w_arg_idx)
2559 msg_putchar('[');
2560 msg_outtrans(alist_name(&ARGLIST[i]));
2561 if (i == curwin->w_arg_idx)
2562 msg_putchar(']');
2563 msg_putchar(' ');
2564 }
2565 }
2566 }
2567#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2568 else if (eap->cmdidx == CMD_arglocal)
2569 {
2570 garray_T *gap = &curwin->w_alist->al_ga;
2571
2572 /*
2573 * ":argslocal": make a local copy of the global argument list.
2574 */
2575 if (ga_grow(gap, GARGCOUNT) == OK)
2576 for (i = 0; i < GARGCOUNT; ++i)
2577 if (GARGLIST[i].ae_fname != NULL)
2578 {
2579 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2580 vim_strsave(GARGLIST[i].ae_fname);
2581 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2582 GARGLIST[i].ae_fnum;
2583 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 }
2585 }
2586#endif
2587}
2588
2589/*
2590 * ":previous", ":sprevious", ":Next" and ":sNext".
2591 */
2592 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002593ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594{
2595 /* If past the last one already, go to the last one. */
2596 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2597 do_argfile(eap, ARGCOUNT - 1);
2598 else
2599 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2600}
2601
2602/*
2603 * ":rewind", ":first", ":sfirst" and ":srewind".
2604 */
2605 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002606ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607{
2608 do_argfile(eap, 0);
2609}
2610
2611/*
2612 * ":last" and ":slast".
2613 */
2614 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002615ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616{
2617 do_argfile(eap, ARGCOUNT - 1);
2618}
2619
2620/*
2621 * ":argument" and ":sargument".
2622 */
2623 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002624ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002625{
2626 int i;
2627
2628 if (eap->addr_count > 0)
2629 i = eap->line2 - 1;
2630 else
2631 i = curwin->w_arg_idx;
2632 do_argfile(eap, i);
2633}
2634
2635/*
2636 * Edit file "argn" of the argument lists.
2637 */
2638 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002639do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640{
2641 int other;
2642 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002643 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644
2645 if (argn < 0 || argn >= ARGCOUNT)
2646 {
2647 if (ARGCOUNT <= 1)
2648 EMSG(_("E163: There is only one file to edit"));
2649 else if (argn < 0)
2650 EMSG(_("E164: Cannot go before first file"));
2651 else
2652 EMSG(_("E165: Cannot go beyond last file"));
2653 }
2654 else
2655 {
2656 setpcmark();
2657#ifdef FEAT_GUI
2658 need_mouse_correct = TRUE;
2659#endif
2660
2661#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002662 /* split window or create new tab page first */
2663 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002664 {
2665 if (win_split(0, 0) == FAIL)
2666 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002667 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002668 }
2669 else
2670#endif
2671 {
2672 /*
2673 * if 'hidden' set, only check for changed file when re-editing
2674 * the same buffer
2675 */
2676 other = TRUE;
2677 if (P_HID(curbuf))
2678 {
2679 p = fix_fname(alist_name(&ARGLIST[argn]));
2680 other = otherfile(p);
2681 vim_free(p);
2682 }
2683 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002684 && check_changed(curbuf, CCGD_AW
2685 | (other ? 0 : CCGD_MULTWIN)
2686 | (eap->forceit ? CCGD_FORCEIT : 0)
2687 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688 return;
2689 }
2690
2691 curwin->w_arg_idx = argn;
2692 if (argn == ARGCOUNT - 1
2693#ifdef FEAT_WINDOWS
2694 && curwin->w_alist == &global_alist
2695#endif
2696 )
2697 arg_had_last = TRUE;
2698
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002699 /* Edit the file; always use the last known line number.
2700 * When it fails (e.g. Abort for already edited file) restore the
2701 * argument index. */
2702 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002704 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2705 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002706 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002708 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709 setmark('\'');
2710 }
2711}
2712
2713/*
2714 * ":next", and commands that behave like it.
2715 */
2716 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002717ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718{
2719 int i;
2720
2721 /*
2722 * check for changed buffer now, if this fails the argument list is not
2723 * redefined.
2724 */
2725 if ( P_HID(curbuf)
2726 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002727 || !check_changed(curbuf, CCGD_AW
2728 | (eap->forceit ? CCGD_FORCEIT : 0)
2729 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730 {
2731 if (*eap->arg != NUL) /* redefine file list */
2732 {
2733 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2734 return;
2735 i = 0;
2736 }
2737 else
2738 i = curwin->w_arg_idx + (int)eap->line2;
2739 do_argfile(eap, i);
2740 }
2741}
2742
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002743#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744/*
2745 * ":argedit"
2746 */
2747 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002748ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002749{
2750 int fnum;
2751 int i;
2752 char_u *s;
2753
2754 /* Add the argument to the buffer list and get the buffer number. */
2755 fnum = buflist_add(eap->arg, BLN_LISTED);
2756
2757 /* Check if this argument is already in the argument list. */
2758 for (i = 0; i < ARGCOUNT; ++i)
2759 if (ARGLIST[i].ae_fnum == fnum)
2760 break;
2761 if (i == ARGCOUNT)
2762 {
2763 /* Can't find it, add it to the argument list. */
2764 s = vim_strsave(eap->arg);
2765 if (s == NULL)
2766 return;
2767 i = alist_add_list(1, &s,
2768 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2769 if (i < 0)
2770 return;
2771 curwin->w_arg_idx = i;
2772 }
2773
2774 alist_check_arg_idx();
2775
2776 /* Edit the argument. */
2777 do_argfile(eap, i);
2778}
2779
2780/*
2781 * ":argadd"
2782 */
2783 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002784ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785{
2786 do_arglist(eap->arg, AL_ADD,
2787 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2788#ifdef FEAT_TITLE
2789 maketitle();
2790#endif
2791}
2792
2793/*
2794 * ":argdelete"
2795 */
2796 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002797ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798{
2799 int i;
2800 int n;
2801
2802 if (eap->addr_count > 0)
2803 {
2804 /* ":1,4argdel": Delete all arguments in the range. */
2805 if (eap->line2 > ARGCOUNT)
2806 eap->line2 = ARGCOUNT;
2807 n = eap->line2 - eap->line1 + 1;
2808 if (*eap->arg != NUL || n <= 0)
2809 EMSG(_(e_invarg));
2810 else
2811 {
2812 for (i = eap->line1; i <= eap->line2; ++i)
2813 vim_free(ARGLIST[i - 1].ae_fname);
2814 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2815 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2816 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817 if (curwin->w_arg_idx >= eap->line2)
2818 curwin->w_arg_idx -= n;
2819 else if (curwin->w_arg_idx > eap->line1)
2820 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002821 if (ARGCOUNT == 0)
2822 curwin->w_arg_idx = 0;
2823 else if (curwin->w_arg_idx >= ARGCOUNT)
2824 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825 }
2826 }
2827 else if (*eap->arg == NUL)
2828 EMSG(_(e_argreq));
2829 else
2830 do_arglist(eap->arg, AL_DEL, 0);
2831#ifdef FEAT_TITLE
2832 maketitle();
2833#endif
2834}
2835
2836/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002837 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002838 */
2839 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002840ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841{
2842 int i;
2843#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002844 win_T *wp;
2845 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002846#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002847 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848 int next_fnum = 0;
2849#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2850 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002852 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002853#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002854 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002855 int qf_idx;
2856#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857
2858#ifndef FEAT_WINDOWS
2859 if (eap->cmdidx == CMD_windo)
2860 {
2861 ex_ni(eap);
2862 return;
2863 }
2864#endif
2865
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002866#ifndef FEAT_QUICKFIX
2867 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2868 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2869 {
2870 ex_ni(eap);
2871 return;
2872 }
2873#endif
2874
Bram Moolenaar071d4272004-06-13 20:20:40 +00002875#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002876 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002877 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2878 * great speed improvement. */
2879 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002880#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002881#ifdef FEAT_CLIPBOARD
2882 start_global_changes();
2883#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884
2885 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002886 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002888 || !check_changed(curbuf, CCGD_AW
2889 | (eap->forceit ? CCGD_FORCEIT : 0)
2890 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002893 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002895 wp = firstwin;
2896 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002898 switch (eap->cmdidx)
2899 {
2900#ifdef FEAT_WINDOWS
2901 case CMD_windo:
2902 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2903 i++;
2904 break;
2905 case CMD_tabdo:
2906 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2907 i++;
2908 break;
2909#endif
2910 case CMD_argdo:
2911 i = eap->line1 - 1;
2912 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002913 default:
2914 break;
2915 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916 /* set pcmark now */
2917 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002918 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002919 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002920 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002921 || !buf->b_p_bl); buf = buf->b_next)
2922 if (buf->b_fnum > eap->line2)
2923 {
2924 buf = NULL;
2925 break;
2926 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002927 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002928 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002929 }
2930#ifdef FEAT_QUICKFIX
2931 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2932 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2933 {
2934 qf_size = qf_get_size(eap);
2935 if (qf_size <= 0 || eap->line1 > qf_size)
2936 buf = NULL;
2937 else
2938 {
2939 ex_cc(eap);
2940
2941 buf = curbuf;
2942 i = eap->line1 - 1;
2943 if (eap->addr_count <= 0)
2944 /* default is all the quickfix/location list entries */
2945 eap->line2 = qf_size;
2946 }
2947 }
2948#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002949 else
2950 setpcmark();
2951 listcmd_busy = TRUE; /* avoids setting pcmark below */
2952
Bram Moolenaare25bb902015-02-27 20:33:37 +01002953 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954 {
2955 if (eap->cmdidx == CMD_argdo)
2956 {
2957 /* go to argument "i" */
2958 if (i == ARGCOUNT)
2959 break;
2960 /* Don't call do_argfile() when already there, it will try
2961 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002962 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002963 {
2964 /* Clear 'shm' to avoid that the file message overwrites
2965 * any output from the command. */
2966 p_shm_save = vim_strsave(p_shm);
2967 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002968 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002969 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2970 vim_free(p_shm_save);
2971 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002972 if (curwin->w_arg_idx != i)
2973 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002974 }
2975#ifdef FEAT_WINDOWS
2976 else if (eap->cmdidx == CMD_windo)
2977 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002978 /* go to window "wp" */
2979 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002980 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002981 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002982 if (curwin != wp)
2983 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002984 wp = curwin->w_next;
2985 }
2986 else if (eap->cmdidx == CMD_tabdo)
2987 {
2988 /* go to window "tp" */
2989 if (!valid_tabpage(tp))
2990 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002991 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002992 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002993 }
2994#endif
2995 else if (eap->cmdidx == CMD_bufdo)
2996 {
2997 /* Remember the number of the next listed buffer, in case
2998 * ":bwipe" is used or autocommands do something strange. */
2999 next_fnum = -1;
3000 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
3001 if (buf->b_p_bl)
3002 {
3003 next_fnum = buf->b_fnum;
3004 break;
3005 }
3006 }
3007
Bram Moolenaara162bc52015-01-07 16:54:21 +01003008 ++i;
3009
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010 /* execute the command */
3011 do_cmdline(eap->arg, eap->getline, eap->cookie,
3012 DOCMD_VERBOSE + DOCMD_NOWAIT);
3013
3014 if (eap->cmdidx == CMD_bufdo)
3015 {
3016 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01003017 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 break;
3019 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02003020 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021 if (buf->b_fnum == next_fnum)
3022 break;
3023 if (buf == NULL)
3024 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003025
3026 /* Go to the next buffer. Clear 'shm' to avoid that the file
3027 * message overwrites any output from the command. */
3028 p_shm_save = vim_strsave(p_shm);
3029 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003031 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3032 vim_free(p_shm_save);
3033
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003034 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035 if (curbuf->b_fnum != next_fnum)
3036 break;
3037 }
3038
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003039#ifdef FEAT_QUICKFIX
3040 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
3041 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3042 {
3043 if (i >= qf_size || i >= eap->line2)
3044 break;
3045
3046 qf_idx = qf_get_cur_idx(eap);
3047
3048 ex_cnext(eap);
3049
3050 /* If jumping to the next quickfix entry fails, quit here */
3051 if (qf_get_cur_idx(eap) == qf_idx)
3052 break;
3053 }
3054#endif
3055
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056 if (eap->cmdidx == CMD_windo)
3057 {
3058 validate_cursor(); /* cursor may have moved */
3059#ifdef FEAT_SCROLLBIND
3060 /* required when 'scrollbind' has been set */
3061 if (curwin->w_p_scb)
3062 do_check_scrollbind(TRUE);
3063#endif
3064 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01003065
3066#ifdef FEAT_WINDOWS
3067 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
3068 if (i+1 > eap->line2)
3069 break;
3070#endif
3071 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
3072 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073 }
3074 listcmd_busy = FALSE;
3075 }
3076
3077#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003078 if (save_ei != NULL)
3079 {
3080 au_event_restore(save_ei);
3081 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
3082 curbuf->b_fname, TRUE, curbuf);
3083 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02003085#ifdef FEAT_CLIPBOARD
3086 end_global_changes();
3087#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088}
3089
3090/*
3091 * Add files[count] to the arglist of the current window after arg "after".
3092 * The file names in files[count] must have been allocated and are taken over.
3093 * Files[] itself is not taken over.
3094 * Returns index of first added argument. Returns -1 when failed (out of mem).
3095 */
3096 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003097alist_add_list(
3098 int count,
3099 char_u **files,
3100 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101{
3102 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003103 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003104
3105 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
3106 {
3107 if (after < 0)
3108 after = 0;
3109 if (after > ARGCOUNT)
3110 after = ARGCOUNT;
3111 if (after < ARGCOUNT)
3112 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
3113 (ARGCOUNT - after) * sizeof(aentry_T));
3114 for (i = 0; i < count; ++i)
3115 {
3116 ARGLIST[after + i].ae_fname = files[i];
3117 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
3118 }
3119 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003120 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3121 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003122 return after;
3123 }
3124
3125 for (i = 0; i < count; ++i)
3126 vim_free(files[i]);
3127 return -1;
3128}
3129
3130#endif /* FEAT_LISTCMDS */
3131
3132#ifdef FEAT_EVAL
3133/*
3134 * ":compiler[!] {name}"
3135 */
3136 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003137ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138{
3139 char_u *buf;
3140 char_u *old_cur_comp = NULL;
3141 char_u *p;
3142
3143 if (*eap->arg == NUL)
3144 {
3145 /* List all compiler scripts. */
3146 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3147 /* ) keep the indenter happy... */
3148 }
3149 else
3150 {
3151 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3152 if (buf != NULL)
3153 {
3154 if (eap->forceit)
3155 {
3156 /* ":compiler! {name}" sets global options */
3157 do_cmdline_cmd((char_u *)
3158 "command -nargs=* CompilerSet set <args>");
3159 }
3160 else
3161 {
3162 /* ":compiler! {name}" sets local options.
3163 * To remain backwards compatible "current_compiler" is always
3164 * used. A user's compiler plugin may set it, the distributed
3165 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003166 * "b:current_compiler" and restore "current_compiler".
3167 * Explicitly prepend "g:" to make it work in a function. */
3168 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003169 if (old_cur_comp != NULL)
3170 old_cur_comp = vim_strsave(old_cur_comp);
3171 do_cmdline_cmd((char_u *)
3172 "command -nargs=* CompilerSet setlocal <args>");
3173 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003174 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003175 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176
3177 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003178 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3180 vim_free(buf);
3181
3182 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3183
3184 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003185 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 if (p != NULL)
3187 set_internal_string_var((char_u *)"b:current_compiler", p);
3188
3189 /* Restore "current_compiler" for ":compiler {name}". */
3190 if (!eap->forceit)
3191 {
3192 if (old_cur_comp != NULL)
3193 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003194 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003195 old_cur_comp);
3196 vim_free(old_cur_comp);
3197 }
3198 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003199 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003200 }
3201 }
3202 }
3203}
3204#endif
3205
3206/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003207 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208 */
3209 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003210ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003212 char_u *arg = eap->arg;
3213 char_u *p = skiptowhite(arg);
3214 int len = (int)(p - arg);
3215 int flags = eap->forceit ? DIP_ALL : 0;
3216
3217 if (STRNCMP(arg, "START", len) == 0)
3218 {
3219 flags += DIP_START + DIP_NORTP;
3220 arg = skipwhite(arg + len);
3221 }
3222 else if (STRNCMP(arg, "OPT", len) == 0)
3223 {
3224 flags += DIP_OPT + DIP_NORTP;
3225 arg = skipwhite(arg + len);
3226 }
3227 else if (STRNCMP(arg, "PACK", len) == 0)
3228 {
3229 flags += DIP_START + DIP_OPT + DIP_NORTP;
3230 arg = skipwhite(arg + len);
3231 }
3232 else if (STRNCMP(arg, "ALL", len) == 0)
3233 {
3234 flags += DIP_START + DIP_OPT;
3235 arg = skipwhite(arg + len);
3236 }
3237
3238 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003239}
3240
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003242source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003243{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003244 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245}
3246
3247/*
3248 * Source the file "name" from all directories in 'runtimepath'.
3249 * "name" can contain wildcards.
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003250 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
Bram Moolenaar91715872016-03-03 17:13:03 +01003251 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003252 * return FAIL when no file could be sourced, OK otherwise.
3253 */
3254 int
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003255source_runtime(char_u *name, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256{
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003257 return do_in_runtimepath(name, flags, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258}
3259
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003260/*
3261 * Find the file "name" in all directories in "path" and invoke
3262 * "callback(fname, cookie)".
3263 * "name" can contain wildcards.
3264 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3265 * When "flags" has DIP_DIR: find directories instead of files.
3266 * When "flags" has DIP_ERR: give an error message if there is no match.
3267 *
3268 * return FAIL when no file could be sourced, OK otherwise.
3269 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003270 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003271do_in_path(
3272 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003273 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003274 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003275 void (*callback)(char_u *fname, void *ck),
3276 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003277{
3278 char_u *rtp;
3279 char_u *np;
3280 char_u *buf;
3281 char_u *rtp_copy;
3282 char_u *tail;
3283 int num_files;
3284 char_u **files;
3285 int i;
3286 int did_one = FALSE;
3287#ifdef AMIGA
3288 struct Process *proc = (struct Process *)FindTask(0L);
3289 APTR save_winptr = proc->pr_WindowPtr;
3290
3291 /* Avoid a requester here for a volume that doesn't exist. */
3292 proc->pr_WindowPtr = (APTR)-1L;
3293#endif
3294
3295 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3296 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003297 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298 buf = alloc(MAXPATHL);
3299 if (buf != NULL && rtp_copy != NULL)
3300 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003301 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003302 {
3303 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003304 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003305 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003306 verbose_leave();
3307 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003308
Bram Moolenaar071d4272004-06-13 20:20:40 +00003309 /* Loop over all entries in 'runtimepath'. */
3310 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003311 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02003313 size_t buflen;
3314
Bram Moolenaar071d4272004-06-13 20:20:40 +00003315 /* Copy the path from 'runtimepath' to buf[]. */
3316 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02003317 buflen = STRLEN(buf);
3318
3319 /* Skip after or non-after directories. */
3320 if (flags & (DIP_NOAFTER | DIP_AFTER))
3321 {
3322 int is_after = buflen >= 5
3323 && STRCMP(buf + buflen - 5, "after") == 0;
3324
3325 if ((is_after && (flags & DIP_NOAFTER))
3326 || (!is_after && (flags & DIP_AFTER)))
3327 continue;
3328 }
3329
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003330 if (name == NULL)
3331 {
3332 (*callback)(buf, (void *) &cookie);
3333 if (!did_one)
3334 did_one = (cookie == NULL);
3335 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02003336 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 {
3338 add_pathsep(buf);
3339 tail = buf + STRLEN(buf);
3340
3341 /* Loop over all patterns in "name" */
3342 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003343 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344 {
3345 /* Append the pattern from "name" to buf[]. */
3346 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3347 "\t ");
3348
3349 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003350 {
3351 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003352 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003353 verbose_leave();
3354 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003355
3356 /* Expand wildcards, invoke the callback for each match. */
3357 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003358 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003359 {
3360 for (i = 0; i < num_files; ++i)
3361 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003362 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003364 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003365 break;
3366 }
3367 FreeWild(num_files, files);
3368 }
3369 }
3370 }
3371 }
3372 }
3373 vim_free(buf);
3374 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003375 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003376 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003377 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3378
3379 if (flags & DIP_ERR)
3380 EMSG3(_(e_dirnotf), basepath, name);
3381 else if (p_verbose > 0)
3382 {
3383 verbose_enter();
3384 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3385 verbose_leave();
3386 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003387 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003388
3389#ifdef AMIGA
3390 proc->pr_WindowPtr = save_winptr;
3391#endif
3392
3393 return did_one ? OK : FAIL;
3394}
3395
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003396/*
3397 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3398 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003399 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3400 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003401 * Returns OK when at least one match found, FAIL otherwise.
3402 *
3403 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3404 * passed by reference in this case, setting it to NULL indicates that callback
3405 * has done its job.
3406 */
3407 int
3408do_in_runtimepath(
3409 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003410 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003411 void (*callback)(char_u *fname, void *ck),
3412 void *cookie)
3413{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003414 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003415 char_u *s;
3416 int len;
3417 char *start_dir = "pack/*/start/*/%s";
3418 char *opt_dir = "pack/*/opt/*/%s";
3419
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003420 if ((flags & DIP_NORTP) == 0)
3421 done = do_in_path(p_rtp, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003422
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003423 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003424 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003425 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003426 s = alloc(len);
3427 if (s == NULL)
3428 return FAIL;
3429 vim_snprintf((char *)s, len, start_dir, name);
3430 done = do_in_path(p_pp, s, flags, callback, cookie);
3431 vim_free(s);
3432 }
3433
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003434 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003435 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003436 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003437 s = alloc(len);
3438 if (s == NULL)
3439 return FAIL;
3440 vim_snprintf((char *)s, len, opt_dir, name);
3441 done = do_in_path(p_pp, s, flags, callback, cookie);
3442 vim_free(s);
3443 }
3444
3445 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003446}
3447
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003448/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003449 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003450 */
3451 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003452source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003453{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003454 int num_files;
3455 char_u **files;
3456 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003457
Bram Moolenaarf3654822016-03-04 22:12:23 +01003458 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003459 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003460 for (i = 0; i < num_files; ++i)
3461 (void)do_source(files[i], FALSE, DOSO_NONE);
3462 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003463 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003464}
3465
Bram Moolenaar49b27322016-04-05 21:13:00 +02003466/* used for "cookie" of add_pack_plugin() */
3467static int APP_ADD_DIR;
3468static int APP_LOAD;
3469static int APP_BOTH;
3470
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003471 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003472add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003473{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003474 char_u *p4, *p3, *p2, *p1, *p;
3475 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003476 int c;
3477 char_u *new_rtp;
3478 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003479 size_t oldlen;
3480 size_t addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003481 char_u *afterdir;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003482 size_t afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003483 char_u *ffname = fix_fname(fname);
Bram Moolenaarfef524b2016-07-02 22:07:22 +02003484 size_t fname_len;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003485
Bram Moolenaar91715872016-03-03 17:13:03 +01003486 if (ffname == NULL)
3487 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003488 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003489 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003490 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003491 p4 = p3 = p2 = p1 = get_past_head(ffname);
3492 for (p = p1; *p; mb_ptr_adv(p))
3493 if (vim_ispathsep_nocolon(*p))
3494 {
3495 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3496 }
3497
3498 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003499 * rtp/pack/name/start/name
3500 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003501 *
3502 * find the part up to "pack" in 'runtimepath' */
3503 c = *p4;
3504 *p4 = NUL;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003505
3506 /* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3507 fname_len = STRLEN(ffname);
3508 insp = p_rtp;
3509 for (;;)
3510 {
3511 if (vim_fnamencmp(insp, ffname, fname_len) == 0)
3512 break;
3513 insp = vim_strchr(insp, ',');
3514 if (insp == NULL)
3515 break;
3516 ++insp;
3517 }
3518
Bram Moolenaarf3654822016-03-04 22:12:23 +01003519 if (insp == NULL)
3520 /* not found, append at the end */
3521 insp = p_rtp + STRLEN(p_rtp);
3522 else
3523 {
3524 /* append after the matching directory. */
3525 insp += STRLEN(ffname);
3526 while (*insp != NUL && *insp != ',')
3527 ++insp;
3528 }
3529 *p4 = c;
3530
Bram Moolenaara5702442016-05-24 19:37:29 +02003531 /* check if rtp/pack/name/start/name/after exists */
3532 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3533 if (afterdir != NULL && mch_isdir(afterdir))
3534 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3535
Bram Moolenaarb0550662016-05-31 21:37:36 +02003536 oldlen = STRLEN(p_rtp);
3537 addlen = STRLEN(ffname) + 1; /* add one for comma */
3538 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003539 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003540 goto theend;
3541 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003542 mch_memmove(new_rtp, p_rtp, keep);
3543 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003544 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003545 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003546 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003547 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003548 if (afterlen > 0)
3549 {
3550 STRCAT(new_rtp, ",");
3551 STRCAT(new_rtp, afterdir);
3552 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003553 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3554 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003555 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003556 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003557
Bram Moolenaar49b27322016-04-05 21:13:00 +02003558 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003559 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003560 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003561 static char *ftpat = "%s/ftdetect/*.vim";
3562 int len;
3563 char_u *pat;
3564
3565 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3566 pat = alloc(len);
3567 if (pat == NULL)
3568 goto theend;
3569 vim_snprintf((char *)pat, len, plugpat, ffname);
3570 source_all_matches(pat);
3571
3572#ifdef FEAT_AUTOCMD
3573 {
3574 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3575
3576 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3577 * found when it loads. */
3578 if (cmd != NULL && eval_to_number(cmd) > 0)
3579 {
3580 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3581 vim_snprintf((char *)pat, len, ftpat, ffname);
3582 source_all_matches(pat);
3583 do_cmdline_cmd((char_u *)"augroup END");
3584 }
3585 vim_free(cmd);
3586 }
3587#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003588 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003589 }
3590
3591theend:
3592 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003593}
3594
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003595static int did_source_packages = FALSE;
3596
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003597/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003598 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003599 * Find plugins in the package directories and source them.
Bram Moolenaar66459b72016-08-06 19:01:55 +02003600 * "eap" is NULL when invoked during startup.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003601 */
3602 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003603ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003604{
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003605 if (!did_source_packages || (eap != NULL && eap->forceit))
3606 {
3607 did_source_packages = TRUE;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003608
3609 /* First do a round to add all directories to 'runtimepath', then load
3610 * the plugins. This allows for plugins to use an autoload directory
3611 * of another plugin. */
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003612 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003613 add_pack_plugin, &APP_ADD_DIR);
3614 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3615 add_pack_plugin, &APP_LOAD);
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003616 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003617}
3618
3619/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003620 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003621 */
3622 void
3623ex_packadd(exarg_T *eap)
3624{
3625 static char *plugpat = "pack/*/opt/%s";
3626 int len;
3627 char *pat;
3628
3629 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3630 pat = (char *)alloc(len);
3631 if (pat == NULL)
3632 return;
3633 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003634 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003635 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003636 vim_free(pat);
3637}
3638
Bram Moolenaar071d4272004-06-13 20:20:40 +00003639#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3640/*
3641 * ":options"
3642 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003643 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003644ex_options(
3645 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646{
3647 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3648}
3649#endif
3650
3651/*
3652 * ":source {fname}"
3653 */
3654 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003655ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003656{
3657#ifdef FEAT_BROWSE
3658 if (cmdmod.browse)
3659 {
3660 char_u *fname = NULL;
3661
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003662 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3664 if (fname != NULL)
3665 {
3666 cmd_source(fname, eap);
3667 vim_free(fname);
3668 }
3669 }
3670 else
3671#endif
3672 cmd_source(eap->arg, eap);
3673}
3674
3675 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003676cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677{
3678 if (*fname == NUL)
3679 EMSG(_(e_argreq));
3680
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003682 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003683 * Need to execute the commands directly. This is required at least
3684 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685 * - ":g" command busy
3686 * - after ":argdo", ":windo" or ":bufdo"
3687 * - another command follows
3688 * - inside a loop
3689 */
3690 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3691#ifdef FEAT_EVAL
3692 || eap->cstack->cs_idx >= 0
3693#endif
3694 );
3695
3696 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003697 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003698 EMSG2(_(e_notopen), fname);
3699}
3700
3701/*
3702 * ":source" and associated commands.
3703 */
3704/*
3705 * Structure used to store info for each sourced file.
3706 * It is shared between do_source() and getsourceline().
3707 * This is required, because it needs to be handed to do_cmdline() and
3708 * sourcing can be done recursively.
3709 */
3710struct source_cookie
3711{
3712 FILE *fp; /* opened file for sourcing */
3713 char_u *nextline; /* if not NULL: line that was read ahead */
3714 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003715#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3717 int error; /* TRUE if LF found after CR-LF */
3718#endif
3719#ifdef FEAT_EVAL
3720 linenr_T breakpoint; /* next line with breakpoint or zero */
3721 char_u *fname; /* name of sourced file */
3722 int dbg_tick; /* debug_tick when breakpoint was set */
3723 int level; /* top nesting level of sourced file */
3724#endif
3725#ifdef FEAT_MBYTE
3726 vimconv_T conv; /* type of conversion */
3727#endif
3728};
3729
3730#ifdef FEAT_EVAL
3731/*
3732 * Return the address holding the next breakpoint line for a source cookie.
3733 */
3734 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003735source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736{
3737 return &((struct source_cookie *)cookie)->breakpoint;
3738}
3739
3740/*
3741 * Return the address holding the debug tick for a source cookie.
3742 */
3743 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003744source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745{
3746 return &((struct source_cookie *)cookie)->dbg_tick;
3747}
3748
3749/*
3750 * Return the nesting level for a source cookie.
3751 */
3752 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003753source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754{
3755 return ((struct source_cookie *)cookie)->level;
3756}
3757#endif
3758
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003759static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003760
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003761#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3762# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003763static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003764
3765/*
3766 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003767 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003768 */
3769 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003770fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003772# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003773 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3774# else
3775 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003776# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777
3778 if (fd_tmp == -1)
3779 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003780
3781# ifdef HAVE_FD_CLOEXEC
3782 {
3783 int fdflags = fcntl(fd_tmp, F_GETFD);
3784 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003785 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003786 }
3787# endif
3788
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 return fdopen(fd_tmp, READBIN);
3790}
3791#endif
3792
3793
3794/*
3795 * do_source: Read the file "fname" and execute its lines as EX commands.
3796 *
3797 * This function may be called recursively!
3798 *
3799 * return FAIL if file could not be opened, OK otherwise
3800 */
3801 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003802do_source(
3803 char_u *fname,
3804 int check_other, /* check for .vimrc and _vimrc */
3805 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003806{
3807 struct source_cookie cookie;
3808 char_u *save_sourcing_name;
3809 linenr_T save_sourcing_lnum;
3810 char_u *p;
3811 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003812 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813 int retval = FAIL;
3814#ifdef FEAT_EVAL
3815 scid_T save_current_SID;
3816 static scid_T last_current_SID = 0;
3817 void *save_funccalp;
3818 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003819 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003821 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822 int stat_ok;
3823# endif
3824#endif
3825#ifdef STARTUPTIME
3826 struct timeval tv_rel;
3827 struct timeval tv_start;
3828#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003829#ifdef FEAT_PROFILE
3830 proftime_T wait_start;
3831#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832
Bram Moolenaar071d4272004-06-13 20:20:40 +00003833 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003834 if (p == NULL)
3835 return retval;
3836 fname_exp = fix_fname(p);
3837 vim_free(p);
3838 if (fname_exp == NULL)
3839 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003840 if (mch_isdir(fname_exp))
3841 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003842 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003843 goto theend;
3844 }
3845
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003846#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003847 /* Apply SourceCmd autocommands, they should get the file and source it. */
3848 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3849 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3850 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003851 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003852# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003853 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003854# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003855 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003856# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003857 goto theend;
3858 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003859
3860 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003861 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3862#endif
3863
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003864#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003865 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3866#else
3867 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3868#endif
3869 if (cookie.fp == NULL && check_other)
3870 {
3871 /*
3872 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3873 * and ".exrc" by "_exrc" or vice versa.
3874 */
3875 p = gettail(fname_exp);
3876 if ((*p == '.' || *p == '_')
3877 && (STRICMP(p + 1, "vimrc") == 0
3878 || STRICMP(p + 1, "gvimrc") == 0
3879 || STRICMP(p + 1, "exrc") == 0))
3880 {
3881 if (*p == '_')
3882 *p = '.';
3883 else
3884 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003885#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003886 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3887#else
3888 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3889#endif
3890 }
3891 }
3892
3893 if (cookie.fp == NULL)
3894 {
3895 if (p_verbose > 0)
3896 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003897 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003899 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900 else
3901 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003902 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003903 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003904 }
3905 goto theend;
3906 }
3907
3908 /*
3909 * The file exists.
3910 * - In verbose mode, give a message.
3911 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3912 */
3913 if (p_verbose > 1)
3914 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003915 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003916 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003917 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003918 else
3919 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003920 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003921 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003922 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003923 if (is_vimrc == DOSO_VIMRC)
3924 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3925 else if (is_vimrc == DOSO_GVIMRC)
3926 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927
3928#ifdef USE_CRNL
3929 /* If no automatic file format: Set default to CR-NL. */
3930 if (*p_ffs == NUL)
3931 cookie.fileformat = EOL_DOS;
3932 else
3933 cookie.fileformat = EOL_UNKNOWN;
3934 cookie.error = FALSE;
3935#endif
3936
3937#ifdef USE_CR
3938 /* If no automatic file format: Set default to CR. */
3939 if (*p_ffs == NUL)
3940 cookie.fileformat = EOL_MAC;
3941 else
3942 cookie.fileformat = EOL_UNKNOWN;
3943 cookie.error = FALSE;
3944#endif
3945
3946 cookie.nextline = NULL;
3947 cookie.finished = FALSE;
3948
3949#ifdef FEAT_EVAL
3950 /*
3951 * Check if this script has a breakpoint.
3952 */
3953 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3954 cookie.fname = fname_exp;
3955 cookie.dbg_tick = debug_tick;
3956
3957 cookie.level = ex_nesting_level;
3958#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003959
3960 /*
3961 * Keep the sourcing name/lnum, for recursive calls.
3962 */
3963 save_sourcing_name = sourcing_name;
3964 sourcing_name = fname_exp;
3965 save_sourcing_lnum = sourcing_lnum;
3966 sourcing_lnum = 0;
3967
Bram Moolenaar73881402009-02-04 16:50:47 +00003968#ifdef FEAT_MBYTE
3969 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3970
3971 /* Read the first line so we can check for a UTF-8 BOM. */
3972 firstline = getsourceline(0, (void *)&cookie, 0);
3973 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3974 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3975 {
3976 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3977 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3978 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003979 if (p == NULL)
3980 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003981 if (p != NULL)
3982 {
3983 vim_free(firstline);
3984 firstline = p;
3985 }
3986 }
3987#endif
3988
Bram Moolenaar071d4272004-06-13 20:20:40 +00003989#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003990 if (time_fd != NULL)
3991 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003992#endif
3993
3994#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003995# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003996 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003997 prof_child_enter(&wait_start); /* entering a child now */
3998# endif
3999
4000 /* Don't use local function variables, if called from a function.
4001 * Also starts profiling timer for nested script. */
4002 save_funccalp = save_funccal();
4003
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004 /*
4005 * Check if this script was sourced before to finds its SID.
4006 * If it's new, generate a new SID.
4007 */
4008 save_current_SID = current_SID;
4009# ifdef UNIX
4010 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
4011# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004012 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
4013 {
4014 si = &SCRIPT_ITEM(current_SID);
4015 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 && (
4017# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00004018 /* Compare dev/ino when possible, it catches symbolic
4019 * links. Also compare file names, the inode may change
4020 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004021 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004022 && (si->sn_dev == st.st_dev
4023 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004025 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004026 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004027 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028 if (current_SID == 0)
4029 {
4030 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004031 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
4032 == FAIL)
4033 goto almosttheend;
4034 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004035 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00004036 ++script_items.ga_len;
4037 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
4038# ifdef FEAT_PROFILE
4039 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004041 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004042 si = &SCRIPT_ITEM(current_SID);
4043 si->sn_name = fname_exp;
4044 fname_exp = NULL;
4045# ifdef UNIX
4046 if (stat_ok)
4047 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004048 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004049 si->sn_dev = st.st_dev;
4050 si->sn_ino = st.st_ino;
4051 }
4052 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004053 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004054# endif
4055
Bram Moolenaar071d4272004-06-13 20:20:40 +00004056 /* Allocate the local script variables to use for this script. */
4057 new_script_vars(current_SID);
4058 }
4059
Bram Moolenaar05159a02005-02-26 23:04:13 +00004060# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004061 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004062 {
4063 int forceit;
4064
4065 /* Check if we do profiling for this script. */
4066 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
4067 {
4068 script_do_profile(si);
4069 si->sn_pr_force = forceit;
4070 }
4071 if (si->sn_prof_on)
4072 {
4073 ++si->sn_pr_count;
4074 profile_start(&si->sn_pr_start);
4075 profile_zero(&si->sn_pr_children);
4076 }
4077 }
4078# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004079#endif
4080
4081 /*
4082 * Call do_cmdline, which will call getsourceline() to get the lines.
4083 */
Bram Moolenaar73881402009-02-04 16:50:47 +00004084 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004086 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004087
4088#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004089 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004090 {
4091 /* Get "si" again, "script_items" may have been reallocated. */
4092 si = &SCRIPT_ITEM(current_SID);
4093 if (si->sn_prof_on)
4094 {
4095 profile_end(&si->sn_pr_start);
4096 profile_sub_wait(&wait_start, &si->sn_pr_start);
4097 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004098 profile_self(&si->sn_pr_self, &si->sn_pr_start,
4099 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004100 }
4101 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004102#endif
4103
4104 if (got_int)
4105 EMSG(_(e_interr));
4106 sourcing_name = save_sourcing_name;
4107 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 if (p_verbose > 1)
4109 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004110 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00004111 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004113 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004114 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115 }
4116#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004117 if (time_fd != NULL)
4118 {
4119 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
4120 time_msg((char *)IObuff, &tv_start);
4121 time_pop(&tv_rel);
4122 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123#endif
4124
4125#ifdef FEAT_EVAL
4126 /*
4127 * After a "finish" in debug mode, need to break at first command of next
4128 * sourced file.
4129 */
4130 if (save_debug_break_level > ex_nesting_level
4131 && debug_break_level == ex_nesting_level)
4132 ++debug_break_level;
4133#endif
4134
Bram Moolenaar05159a02005-02-26 23:04:13 +00004135#ifdef FEAT_EVAL
4136almosttheend:
4137 current_SID = save_current_SID;
4138 restore_funccal(save_funccalp);
4139# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004140 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004141 prof_child_exit(&wait_start); /* leaving a child now */
4142# endif
4143#endif
4144 fclose(cookie.fp);
4145 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004146 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004147#ifdef FEAT_MBYTE
4148 convert_setup(&cookie.conv, NULL, NULL);
4149#endif
4150
Bram Moolenaar071d4272004-06-13 20:20:40 +00004151theend:
4152 vim_free(fname_exp);
4153 return retval;
4154}
4155
4156#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004157
Bram Moolenaar071d4272004-06-13 20:20:40 +00004158/*
4159 * ":scriptnames"
4160 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004162ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163{
4164 int i;
4165
Bram Moolenaar05159a02005-02-26 23:04:13 +00004166 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4167 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004168 {
4169 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4170 NameBuff, MAXPATHL, TRUE);
4171 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004172 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004173}
4174
4175# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4176/*
4177 * Fix slashes in the list of script names for 'shellslash'.
4178 */
4179 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004180scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181{
4182 int i;
4183
Bram Moolenaar05159a02005-02-26 23:04:13 +00004184 for (i = 1; i <= script_items.ga_len; ++i)
4185 if (SCRIPT_ITEM(i).sn_name != NULL)
4186 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187}
4188# endif
4189
4190/*
4191 * Get a pointer to a script name. Used for ":verbose set".
4192 */
4193 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004194get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004195{
4196 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004197 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004198 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004199 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004200 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004201 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004202 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004203 return (char_u *)_("environment variable");
4204 if (id == SID_ERROR)
4205 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004206 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004208
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004209# if defined(EXITFREE) || defined(PROTO)
4210 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004211free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004212{
4213 int i;
4214
4215 for (i = script_items.ga_len; i > 0; --i)
4216 vim_free(SCRIPT_ITEM(i).sn_name);
4217 ga_clear(&script_items);
4218}
4219# endif
4220
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221#endif
4222
4223#if defined(USE_CR) || defined(PROTO)
4224
4225# if defined(__MSL__) && (__MSL__ >= 22)
4226/*
4227 * Newer version of the Metrowerks library handle DOS and UNIX files
4228 * without help.
4229 * Test with earlier versions, MSL 2.2 is the library supplied with
4230 * Codewarrior Pro 2.
4231 */
4232 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004233fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004234{
4235 return fgets(s, n, stream);
4236}
4237# else
4238/*
4239 * Version of fgets() which also works for lines ending in a <CR> only
4240 * (Macintosh format).
4241 * For older versions of the Metrowerks library.
4242 * At least CodeWarrior 9 needed this code.
4243 */
4244 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004245fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004246{
4247 int c = 0;
4248 int char_read = 0;
4249
4250 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4251 {
4252 c = fgetc(stream);
4253 s[char_read++] = c;
4254 /* If the file is in DOS format, we need to skip a NL after a CR. I
4255 * thought it was the other way around, but this appears to work... */
4256 if (c == '\n')
4257 {
4258 c = fgetc(stream);
4259 if (c != '\r')
4260 ungetc(c, stream);
4261 }
4262 }
4263
4264 s[char_read] = 0;
4265 if (char_read == 0)
4266 return NULL;
4267
4268 if (feof(stream) && char_read == 1)
4269 return NULL;
4270
4271 return s;
4272}
4273# endif
4274#endif
4275
4276/*
4277 * Get one full line from a sourced file.
4278 * Called by do_cmdline() when it's called from do_source().
4279 *
4280 * Return a pointer to the line in allocated memory.
4281 * Return NULL for end-of-file or some error.
4282 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004283 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004284getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004285{
4286 struct source_cookie *sp = (struct source_cookie *)cookie;
4287 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004288 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289
4290#ifdef FEAT_EVAL
4291 /* If breakpoints have been added/deleted need to check for it. */
4292 if (sp->dbg_tick < debug_tick)
4293 {
4294 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4295 sp->dbg_tick = debug_tick;
4296 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004297# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004298 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004299 script_line_end();
4300# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301#endif
4302 /*
4303 * Get current line. If there is a read-ahead line, use it, otherwise get
4304 * one now.
4305 */
4306 if (sp->finished)
4307 line = NULL;
4308 else if (sp->nextline == NULL)
4309 line = get_one_sourceline(sp);
4310 else
4311 {
4312 line = sp->nextline;
4313 sp->nextline = NULL;
4314 ++sourcing_lnum;
4315 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004316#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004317 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004318 script_line_start();
4319#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320
4321 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4322 * contain the 'C' flag. */
4323 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4324 {
4325 /* compensate for the one line read-ahead */
4326 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004327
4328 /* Get the next line and concatenate it when it starts with a
4329 * backslash. We always need to read the next line, keep it in
4330 * sp->nextline. */
4331 sp->nextline = get_one_sourceline(sp);
4332 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004333 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004334 garray_T ga;
4335
Bram Moolenaarb549a732012-02-22 18:29:33 +01004336 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004337 ga_concat(&ga, line);
4338 ga_concat(&ga, p + 1);
4339 for (;;)
4340 {
4341 vim_free(sp->nextline);
4342 sp->nextline = get_one_sourceline(sp);
4343 if (sp->nextline == NULL)
4344 break;
4345 p = skipwhite(sp->nextline);
4346 if (*p != '\\')
4347 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004348 /* Adjust the growsize to the current length to speed up
4349 * concatenating many lines. */
4350 if (ga.ga_len > 400)
4351 {
4352 if (ga.ga_len > 8000)
4353 ga.ga_growsize = 8000;
4354 else
4355 ga.ga_growsize = ga.ga_len;
4356 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004357 ga_concat(&ga, p + 1);
4358 }
4359 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004361 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362 }
4363 }
4364
4365#ifdef FEAT_MBYTE
4366 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4367 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004368 char_u *s;
4369
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370 /* Convert the encoding of the script line. */
4371 s = string_convert(&sp->conv, line, NULL);
4372 if (s != NULL)
4373 {
4374 vim_free(line);
4375 line = s;
4376 }
4377 }
4378#endif
4379
4380#ifdef FEAT_EVAL
4381 /* Did we encounter a breakpoint? */
4382 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4383 {
4384 dbg_breakpoint(sp->fname, sourcing_lnum);
4385 /* Find next breakpoint. */
4386 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4387 sp->dbg_tick = debug_tick;
4388 }
4389#endif
4390
4391 return line;
4392}
4393
4394 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004395get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004396{
4397 garray_T ga;
4398 int len;
4399 int c;
4400 char_u *buf;
4401#ifdef USE_CRNL
4402 int has_cr; /* CR-LF found */
4403#endif
4404#ifdef USE_CR
4405 char_u *scan;
4406#endif
4407 int have_read = FALSE;
4408
4409 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004410 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411
4412 /*
4413 * Loop until there is a finished line (or end-of-file).
4414 */
4415 sourcing_lnum++;
4416 for (;;)
4417 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004418 /* make room to read at least 120 (more) characters */
4419 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004420 break;
4421 buf = (char_u *)ga.ga_data;
4422
4423#ifdef USE_CR
4424 if (sp->fileformat == EOL_MAC)
4425 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004426 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4427 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004428 break;
4429 }
4430 else
4431#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004432 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4433 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004435 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004436#ifdef USE_CRNL
4437 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4438 * CTRL-Z by its own, or after a NL. */
4439 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4440 && sp->fileformat == EOL_DOS
4441 && buf[len - 1] == Ctrl_Z)
4442 {
4443 buf[len - 1] = NUL;
4444 break;
4445 }
4446#endif
4447
4448#ifdef USE_CR
4449 /* If the read doesn't stop on a new line, and there's
4450 * some CR then we assume a Mac format */
4451 if (sp->fileformat == EOL_UNKNOWN)
4452 {
4453 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4454 sp->fileformat = EOL_MAC;
4455 else
4456 sp->fileformat = EOL_UNIX;
4457 }
4458
4459 if (sp->fileformat == EOL_MAC)
4460 {
4461 scan = vim_strchr(buf, '\r');
4462
4463 if (scan != NULL)
4464 {
4465 *scan = '\n';
4466 if (*(scan + 1) != 0)
4467 {
4468 *(scan + 1) = 0;
4469 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4470 }
4471 }
4472 len = STRLEN(buf);
4473 }
4474#endif
4475
4476 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004477 ga.ga_len = len;
4478
4479 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004480 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004481 continue;
4482
4483 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4484 {
4485#ifdef USE_CRNL
4486 has_cr = (len >= 2 && buf[len - 2] == '\r');
4487 if (sp->fileformat == EOL_UNKNOWN)
4488 {
4489 if (has_cr)
4490 sp->fileformat = EOL_DOS;
4491 else
4492 sp->fileformat = EOL_UNIX;
4493 }
4494
4495 if (sp->fileformat == EOL_DOS)
4496 {
4497 if (has_cr) /* replace trailing CR */
4498 {
4499 buf[len - 2] = '\n';
4500 --len;
4501 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004502 }
4503 else /* lines like ":map xx yy^M" will have failed */
4504 {
4505 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004506 {
4507 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004509 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004510 sp->error = TRUE;
4511 sp->fileformat = EOL_UNIX;
4512 }
4513 }
4514#endif
4515 /* The '\n' is escaped if there is an odd number of ^V's just
4516 * before it, first set "c" just before the 'V's and then check
4517 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4518 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4519 ;
4520 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4521 {
4522 sourcing_lnum++;
4523 continue;
4524 }
4525
4526 buf[len - 1] = NUL; /* remove the NL */
4527 }
4528
4529 /*
4530 * Check for ^C here now and then, so recursive :so can be broken.
4531 */
4532 line_breakcheck();
4533 break;
4534 }
4535
4536 if (have_read)
4537 return (char_u *)ga.ga_data;
4538
4539 vim_free(ga.ga_data);
4540 return NULL;
4541}
4542
Bram Moolenaar05159a02005-02-26 23:04:13 +00004543#if defined(FEAT_PROFILE) || defined(PROTO)
4544/*
4545 * Called when starting to read a script line.
4546 * "sourcing_lnum" must be correct!
4547 * When skipping lines it may not actually be executed, but we won't find out
4548 * until later and we need to store the time now.
4549 */
4550 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004551script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004552{
4553 scriptitem_T *si;
4554 sn_prl_T *pp;
4555
4556 if (current_SID <= 0 || current_SID > script_items.ga_len)
4557 return;
4558 si = &SCRIPT_ITEM(current_SID);
4559 if (si->sn_prof_on && sourcing_lnum >= 1)
4560 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004561 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004562 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004563 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004564 si->sn_prl_idx = sourcing_lnum - 1;
4565 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4566 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4567 {
4568 /* Zero counters for a line that was not used before. */
4569 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4570 pp->snp_count = 0;
4571 profile_zero(&pp->sn_prl_total);
4572 profile_zero(&pp->sn_prl_self);
4573 ++si->sn_prl_ga.ga_len;
4574 }
4575 si->sn_prl_execed = FALSE;
4576 profile_start(&si->sn_prl_start);
4577 profile_zero(&si->sn_prl_children);
4578 profile_get_wait(&si->sn_prl_wait);
4579 }
4580}
4581
4582/*
4583 * Called when actually executing a function line.
4584 */
4585 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004586script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004587{
4588 scriptitem_T *si;
4589
4590 if (current_SID <= 0 || current_SID > script_items.ga_len)
4591 return;
4592 si = &SCRIPT_ITEM(current_SID);
4593 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4594 si->sn_prl_execed = TRUE;
4595}
4596
4597/*
4598 * Called when done with a function line.
4599 */
4600 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004601script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004602{
4603 scriptitem_T *si;
4604 sn_prl_T *pp;
4605
4606 if (current_SID <= 0 || current_SID > script_items.ga_len)
4607 return;
4608 si = &SCRIPT_ITEM(current_SID);
4609 if (si->sn_prof_on && si->sn_prl_idx >= 0
4610 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4611 {
4612 if (si->sn_prl_execed)
4613 {
4614 pp = &PRL_ITEM(si, si->sn_prl_idx);
4615 ++pp->snp_count;
4616 profile_end(&si->sn_prl_start);
4617 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004618 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004619 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4620 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004621 }
4622 si->sn_prl_idx = -1;
4623 }
4624}
4625#endif
4626
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627/*
4628 * ":scriptencoding": Set encoding conversion for a sourced script.
4629 * Without the multi-byte feature it's simply ignored.
4630 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004632ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004633{
4634#ifdef FEAT_MBYTE
4635 struct source_cookie *sp;
4636 char_u *name;
4637
4638 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4639 {
4640 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4641 return;
4642 }
4643
4644 if (*eap->arg != NUL)
4645 {
4646 name = enc_canonize(eap->arg);
4647 if (name == NULL) /* out of memory */
4648 return;
4649 }
4650 else
4651 name = eap->arg;
4652
4653 /* Setup for conversion from the specified encoding to 'encoding'. */
4654 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4655 convert_setup(&sp->conv, name, p_enc);
4656
4657 if (name != eap->arg)
4658 vim_free(name);
4659#endif
4660}
4661
4662#if defined(FEAT_EVAL) || defined(PROTO)
4663/*
4664 * ":finish": Mark a sourced file as finished.
4665 */
4666 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004667ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004668{
4669 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4670 do_finish(eap, FALSE);
4671 else
4672 EMSG(_("E168: :finish used outside of a sourced file"));
4673}
4674
4675/*
4676 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4677 * Also called for a pending finish at the ":endtry" or after returning from
4678 * an extra do_cmdline(). "reanimate" is used in the latter case.
4679 */
4680 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004681do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004682{
4683 int idx;
4684
4685 if (reanimate)
4686 ((struct source_cookie *)getline_cookie(eap->getline,
4687 eap->cookie))->finished = FALSE;
4688
4689 /*
4690 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4691 * not in its finally clause (which then is to be executed next) is found.
4692 * In this case, make the ":finish" pending for execution at the ":endtry".
4693 * Otherwise, finish normally.
4694 */
4695 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4696 if (idx >= 0)
4697 {
4698 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4699 report_make_pending(CSTP_FINISH, NULL);
4700 }
4701 else
4702 ((struct source_cookie *)getline_cookie(eap->getline,
4703 eap->cookie))->finished = TRUE;
4704}
4705
4706
4707/*
4708 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4709 * message for missing ":endif".
4710 * Return FALSE when not sourcing a file.
4711 */
4712 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004713source_finished(
4714 char_u *(*fgetline)(int, void *, int),
4715 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004716{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004717 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004718 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004719 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004720}
4721#endif
4722
4723#if defined(FEAT_LISTCMDS) || defined(PROTO)
4724/*
4725 * ":checktime [buffer]"
4726 */
4727 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004728ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729{
4730 buf_T *buf;
4731 int save_no_check_timestamps = no_check_timestamps;
4732
4733 no_check_timestamps = 0;
4734 if (eap->addr_count == 0) /* default is all buffers */
4735 check_timestamps(FALSE);
4736 else
4737 {
4738 buf = buflist_findnr((int)eap->line2);
4739 if (buf != NULL) /* cannot happen? */
4740 (void)buf_check_timestamp(buf, FALSE);
4741 }
4742 no_check_timestamps = save_no_check_timestamps;
4743}
4744#endif
4745
Bram Moolenaar071d4272004-06-13 20:20:40 +00004746#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4747 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004748# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004749static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004751 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004752get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004753{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004754 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004755
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004756 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004757 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004758
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004759# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760 if (loc != NULL)
4761 {
4762 char_u *p;
4763
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004764 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4765 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004766 p = vim_strchr(loc, '=');
4767 if (p != NULL)
4768 {
4769 loc = ++p;
4770 while (*p != NUL) /* remove trailing newline */
4771 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004772 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004773 {
4774 *p = NUL;
4775 break;
4776 }
4777 ++p;
4778 }
4779 }
4780 }
4781# endif
4782
4783 return loc;
4784}
4785#endif
4786
4787
4788#ifdef WIN32
4789/*
4790 * On MS-Windows locale names are strings like "German_Germany.1252", but
4791 * gettext expects "de". Try to translate one into another here for a few
4792 * supported languages.
4793 */
4794 static char_u *
4795gettext_lang(char_u *name)
4796{
4797 int i;
4798 static char *(mtable[]) = {
4799 "afrikaans", "af",
4800 "czech", "cs",
4801 "dutch", "nl",
4802 "german", "de",
4803 "english_united kingdom", "en_GB",
4804 "spanish", "es",
4805 "french", "fr",
4806 "italian", "it",
4807 "japanese", "ja",
4808 "korean", "ko",
4809 "norwegian", "no",
4810 "polish", "pl",
4811 "russian", "ru",
4812 "slovak", "sk",
4813 "swedish", "sv",
4814 "ukrainian", "uk",
4815 "chinese_china", "zh_CN",
4816 "chinese_taiwan", "zh_TW",
4817 NULL};
4818
4819 for (i = 0; mtable[i] != NULL; i += 2)
4820 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004821 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004822 return name;
4823}
4824#endif
4825
4826#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4827/*
4828 * Obtain the current messages language. Used to set the default for
4829 * 'helplang'. May return NULL or an empty string.
4830 */
4831 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004832get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004833{
4834 char_u *p;
4835
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004836# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004838 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839# else
4840 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004841 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4842 * and LC_MONETARY may be set differently for a Japanese working in the
4843 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004844 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004845# endif
4846# else
4847 p = mch_getenv((char_u *)"LC_ALL");
4848 if (p == NULL || *p == NUL)
4849 {
4850 p = mch_getenv((char_u *)"LC_MESSAGES");
4851 if (p == NULL || *p == NUL)
4852 p = mch_getenv((char_u *)"LANG");
4853 }
4854# endif
4855# ifdef WIN32
4856 p = gettext_lang(p);
4857# endif
4858 return p;
4859}
4860#endif
4861
Bram Moolenaardef9e822004-12-31 20:58:58 +00004862/* Complicated #if; matches with where get_mess_env() is used below. */
4863#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4864 && defined(LC_MESSAGES))) \
4865 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4866 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4867 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004868static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004869
4870/*
4871 * Get the language used for messages from the environment.
4872 */
4873 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004874get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004875{
4876 char_u *p;
4877
4878 p = mch_getenv((char_u *)"LC_ALL");
4879 if (p == NULL || *p == NUL)
4880 {
4881 p = mch_getenv((char_u *)"LC_MESSAGES");
4882 if (p == NULL || *p == NUL)
4883 {
4884 p = mch_getenv((char_u *)"LANG");
4885 if (p != NULL && VIM_ISDIGIT(*p))
4886 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004887# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004888 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004889 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004890# endif
4891 }
4892 }
4893 return p;
4894}
4895#endif
4896
4897#if defined(FEAT_EVAL) || defined(PROTO)
4898
4899/*
4900 * Set the "v:lang" variable according to the current locale setting.
4901 * Also do "v:lc_time"and "v:ctype".
4902 */
4903 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004904set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905{
4906 char_u *loc;
4907
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004908# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004909 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004910# else
4911 /* setlocale() not supported: use the default value */
4912 loc = (char_u *)"C";
4913# endif
4914 set_vim_var_string(VV_CTYPE, loc, -1);
4915
4916 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4917 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004918# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004919 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004920# else
4921 loc = get_mess_env();
4922# endif
4923 set_vim_var_string(VV_LANG, loc, -1);
4924
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004925# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004926 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927# endif
4928 set_vim_var_string(VV_LC_TIME, loc, -1);
4929}
4930#endif
4931
4932#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4933 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4934/*
4935 * ":language": Set the language (locale).
4936 */
4937 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004938ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004939{
4940 char *loc;
4941 char_u *p;
4942 char_u *name;
4943 int what = LC_ALL;
4944 char *whatstr = "";
4945#ifdef LC_MESSAGES
4946# define VIM_LC_MESSAGES LC_MESSAGES
4947#else
4948# define VIM_LC_MESSAGES 6789
4949#endif
4950
4951 name = eap->arg;
4952
4953 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4954 * Allow abbreviation, but require at least 3 characters to avoid
4955 * confusion with a two letter language name "me" or "ct". */
4956 p = skiptowhite(eap->arg);
4957 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4958 {
4959 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4960 {
4961 what = VIM_LC_MESSAGES;
4962 name = skipwhite(p);
4963 whatstr = "messages ";
4964 }
4965 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4966 {
4967 what = LC_CTYPE;
4968 name = skipwhite(p);
4969 whatstr = "ctype ";
4970 }
4971 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4972 {
4973 what = LC_TIME;
4974 name = skipwhite(p);
4975 whatstr = "time ";
4976 }
4977 }
4978
4979 if (*name == NUL)
4980 {
4981#ifndef LC_MESSAGES
4982 if (what == VIM_LC_MESSAGES)
4983 p = get_mess_env();
4984 else
4985#endif
4986 p = (char_u *)setlocale(what, NULL);
4987 if (p == NULL || *p == NUL)
4988 p = (char_u *)"Unknown";
4989 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4990 }
4991 else
4992 {
4993#ifndef LC_MESSAGES
4994 if (what == VIM_LC_MESSAGES)
4995 loc = "";
4996 else
4997#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004998 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005000#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
5001 /* Make sure strtod() uses a decimal point, not a comma. */
5002 setlocale(LC_NUMERIC, "C");
5003#endif
5004 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005005 if (loc == NULL)
5006 EMSG2(_("E197: Cannot set language to \"%s\""), name);
5007 else
5008 {
5009#ifdef HAVE_NL_MSG_CAT_CNTR
5010 /* Need to do this for GNU gettext, otherwise cached translations
5011 * will be used again. */
5012 extern int _nl_msg_cat_cntr;
5013
5014 ++_nl_msg_cat_cntr;
5015#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00005016 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
5018
5019 if (what != LC_TIME)
5020 {
5021 /* Tell gettext() what to translate to. It apparently doesn't
5022 * use the currently effective locale. Also do this when
5023 * FEAT_GETTEXT isn't defined, so that shell commands use this
5024 * value. */
5025 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005026 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005027 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02005028
5029 /* Clear $LANGUAGE because GNU gettext uses it. */
5030 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005031# ifdef WIN32
5032 /* Apparently MS-Windows printf() may cause a crash when
5033 * we give it 8-bit text while it's expecting text in the
5034 * current locale. This call avoids that. */
5035 setlocale(LC_CTYPE, "C");
5036# endif
5037 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038 if (what != LC_CTYPE)
5039 {
5040 char_u *mname;
5041#ifdef WIN32
5042 mname = gettext_lang(name);
5043#else
5044 mname = name;
5045#endif
5046 vim_setenv((char_u *)"LC_MESSAGES", mname);
5047#ifdef FEAT_MULTI_LANG
5048 set_helplang_default(mname);
5049#endif
5050 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051 }
5052
5053# ifdef FEAT_EVAL
5054 /* Set v:lang, v:lc_time and v:ctype to the final result. */
5055 set_lang_var();
5056# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02005057# ifdef FEAT_TITLE
5058 maketitle();
5059# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005060 }
5061 }
5062}
5063
5064# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005065
5066static char_u **locales = NULL; /* Array of all available locales */
5067static int did_init_locales = FALSE;
5068
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01005069static void init_locales(void);
5070static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005071
5072/*
5073 * Lazy initialization of all available locales.
5074 */
5075 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005076init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005077{
5078 if (!did_init_locales)
5079 {
5080 did_init_locales = TRUE;
5081 locales = find_locales();
5082 }
5083}
5084
5085/* Return an array of strings for all available locales + NULL for the
5086 * last element. Return NULL in case of error. */
5087 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005088find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005089{
5090 garray_T locales_ga;
5091 char_u *loc;
5092
5093 /* Find all available locales by running command "locale -a". If this
5094 * doesn't work we won't have completion. */
5095 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02005096 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005097 if (locale_a == NULL)
5098 return NULL;
5099 ga_init2(&locales_ga, sizeof(char_u *), 20);
5100
5101 /* Transform locale_a string where each locale is separated by "\n"
5102 * into an array of locale strings. */
5103 loc = (char_u *)strtok((char *)locale_a, "\n");
5104
5105 while (loc != NULL)
5106 {
5107 if (ga_grow(&locales_ga, 1) == FAIL)
5108 break;
5109 loc = vim_strsave(loc);
5110 if (loc == NULL)
5111 break;
5112
5113 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
5114 loc = (char_u *)strtok(NULL, "\n");
5115 }
5116 vim_free(locale_a);
5117 if (ga_grow(&locales_ga, 1) == FAIL)
5118 {
5119 ga_clear(&locales_ga);
5120 return NULL;
5121 }
5122 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
5123 return (char_u **)locales_ga.ga_data;
5124}
5125
5126# if defined(EXITFREE) || defined(PROTO)
5127 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005128free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005129{
5130 int i;
5131 if (locales != NULL)
5132 {
5133 for (i = 0; locales[i] != NULL; i++)
5134 vim_free(locales[i]);
5135 vim_free(locales);
5136 locales = NULL;
5137 }
5138}
5139# endif
5140
Bram Moolenaar071d4272004-06-13 20:20:40 +00005141/*
5142 * Function given to ExpandGeneric() to obtain the possible arguments of the
5143 * ":language" command.
5144 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005145 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005146get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005147{
5148 if (idx == 0)
5149 return (char_u *)"messages";
5150 if (idx == 1)
5151 return (char_u *)"ctype";
5152 if (idx == 2)
5153 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005154
5155 init_locales();
5156 if (locales == NULL)
5157 return NULL;
5158 return locales[idx - 3];
5159}
5160
5161/*
5162 * Function given to ExpandGeneric() to obtain the available locales.
5163 */
5164 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005165get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005166{
5167 init_locales();
5168 if (locales == NULL)
5169 return NULL;
5170 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005171}
5172# endif
5173
5174#endif