blob: f6c054b8d29dea8228a02c40814cc7aa3a978f96 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
Bram Moolenaarf1f60f82016-01-16 15:40:53 +010071static int get_maxbacktrace_level(void);
72static void do_setdebugtracelevel(char_u *arg);
73static void do_checkbacktracelevel(void);
74static void do_showbacktrace(char_u *cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +000075
76/*
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
79 */
80 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010081do_debug(char_u *cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +000082{
83 int save_msg_scroll = msg_scroll;
84 int save_State = State;
85 int save_did_emsg = did_emsg;
86 int save_cmd_silent = cmd_silent;
87 int save_msg_silent = msg_silent;
88 int save_emsg_silent = emsg_silent;
89 int save_redir_off = redir_off;
90 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000091 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000092 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 int save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 int n;
95 char_u *cmdline = NULL;
96 char_u *p;
97 char *tail = NULL;
98 static int last_cmd = 0;
99#define CMD_CONT 1
100#define CMD_NEXT 2
101#define CMD_STEP 3
102#define CMD_FINISH 4
103#define CMD_QUIT 5
104#define CMD_INTERRUPT 6
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100105#define CMD_BACKTRACE 7
106#define CMD_FRAME 8
107#define CMD_UP 9
108#define CMD_DOWN 10
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109
110#ifdef ALWAYS_USE_GUI
111 /* Can't do this when there is no terminal for input/output. */
112 if (!gui.in_use)
113 {
114 /* Break as soon as possible. */
115 debug_break_level = 9999;
116 return;
117 }
118#endif
119
120 /* Make sure we are in raw mode and start termcap mode. Might have side
121 * effects... */
122 settmode(TMODE_RAW);
123 starttermcap();
124
125 ++RedrawingDisabled; /* don't redisplay the window */
126 ++no_wait_return; /* don't wait for return */
127 did_emsg = FALSE; /* don't use error from debugged stuff */
128 cmd_silent = FALSE; /* display commands */
129 msg_silent = FALSE; /* display messages */
130 emsg_silent = FALSE; /* display error messages */
131 redir_off = TRUE; /* don't redirect debug commands */
132
133 State = NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134
135 if (!debug_did_msg)
136 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
137 if (sourcing_name != NULL)
138 msg(sourcing_name);
139 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000142 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143
144 /*
145 * Repeat getting a command and executing it.
146 */
147 for (;;)
148 {
149 msg_scroll = TRUE;
150 need_wait_return = FALSE;
Bram Moolenaar85b11762016-02-27 18:13:23 +0100151
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 save_ex_normal_busy = ex_normal_busy;
158 ex_normal_busy = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000160 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 typeahead_saved = TRUE;
163 save_ignore_script = ignore_script;
164 ignore_script = TRUE;
165 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166
Bram Moolenaardc303bc2016-05-17 17:45:38 +0200167 vim_free(cmdline);
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000168 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000170 if (typeahead_saved)
171 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000173 ignore_script = save_ignore_script;
174 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176
177 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100178 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 if (cmdline != NULL)
180 {
181 /* If this is a debug command, set "last_cmd".
182 * If not, reset "last_cmd".
183 * For a blank line use previous command. */
184 p = skipwhite(cmdline);
185 if (*p != NUL)
186 {
187 switch (*p)
188 {
189 case 'c': last_cmd = CMD_CONT;
190 tail = "ont";
191 break;
192 case 'n': last_cmd = CMD_NEXT;
193 tail = "ext";
194 break;
195 case 's': last_cmd = CMD_STEP;
196 tail = "tep";
197 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100198 case 'f':
199 last_cmd = 0;
200 if (p[1] == 'r')
201 {
202 last_cmd = CMD_FRAME;
203 tail = "rame";
204 }
205 else
206 {
207 last_cmd = CMD_FINISH;
208 tail = "inish";
209 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210 break;
211 case 'q': last_cmd = CMD_QUIT;
212 tail = "uit";
213 break;
214 case 'i': last_cmd = CMD_INTERRUPT;
215 tail = "nterrupt";
216 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100217 case 'b': last_cmd = CMD_BACKTRACE;
218 if (p[1] == 't')
219 tail = "t";
220 else
221 tail = "acktrace";
222 break;
223 case 'w': last_cmd = CMD_BACKTRACE;
224 tail = "here";
225 break;
226 case 'u': last_cmd = CMD_UP;
227 tail = "p";
228 break;
229 case 'd': last_cmd = CMD_DOWN;
230 tail = "own";
231 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 default: last_cmd = 0;
233 }
234 if (last_cmd != 0)
235 {
236 /* Check that the tail matches. */
237 ++p;
238 while (*p != NUL && *p == *tail)
239 {
240 ++p;
241 ++tail;
242 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100243 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 last_cmd = 0;
245 }
246 }
247
248 if (last_cmd != 0)
249 {
250 /* Execute debug command: decided where to break next and
251 * return. */
252 switch (last_cmd)
253 {
254 case CMD_CONT:
255 debug_break_level = -1;
256 break;
257 case CMD_NEXT:
258 debug_break_level = ex_nesting_level;
259 break;
260 case CMD_STEP:
261 debug_break_level = 9999;
262 break;
263 case CMD_FINISH:
264 debug_break_level = ex_nesting_level - 1;
265 break;
266 case CMD_QUIT:
267 got_int = TRUE;
268 debug_break_level = -1;
269 break;
270 case CMD_INTERRUPT:
271 got_int = TRUE;
272 debug_break_level = 9999;
273 /* Do not repeat ">interrupt" cmd, continue stepping. */
274 last_cmd = CMD_STEP;
275 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100276 case CMD_BACKTRACE:
277 do_showbacktrace(cmd);
278 continue;
279 case CMD_FRAME:
280 if (*p == NUL)
281 {
282 do_showbacktrace(cmd);
283 }
284 else
285 {
286 p = skipwhite(p);
287 do_setdebugtracelevel(p);
288 }
289 continue;
290 case CMD_UP:
291 debug_backtrace_level++;
292 do_checkbacktracelevel();
293 continue;
294 case CMD_DOWN:
295 debug_backtrace_level--;
296 do_checkbacktracelevel();
297 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100299 /* Going out reset backtrace_level */
300 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301 break;
302 }
303
304 /* don't debug this command */
305 n = debug_break_level;
306 debug_break_level = -1;
307 (void)do_cmdline(cmdline, getexline, NULL,
308 DOCMD_VERBOSE|DOCMD_EXCRESET);
309 debug_break_level = n;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 }
311 lines_left = Rows - 1;
312 }
313 vim_free(cmdline);
314
315 --RedrawingDisabled;
316 --no_wait_return;
317 redraw_all_later(NOT_VALID);
318 need_wait_return = FALSE;
319 msg_scroll = save_msg_scroll;
320 lines_left = Rows - 1;
321 State = save_State;
322 did_emsg = save_did_emsg;
323 cmd_silent = save_cmd_silent;
324 msg_silent = save_msg_silent;
325 emsg_silent = save_emsg_silent;
326 redir_off = save_redir_off;
327
328 /* Only print the message again when typing a command before coming back
329 * here. */
330 debug_did_msg = TRUE;
331}
332
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100333 static int
334get_maxbacktrace_level(void)
335{
336 char *p, *q;
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200337 int maxbacktrace = 0;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100338
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100339 if (sourcing_name != NULL)
340 {
341 p = (char *)sourcing_name;
342 while ((q = strstr(p, "..")) != NULL)
343 {
344 p = q + 2;
345 maxbacktrace++;
346 }
347 }
348 return maxbacktrace;
349}
350
351 static void
352do_setdebugtracelevel(char_u *arg)
353{
354 int level;
355
356 level = atoi((char *)arg);
357 if (*arg == '+' || level < 0)
358 debug_backtrace_level += level;
359 else
360 debug_backtrace_level = level;
361
362 do_checkbacktracelevel();
363}
364
365 static void
366do_checkbacktracelevel(void)
367{
368 if (debug_backtrace_level < 0)
369 {
370 debug_backtrace_level = 0;
371 MSG(_("frame is zero"));
372 }
373 else
374 {
375 int max = get_maxbacktrace_level();
376
377 if (debug_backtrace_level > max)
378 {
379 debug_backtrace_level = max;
380 smsg((char_u *)_("frame at highest level: %d"), max);
381 }
382 }
383}
384
385 static void
386do_showbacktrace(char_u *cmd)
387{
388 char *cur;
389 char *next;
390 int i = 0;
391 int max = get_maxbacktrace_level();
392
393 if (sourcing_name != NULL)
394 {
395 cur = (char *)sourcing_name;
396 while (!got_int)
397 {
398 next = strstr(cur, "..");
399 if (next != NULL)
400 *next = NUL;
401 if (i == max - debug_backtrace_level)
402 smsg((char_u *)"->%d %s", max - i, cur);
403 else
404 smsg((char_u *)" %d %s", max - i, cur);
405 ++i;
406 if (next == NULL)
407 break;
408 *next = '.';
409 cur = next + 2;
410 }
411 }
412 if (sourcing_lnum != 0)
413 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
414 else
415 smsg((char_u *)_("cmd: %s"), cmd);
416}
417
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418/*
419 * ":debug".
420 */
421 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100422ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423{
424 int debug_break_level_save = debug_break_level;
425
426 debug_break_level = 9999;
427 do_cmdline_cmd(eap->arg);
428 debug_break_level = debug_break_level_save;
429}
430
431static char_u *debug_breakpoint_name = NULL;
432static linenr_T debug_breakpoint_lnum;
433
434/*
435 * When debugging or a breakpoint is set on a skipped command, no debug prompt
436 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
437 * debug_skipped_name is then set to the source name in the breakpoint case. If
438 * a skipped command decides itself that a debug prompt should be displayed, it
439 * can do so by calling dbg_check_skipped().
440 */
441static int debug_skipped;
442static char_u *debug_skipped_name;
443
444/*
445 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
446 * at or below the break level. But only when the line is actually
447 * executed. Return TRUE and set breakpoint_name for skipped commands that
448 * decide to execute something themselves.
449 * Called from do_one_cmd() before executing a command.
450 */
451 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100452dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453{
454 char_u *p;
455
456 debug_skipped = FALSE;
457 if (debug_breakpoint_name != NULL)
458 {
459 if (!eap->skip)
460 {
461 /* replace K_SNR with "<SNR>" */
462 if (debug_breakpoint_name[0] == K_SPECIAL
463 && debug_breakpoint_name[1] == KS_EXTRA
464 && debug_breakpoint_name[2] == (int)KE_SNR)
465 p = (char_u *)"<SNR>";
466 else
467 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000468 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
469 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 debug_breakpoint_name + (*p == NUL ? 0 : 3),
471 (long)debug_breakpoint_lnum);
472 debug_breakpoint_name = NULL;
473 do_debug(eap->cmd);
474 }
475 else
476 {
477 debug_skipped = TRUE;
478 debug_skipped_name = debug_breakpoint_name;
479 debug_breakpoint_name = NULL;
480 }
481 }
482 else if (ex_nesting_level <= debug_break_level)
483 {
484 if (!eap->skip)
485 do_debug(eap->cmd);
486 else
487 {
488 debug_skipped = TRUE;
489 debug_skipped_name = NULL;
490 }
491 }
492}
493
494/*
495 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
496 * set. Return TRUE when the debug mode is entered this time.
497 */
498 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100499dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500{
501 int prev_got_int;
502
503 if (debug_skipped)
504 {
505 /*
506 * Save the value of got_int and reset it. We don't want a previous
507 * interruption cause flushing the input buffer.
508 */
509 prev_got_int = got_int;
510 got_int = FALSE;
511 debug_breakpoint_name = debug_skipped_name;
512 /* eap->skip is TRUE */
513 eap->skip = FALSE;
514 (void)dbg_check_breakpoint(eap);
515 eap->skip = TRUE;
516 got_int |= prev_got_int;
517 return TRUE;
518 }
519 return FALSE;
520}
521
522/*
523 * The list of breakpoints: dbg_breakp.
524 * This is a grow-array of structs.
525 */
526struct debuggy
527{
528 int dbg_nr; /* breakpoint number */
529 int dbg_type; /* DBG_FUNC or DBG_FILE */
530 char_u *dbg_name; /* function or file name */
531 regprog_T *dbg_prog; /* regexp program */
532 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534};
535
536static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000537#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
538#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539static int last_breakp = 0; /* nr of last defined breakpoint */
540
Bram Moolenaar05159a02005-02-26 23:04:13 +0000541#ifdef FEAT_PROFILE
542/* Profiling uses file and func names similar to breakpoints. */
543static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
544#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545#define DBG_FUNC 1
546#define DBG_FILE 2
547
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100548static int dbg_parsearg(char_u *arg, garray_T *gap);
549static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550
551/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000552 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
553 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
554 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 * Returns FAIL for failure.
556 */
557 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100558dbg_parsearg(
559 char_u *arg,
560 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561{
562 char_u *p = arg;
563 char_u *q;
564 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000565 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566
Bram Moolenaar05159a02005-02-26 23:04:13 +0000567 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000569 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570
571 /* Find "func" or "file". */
572 if (STRNCMP(p, "func", 4) == 0)
573 bp->dbg_type = DBG_FUNC;
574 else if (STRNCMP(p, "file", 4) == 0)
575 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000576 else if (
577#ifdef FEAT_PROFILE
578 gap != &prof_ga &&
579#endif
580 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000581 {
582 if (curbuf->b_ffname == NULL)
583 {
584 EMSG(_(e_noname));
585 return FAIL;
586 }
587 bp->dbg_type = DBG_FILE;
588 here = TRUE;
589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590 else
591 {
592 EMSG2(_(e_invarg2), p);
593 return FAIL;
594 }
595 p = skipwhite(p + 4);
596
597 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000598 if (here)
599 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000600 else if (
601#ifdef FEAT_PROFILE
602 gap != &prof_ga &&
603#endif
604 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 {
606 bp->dbg_lnum = getdigits(&p);
607 p = skipwhite(p);
608 }
609 else
610 bp->dbg_lnum = 0;
611
612 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000613 if ((!here && *p == NUL)
614 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
616 {
617 EMSG2(_(e_invarg2), arg);
618 return FAIL;
619 }
620
621 if (bp->dbg_type == DBG_FUNC)
622 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000623 else if (here)
624 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 else
626 {
627 /* Expand the file name in the same way as do_source(). This means
628 * doing it twice, so that $DIR/file gets expanded when $DIR is
629 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 if (q == NULL)
632 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 vim_free(q);
635 if (p == NULL)
636 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000637 if (*p != '*')
638 {
639 bp->dbg_name = fix_fname(p);
640 vim_free(p);
641 }
642 else
643 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 }
645
646 if (bp->dbg_name == NULL)
647 return FAIL;
648 return OK;
649}
650
651/*
652 * ":breakadd".
653 */
654 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100655ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656{
657 struct debuggy *bp;
658 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000659 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660
Bram Moolenaar05159a02005-02-26 23:04:13 +0000661 gap = &dbg_breakp;
662#ifdef FEAT_PROFILE
663 if (eap->cmdidx == CMD_profile)
664 gap = &prof_ga;
665#endif
666
667 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000669 bp = &DEBUGGY(gap, gap->ga_len);
670 bp->dbg_forceit = eap->forceit;
671
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
673 if (pat != NULL)
674 {
675 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
676 vim_free(pat);
677 }
678 if (pat == NULL || bp->dbg_prog == NULL)
679 vim_free(bp->dbg_name);
680 else
681 {
682 if (bp->dbg_lnum == 0) /* default line number is 1 */
683 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000684#ifdef FEAT_PROFILE
685 if (eap->cmdidx != CMD_profile)
686#endif
687 {
688 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
689 ++debug_tick;
690 }
691 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 }
693 }
694}
695
696/*
697 * ":debuggreedy".
698 */
699 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100700ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701{
702 if (eap->addr_count == 0 || eap->line2 != 0)
703 debug_greedy = TRUE;
704 else
705 debug_greedy = FALSE;
706}
707
708/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000709 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 */
711 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100712ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713{
714 struct debuggy *bp, *bpi;
715 int nr;
716 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000717 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 int i;
719 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000720 garray_T *gap;
721
722 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000723 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200724 {
725#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000726 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200727#else
728 ex_ni(eap);
729 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000730#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200731 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732
733 if (vim_isdigit(*eap->arg))
734 {
735 /* ":breakdel {nr}" */
736 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000737 for (i = 0; i < gap->ga_len; ++i)
738 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 {
740 todel = i;
741 break;
742 }
743 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000744 else if (*eap->arg == '*')
745 {
746 todel = 0;
747 del_all = TRUE;
748 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 else
750 {
751 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000752 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000754 bp = &DEBUGGY(gap, gap->ga_len);
755 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000757 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 if (bp->dbg_type == bpi->dbg_type
759 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
760 && (bp->dbg_lnum == bpi->dbg_lnum
761 || (bp->dbg_lnum == 0
762 && (best_lnum == 0
763 || bpi->dbg_lnum < best_lnum))))
764 {
765 todel = i;
766 best_lnum = bpi->dbg_lnum;
767 }
768 }
769 vim_free(bp->dbg_name);
770 }
771
772 if (todel < 0)
773 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
774 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000775 {
776 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000777 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000778 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200779 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000780 --gap->ga_len;
781 if (todel < gap->ga_len)
782 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
783 (gap->ga_len - todel) * sizeof(struct debuggy));
784#ifdef FEAT_PROFILE
785 if (eap->cmdidx == CMD_breakdel)
786#endif
787 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000788 if (!del_all)
789 break;
790 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000791
792 /* If all breakpoints were removed clear the array. */
793 if (gap->ga_len == 0)
794 ga_clear(gap);
795 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796}
797
798/*
799 * ":breaklist".
800 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100802ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803{
804 struct debuggy *bp;
805 int i;
806
807 if (dbg_breakp.ga_len == 0)
808 MSG(_("No breakpoints defined"));
809 else
810 for (i = 0; i < dbg_breakp.ga_len; ++i)
811 {
812 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200813 if (bp->dbg_type == DBG_FILE)
814 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 smsg((char_u *)_("%3d %s %s line %ld"),
816 bp->dbg_nr,
817 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200818 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 (long)bp->dbg_lnum);
820 }
821}
822
823/*
824 * Find a breakpoint for a function or sourced file.
825 * Returns line number at which to break; zero when no matching breakpoint.
826 */
827 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100828dbg_find_breakpoint(
829 int file, /* TRUE for a file, FALSE for a function */
830 char_u *fname, /* file or function name */
831 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000833 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
834}
835
836#if defined(FEAT_PROFILE) || defined(PROTO)
837/*
838 * Return TRUE if profiling is on for a function or sourced file.
839 */
840 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100841has_profiling(
842 int file, /* TRUE for a file, FALSE for a function */
843 char_u *fname, /* file or function name */
844 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845{
846 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
847 != (linenr_T)0);
848}
849#endif
850
851/*
852 * Common code for dbg_find_breakpoint() and has_profiling().
853 */
854 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100855debuggy_find(
856 int file, /* TRUE for a file, FALSE for a function */
857 char_u *fname, /* file or function name */
858 linenr_T after, /* after this line number */
859 garray_T *gap, /* either &dbg_breakp or &prof_ga */
860 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 struct debuggy *bp;
863 int i;
864 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 char_u *name = fname;
866 int prev_got_int;
867
Bram Moolenaar05159a02005-02-26 23:04:13 +0000868 /* Return quickly when there are no breakpoints. */
869 if (gap->ga_len == 0)
870 return (linenr_T)0;
871
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 /* Replace K_SNR in function name with "<SNR>". */
873 if (!file && fname[0] == K_SPECIAL)
874 {
875 name = alloc((unsigned)STRLEN(fname) + 3);
876 if (name == NULL)
877 name = fname;
878 else
879 {
880 STRCPY(name, "<SNR>");
881 STRCPY(name + 5, fname + 3);
882 }
883 }
884
Bram Moolenaar05159a02005-02-26 23:04:13 +0000885 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000887 /* Skip entries that are not useful or are for a line that is beyond
888 * an already found breakpoint. */
889 bp = &DEBUGGY(gap, i);
890 if (((bp->dbg_type == DBG_FILE) == file && (
891#ifdef FEAT_PROFILE
892 gap == &prof_ga ||
893#endif
894 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000897 * Save the value of got_int and reset it. We don't want a
898 * previous interruption cancel matching, only hitting CTRL-C
899 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900 */
901 prev_got_int = got_int;
902 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100903 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000904 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000906 if (fp != NULL)
907 *fp = bp->dbg_forceit;
908 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 got_int |= prev_got_int;
910 }
911 }
912 if (name != fname)
913 vim_free(name);
914
915 return lnum;
916}
917
918/*
919 * Called when a breakpoint was encountered.
920 */
921 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100922dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923{
924 /* We need to check if this line is actually executed in do_one_cmd() */
925 debug_breakpoint_name = name;
926 debug_breakpoint_lnum = lnum;
927}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000928
929
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000930# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000931/*
932 * Store the current time in "tm".
933 */
934 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100935profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000936{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000937# ifdef WIN3264
938 QueryPerformanceCounter(tm);
939# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000940 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000941# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000942}
943
944/*
945 * Compute the elapsed time from "tm" till now and store in "tm".
946 */
947 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100948profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000949{
950 proftime_T now;
951
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000952# ifdef WIN3264
953 QueryPerformanceCounter(&now);
954 tm->QuadPart = now.QuadPart - tm->QuadPart;
955# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000956 gettimeofday(&now, NULL);
957 tm->tv_usec = now.tv_usec - tm->tv_usec;
958 tm->tv_sec = now.tv_sec - tm->tv_sec;
959 if (tm->tv_usec < 0)
960 {
961 tm->tv_usec += 1000000;
962 --tm->tv_sec;
963 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000964# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000965}
966
967/*
968 * Subtract the time "tm2" from "tm".
969 */
970 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100971profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000972{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000973# ifdef WIN3264
974 tm->QuadPart -= tm2->QuadPart;
975# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000976 tm->tv_usec -= tm2->tv_usec;
977 tm->tv_sec -= tm2->tv_sec;
978 if (tm->tv_usec < 0)
979 {
980 tm->tv_usec += 1000000;
981 --tm->tv_sec;
982 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000983# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000984}
985
986/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000987 * Return a string that represents the time in "tm".
988 * Uses a static buffer!
989 */
990 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100991profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000992{
993 static char buf[50];
994
995# ifdef WIN3264
996 LARGE_INTEGER fr;
997
998 QueryPerformanceFrequency(&fr);
999 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1000# else
1001 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001002# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001003 return buf;
1004}
1005
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001006# if defined(FEAT_FLOAT) || defined(PROTO)
1007/*
1008 * Return a float that represents the time in "tm".
1009 */
1010 float_T
1011profile_float(proftime_T *tm)
1012{
1013# ifdef WIN3264
1014 LARGE_INTEGER fr;
1015
1016 QueryPerformanceFrequency(&fr);
1017 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
1018# else
1019 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
1020# endif
1021}
1022# endif
1023
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001024/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001025 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001026 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001027 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001028profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001029{
1030 if (msec <= 0) /* no limit */
1031 profile_zero(tm);
1032 else
1033 {
1034# ifdef WIN3264
1035 LARGE_INTEGER fr;
1036
1037 QueryPerformanceCounter(tm);
1038 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001039 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001040# else
1041 long usec;
1042
1043 gettimeofday(tm, NULL);
1044 usec = (long)tm->tv_usec + (long)msec * 1000;
1045 tm->tv_usec = usec % 1000000L;
1046 tm->tv_sec += usec / 1000000L;
1047# endif
1048 }
1049}
1050
1051/*
1052 * Return TRUE if the current time is past "tm".
1053 */
1054 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001055profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001056{
1057 proftime_T now;
1058
1059# ifdef WIN3264
1060 if (tm->QuadPart == 0) /* timer was not set */
1061 return FALSE;
1062 QueryPerformanceCounter(&now);
1063 return (now.QuadPart > tm->QuadPart);
1064# else
1065 if (tm->tv_sec == 0) /* timer was not set */
1066 return FALSE;
1067 gettimeofday(&now, NULL);
1068 return (now.tv_sec > tm->tv_sec
1069 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1070# endif
1071}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001072
1073/*
1074 * Set the time in "tm" to zero.
1075 */
1076 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001077profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001078{
1079# ifdef WIN3264
1080 tm->QuadPart = 0;
1081# else
1082 tm->tv_usec = 0;
1083 tm->tv_sec = 0;
1084# endif
1085}
1086
Bram Moolenaar76929292008-01-06 19:07:36 +00001087# endif /* FEAT_PROFILE || FEAT_RELTIME */
1088
Bram Moolenaar975b5272016-03-15 23:10:59 +01001089# if defined(FEAT_TIMERS) || defined(PROTO)
1090static timer_T *first_timer = NULL;
1091static int last_timer_id = 0;
1092
1093/*
1094 * Insert a timer in the list of timers.
1095 */
1096 static void
1097insert_timer(timer_T *timer)
1098{
1099 timer->tr_next = first_timer;
1100 timer->tr_prev = NULL;
1101 if (first_timer != NULL)
1102 first_timer->tr_prev = timer;
1103 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +02001104 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001105}
1106
1107/*
1108 * Take a timer out of the list of timers.
1109 */
1110 static void
1111remove_timer(timer_T *timer)
1112{
1113 if (timer->tr_prev == NULL)
1114 first_timer = timer->tr_next;
1115 else
1116 timer->tr_prev->tr_next = timer->tr_next;
1117 if (timer->tr_next != NULL)
1118 timer->tr_next->tr_prev = timer->tr_prev;
1119}
1120
1121 static void
1122free_timer(timer_T *timer)
1123{
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 {
1192# ifdef WIN3264
1193 this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
1194 / (double)fr.QuadPart) * 1000);
1195# else
1196 this_due = (timer->tr_due.tv_sec - now.tv_sec) * 1000
1197 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1198# endif
1199 if (this_due <= 1)
1200 {
1201 remove_timer(timer);
1202 timer_callback(timer);
1203 did_one = TRUE;
1204 if (timer->tr_repeat != 0)
1205 {
1206 profile_setlimit(timer->tr_interval, &timer->tr_due);
1207 if (timer->tr_repeat > 0)
1208 --timer->tr_repeat;
1209 insert_timer(timer);
1210 }
1211 else
1212 free_timer(timer);
1213 /* the callback may do anything, start all over */
1214 break;
1215 }
1216 if (next_due == -1 || next_due > this_due)
1217 next_due = this_due;
1218 }
1219 if (timer == NULL)
1220 break;
1221 }
1222
1223 if (did_one)
1224 redraw_after_callback();
1225
1226 return next_due;
1227}
1228
1229/*
1230 * Find a timer by ID. Returns NULL if not found;
1231 */
1232 timer_T *
1233find_timer(int id)
1234{
1235 timer_T *timer;
1236
1237 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1238 if (timer->tr_id == id)
1239 break;
1240 return timer;
1241}
1242
1243
1244/*
1245 * Stop a timer and delete it.
1246 */
1247 void
1248stop_timer(timer_T *timer)
1249{
1250 remove_timer(timer);
1251 free_timer(timer);
1252}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001253
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001254 void
1255add_timer_info(typval_T *rettv, timer_T *timer)
1256{
1257 list_T *list = rettv->vval.v_list;
1258 dict_T *dict = dict_alloc();
1259 dictitem_T *di;
1260 long remaining;
1261 proftime_T now;
1262
1263 if (dict == NULL)
1264 return;
1265 list_append_dict(list, dict);
1266
1267 dict_add_nr_str(dict, "id", (long)timer->tr_id, NULL);
1268 dict_add_nr_str(dict, "time", (long)timer->tr_interval, NULL);
1269
1270 profile_start(&now);
1271# ifdef WIN3264
1272 remaining = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
1273 / (double)fr.QuadPart) * 1000);
1274# else
1275 remaining = (timer->tr_due.tv_sec - now.tv_sec) * 1000
1276 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1277# endif
1278 dict_add_nr_str(dict, "remaining", (long)remaining, NULL);
1279
1280 dict_add_nr_str(dict, "repeat",
1281 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1), NULL);
1282
1283 di = dictitem_alloc((char_u *)"callback");
1284 if (di != NULL)
1285 {
1286 if (dict_add(dict, di) == FAIL)
1287 vim_free(di);
1288 else if (timer->tr_partial != NULL)
1289 {
1290 di->di_tv.v_type = VAR_PARTIAL;
1291 di->di_tv.vval.v_partial = timer->tr_partial;
1292 ++timer->tr_partial->pt_refcount;
1293 }
1294 else
1295 {
1296 di->di_tv.v_type = VAR_FUNC;
1297 di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
1298 }
1299 di->di_tv.v_lock = 0;
1300 }
1301}
1302
1303 void
1304add_timer_info_all(typval_T *rettv)
1305{
1306 timer_T *timer;
1307
1308 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1309 add_timer_info(rettv, timer);
1310}
1311
Bram Moolenaare3188e22016-05-31 21:13:04 +02001312/*
1313 * Mark references in partials of timers.
1314 */
1315 int
1316set_ref_in_timer(int copyID)
1317{
1318 int abort = FALSE;
1319 timer_T *timer;
1320 typval_T tv;
1321
1322 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1323 {
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +02001324 if (timer->tr_partial != NULL)
1325 {
1326 tv.v_type = VAR_PARTIAL;
1327 tv.vval.v_partial = timer->tr_partial;
1328 }
1329 else
1330 {
1331 tv.v_type = VAR_FUNC;
1332 tv.vval.v_string = timer->tr_callback;
1333 }
Bram Moolenaare3188e22016-05-31 21:13:04 +02001334 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1335 }
1336 return abort;
1337}
Bram Moolenaar623e2632016-07-30 22:47:56 +02001338
1339# if defined(EXITFREE) || defined(PROTO)
1340 void
1341timer_free_all()
1342{
1343 timer_T *timer;
1344
1345 while (first_timer != NULL)
1346 {
1347 timer = first_timer;
1348 remove_timer(timer);
1349 free_timer(timer);
1350 }
1351}
1352# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +01001353# endif
1354
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001355#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1356# if defined(HAVE_MATH_H)
1357# include <math.h>
1358# endif
1359
1360/*
1361 * Divide the time "tm" by "count" and store in "tm2".
1362 */
1363 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001364profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001365{
1366 if (count == 0)
1367 profile_zero(tm2);
1368 else
1369 {
1370# ifdef WIN3264
1371 tm2->QuadPart = tm->QuadPart / count;
1372# else
1373 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1374
1375 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001376 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001377# endif
1378 }
1379}
1380#endif
1381
Bram Moolenaar76929292008-01-06 19:07:36 +00001382# if defined(FEAT_PROFILE) || defined(PROTO)
1383/*
1384 * Functions for profiling.
1385 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001386static void script_do_profile(scriptitem_T *si);
1387static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001388static proftime_T prof_wait_time;
1389
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001390/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001391 * Add the time "tm2" to "tm".
1392 */
1393 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001394profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001395{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001396# ifdef WIN3264
1397 tm->QuadPart += tm2->QuadPart;
1398# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001399 tm->tv_usec += tm2->tv_usec;
1400 tm->tv_sec += tm2->tv_sec;
1401 if (tm->tv_usec >= 1000000)
1402 {
1403 tm->tv_usec -= 1000000;
1404 ++tm->tv_sec;
1405 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001406# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001407}
1408
1409/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001410 * Add the "self" time from the total time and the children's time.
1411 */
1412 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001413profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001414{
1415 /* Check that the result won't be negative. Can happen with recursive
1416 * calls. */
1417#ifdef WIN3264
1418 if (total->QuadPart <= children->QuadPart)
1419 return;
1420#else
1421 if (total->tv_sec < children->tv_sec
1422 || (total->tv_sec == children->tv_sec
1423 && total->tv_usec <= children->tv_usec))
1424 return;
1425#endif
1426 profile_add(self, total);
1427 profile_sub(self, children);
1428}
1429
1430/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001431 * Get the current waittime.
1432 */
1433 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001434profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001435{
1436 *tm = prof_wait_time;
1437}
1438
1439/*
1440 * Subtract the passed waittime since "tm" from "tma".
1441 */
1442 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001443profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001444{
1445 proftime_T tm3 = prof_wait_time;
1446
1447 profile_sub(&tm3, tm);
1448 profile_sub(tma, &tm3);
1449}
1450
1451/*
1452 * Return TRUE if "tm1" and "tm2" are equal.
1453 */
1454 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001455profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001456{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001457# ifdef WIN3264
1458 return (tm1->QuadPart == tm2->QuadPart);
1459# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001460 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001461# endif
1462}
1463
1464/*
1465 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1466 */
1467 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001468profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001469{
1470# ifdef WIN3264
1471 return (int)(tm2->QuadPart - tm1->QuadPart);
1472# else
1473 if (tm1->tv_sec == tm2->tv_sec)
1474 return tm2->tv_usec - tm1->tv_usec;
1475 return tm2->tv_sec - tm1->tv_sec;
1476# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001477}
1478
Bram Moolenaar05159a02005-02-26 23:04:13 +00001479static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001480static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001481
1482/*
1483 * ":profile cmd args"
1484 */
1485 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001486ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001487{
1488 char_u *e;
1489 int len;
1490
1491 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001492 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001493 e = skipwhite(e);
1494
1495 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1496 {
1497 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001498 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001499 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001500 profile_zero(&prof_wait_time);
1501 set_vim_var_nr(VV_PROFILING, 1L);
1502 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001503 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001504 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001505 else if (STRCMP(eap->arg, "pause") == 0)
1506 {
1507 if (do_profiling == PROF_YES)
1508 profile_start(&pause_time);
1509 do_profiling = PROF_PAUSED;
1510 }
1511 else if (STRCMP(eap->arg, "continue") == 0)
1512 {
1513 if (do_profiling == PROF_PAUSED)
1514 {
1515 profile_end(&pause_time);
1516 profile_add(&prof_wait_time, &pause_time);
1517 }
1518 do_profiling = PROF_YES;
1519 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001520 else
1521 {
1522 /* The rest is similar to ":breakadd". */
1523 ex_breakadd(eap);
1524 }
1525}
1526
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001527/* Command line expansion for :profile. */
1528static enum
1529{
1530 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001531 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001532} pexpand_what;
1533
1534static char *pexpand_cmds[] = {
1535 "start",
1536#define PROFCMD_START 0
1537 "pause",
1538#define PROFCMD_PAUSE 1
1539 "continue",
1540#define PROFCMD_CONTINUE 2
1541 "func",
1542#define PROFCMD_FUNC 3
1543 "file",
1544#define PROFCMD_FILE 4
1545 NULL
1546#define PROFCMD_LAST 5
1547};
1548
1549/*
1550 * Function given to ExpandGeneric() to obtain the profile command
1551 * specific expansion.
1552 */
1553 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001554get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001555{
1556 switch (pexpand_what)
1557 {
1558 case PEXP_SUBCMD:
1559 return (char_u *)pexpand_cmds[idx];
1560 /* case PEXP_FUNC: TODO */
1561 default:
1562 return NULL;
1563 }
1564}
1565
1566/*
1567 * Handle command line completion for :profile command.
1568 */
1569 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001570set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001571{
1572 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001573
1574 /* Default: expand subcommands. */
1575 xp->xp_context = EXPAND_PROFILE;
1576 pexpand_what = PEXP_SUBCMD;
1577 xp->xp_pattern = arg;
1578
1579 end_subcmd = skiptowhite(arg);
1580 if (*end_subcmd == NUL)
1581 return;
1582
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001583 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001584 {
1585 xp->xp_context = EXPAND_FILES;
1586 xp->xp_pattern = skipwhite(end_subcmd);
1587 return;
1588 }
1589
1590 /* TODO: expand function names after "func" */
1591 xp->xp_context = EXPAND_NOTHING;
1592}
1593
Bram Moolenaar05159a02005-02-26 23:04:13 +00001594/*
1595 * Dump the profiling info.
1596 */
1597 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001598profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001599{
1600 FILE *fd;
1601
1602 if (profile_fname != NULL)
1603 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001604 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001605 if (fd == NULL)
1606 EMSG2(_(e_notopen), profile_fname);
1607 else
1608 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001609 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001610 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001611 fclose(fd);
1612 }
1613 }
1614}
1615
1616/*
1617 * Start profiling script "fp".
1618 */
1619 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001620script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001621{
1622 si->sn_pr_count = 0;
1623 profile_zero(&si->sn_pr_total);
1624 profile_zero(&si->sn_pr_self);
1625
1626 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1627 si->sn_prl_idx = -1;
1628 si->sn_prof_on = TRUE;
1629 si->sn_pr_nest = 0;
1630}
1631
1632/*
1633 * save time when starting to invoke another script or function.
1634 */
1635 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001636script_prof_save(
1637 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001638{
1639 scriptitem_T *si;
1640
1641 if (current_SID > 0 && current_SID <= script_items.ga_len)
1642 {
1643 si = &SCRIPT_ITEM(current_SID);
1644 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1645 profile_start(&si->sn_pr_child);
1646 }
1647 profile_get_wait(tm);
1648}
1649
1650/*
1651 * Count time spent in children after invoking another script or function.
1652 */
1653 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001654script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001655{
1656 scriptitem_T *si;
1657
1658 if (current_SID > 0 && current_SID <= script_items.ga_len)
1659 {
1660 si = &SCRIPT_ITEM(current_SID);
1661 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1662 {
1663 profile_end(&si->sn_pr_child);
1664 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1665 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1666 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1667 }
1668 }
1669}
1670
1671static proftime_T inchar_time;
1672
1673/*
1674 * Called when starting to wait for the user to type a character.
1675 */
1676 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001677prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001678{
1679 profile_start(&inchar_time);
1680}
1681
1682/*
1683 * Called when finished waiting for the user to type a character.
1684 */
1685 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001686prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001687{
1688 profile_end(&inchar_time);
1689 profile_add(&prof_wait_time, &inchar_time);
1690}
1691
1692/*
1693 * Dump the profiling results for all scripts in file "fd".
1694 */
1695 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001696script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001697{
1698 int id;
1699 scriptitem_T *si;
1700 int i;
1701 FILE *sfd;
1702 sn_prl_T *pp;
1703
1704 for (id = 1; id <= script_items.ga_len; ++id)
1705 {
1706 si = &SCRIPT_ITEM(id);
1707 if (si->sn_prof_on)
1708 {
1709 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1710 if (si->sn_pr_count == 1)
1711 fprintf(fd, "Sourced 1 time\n");
1712 else
1713 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1714 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1715 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1716 fprintf(fd, "\n");
1717 fprintf(fd, "count total (s) self (s)\n");
1718
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001719 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001720 if (sfd == NULL)
1721 fprintf(fd, "Cannot open file!\n");
1722 else
1723 {
1724 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1725 {
1726 if (vim_fgets(IObuff, IOSIZE, sfd))
1727 break;
1728 pp = &PRL_ITEM(si, i);
1729 if (pp->snp_count > 0)
1730 {
1731 fprintf(fd, "%5d ", pp->snp_count);
1732 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1733 fprintf(fd, " ");
1734 else
1735 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1736 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1737 }
1738 else
1739 fprintf(fd, " ");
1740 fprintf(fd, "%s", IObuff);
1741 }
1742 fclose(sfd);
1743 }
1744 fprintf(fd, "\n");
1745 }
1746 }
1747}
1748
1749/*
1750 * Return TRUE when a function defined in the current script should be
1751 * profiled.
1752 */
1753 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001754prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001755{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001756 if (current_SID > 0)
1757 return SCRIPT_ITEM(current_SID).sn_pr_force;
1758 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001759}
1760
1761# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762#endif
1763
1764/*
1765 * If 'autowrite' option set, try to write the file.
1766 * Careful: autocommands may make "buf" invalid!
1767 *
1768 * return FAIL for failure, OK otherwise
1769 */
1770 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001771autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001773 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001774 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001775
Bram Moolenaar071d4272004-06-13 20:20:40 +00001776 if (!(p_aw || p_awa) || !p_write
1777#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001778 /* never autowrite a "nofile" or "nowrite" buffer */
1779 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001781 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001782 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001783 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001784 r = buf_write_all(buf, forceit);
1785
1786 /* Writing may succeed but the buffer still changed, e.g., when there is a
1787 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001788 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001789 r = FAIL;
1790 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791}
1792
1793/*
1794 * flush all buffers, except the ones that are readonly
1795 */
1796 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001797autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798{
1799 buf_T *buf;
1800
1801 if (!(p_aw || p_awa) || !p_write)
1802 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001803 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001804 if (bufIsChanged(buf) && !buf->b_p_ro)
1805 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001806#ifdef FEAT_AUTOCMD
1807 bufref_T bufref;
1808
1809 set_bufref(&bufref, buf);
1810#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001811 (void)buf_write_all(buf, FALSE);
1812#ifdef FEAT_AUTOCMD
1813 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001814 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815 buf = firstbuf;
1816#endif
1817 }
1818}
1819
1820/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001821 * Return TRUE if buffer was changed and cannot be abandoned.
1822 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001823 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001825check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001827 int forceit = (flags & CCGD_FORCEIT);
1828#ifdef FEAT_AUTOCMD
1829 bufref_T bufref;
1830
1831 set_bufref(&bufref, buf);
1832#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001833
Bram Moolenaar071d4272004-06-13 20:20:40 +00001834 if ( !forceit
1835 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001836 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1837 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 {
1839#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1840 if ((p_confirm || cmdmod.confirm) && p_write)
1841 {
1842 buf_T *buf2;
1843 int count = 0;
1844
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001845 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001846 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847 if (bufIsChanged(buf2)
1848 && (buf2->b_ffname != NULL
1849# ifdef FEAT_BROWSE
1850 || cmdmod.browse
1851# endif
1852 ))
1853 ++count;
1854# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001855 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001856 /* Autocommand deleted buffer, oops! It's not changed now. */
1857 return FALSE;
1858# endif
1859 dialog_changed(buf, count > 1);
1860# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001861 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862 /* Autocommand deleted buffer, oops! It's not changed now. */
1863 return FALSE;
1864# endif
1865 return bufIsChanged(buf);
1866 }
1867#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001868 if (flags & CCGD_EXCMD)
1869 EMSG(_(e_nowrtmsg));
1870 else
1871 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 return TRUE;
1873 }
1874 return FALSE;
1875}
1876
1877#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1878
1879#if defined(FEAT_BROWSE) || defined(PROTO)
1880/*
1881 * When wanting to write a file without a file name, ask the user for a name.
1882 */
1883 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001884browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001885{
1886 if (buf->b_fname == NULL)
1887 {
1888 char_u *fname;
1889
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001890 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1891 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001892 if (fname != NULL)
1893 {
1894 if (setfname(buf, fname, NULL, TRUE) == OK)
1895 buf->b_flags |= BF_NOTEDITED;
1896 vim_free(fname);
1897 }
1898 }
1899}
1900#endif
1901
1902/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001903 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 * Must check 'write' option first!
1905 */
1906 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001907dialog_changed(
1908 buf_T *buf,
1909 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001911 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912 int ret;
1913 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001914 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001916 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001917 (buf->b_fname != NULL) ?
1918 buf->b_fname : (char_u *)_("Untitled"));
1919 if (checkall)
1920 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1921 else
1922 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1923
Bram Moolenaar8218f602012-04-25 17:32:18 +02001924 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1925 * function. */
1926 ea.append = ea.forceit = FALSE;
1927
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 if (ret == VIM_YES)
1929 {
1930#ifdef FEAT_BROWSE
1931 /* May get file name, when there is none */
1932 browse_save_fname(buf);
1933#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001934 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1935 buf->b_fname, buf->b_ffname, FALSE) == OK)
1936 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 (void)buf_write_all(buf, FALSE);
1938 }
1939 else if (ret == VIM_NO)
1940 {
1941 unchanged(buf, TRUE);
1942 }
1943 else if (ret == VIM_ALL)
1944 {
1945 /*
1946 * Write all modified files that can be written.
1947 * Skip readonly buffers, these need to be confirmed
1948 * individually.
1949 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001950 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001951 {
1952 if (bufIsChanged(buf2)
1953 && (buf2->b_ffname != NULL
1954#ifdef FEAT_BROWSE
1955 || cmdmod.browse
1956#endif
1957 )
1958 && !buf2->b_p_ro)
1959 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001960#ifdef FEAT_AUTOCMD
1961 bufref_T bufref;
1962
1963 set_bufref(&bufref, buf2);
1964#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965#ifdef FEAT_BROWSE
1966 /* May get file name, when there is none */
1967 browse_save_fname(buf2);
1968#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001969 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1970 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1971 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001972 (void)buf_write_all(buf2, FALSE);
1973#ifdef FEAT_AUTOCMD
1974 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001975 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976 buf2 = firstbuf;
1977#endif
1978 }
1979 }
1980 }
1981 else if (ret == VIM_DISCARDALL)
1982 {
1983 /*
1984 * mark all buffers as unchanged
1985 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001986 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987 unchanged(buf2, TRUE);
1988 }
1989}
1990#endif
1991
1992/*
1993 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1994 * hidden, autowriting it or unloading it.
1995 */
1996 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001997can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001998{
1999 return ( P_HID(buf)
2000 || !bufIsChanged(buf)
2001 || buf->b_nwindows > 1
2002 || autowrite(buf, forceit) == OK
2003 || forceit);
2004}
2005
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002006static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002007
2008/*
2009 * Add a buffer number to "bufnrs", unless it's already there.
2010 */
2011 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002012add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002013{
2014 int i;
2015
2016 for (i = 0; i < *bufnump; ++i)
2017 if (bufnrs[i] == nr)
2018 return;
2019 bufnrs[*bufnump] = nr;
2020 *bufnump = *bufnump + 1;
2021}
2022
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023/*
2024 * Return TRUE if any buffer was changed and cannot be abandoned.
2025 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01002026 * When "unload" is true the current buffer is unloaded instead of making it
2027 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002028 */
2029 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002030check_changed_any(
2031 int hidden, /* Only check hidden buffers */
2032 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002033{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002034 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002035 buf_T *buf;
2036 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002037 int i;
2038 int bufnum = 0;
2039 int bufcount = 0;
2040 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002041#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002042 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 win_T *wp;
2044#endif
2045
Bram Moolenaar29323592016-07-24 22:04:11 +02002046 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002047 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002048
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002049 if (bufcount == 0)
2050 return FALSE;
2051
2052 bufnrs = (int *)alloc(sizeof(int) * bufcount);
2053 if (bufnrs == NULL)
2054 return FALSE;
2055
2056 /* curbuf */
2057 bufnrs[bufnum++] = curbuf->b_fnum;
2058#ifdef FEAT_WINDOWS
2059 /* buf in curtab */
2060 FOR_ALL_WINDOWS(wp)
2061 if (wp->w_buffer != curbuf)
2062 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2063
2064 /* buf in other tab */
Bram Moolenaar29323592016-07-24 22:04:11 +02002065 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002066 if (tp != curtab)
2067 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
2068 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2069#endif
2070 /* any other buf */
Bram Moolenaar29323592016-07-24 22:04:11 +02002071 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002072 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
2073
2074 for (i = 0; i < bufnum; ++i)
2075 {
2076 buf = buflist_findnr(bufnrs[i]);
2077 if (buf == NULL)
2078 continue;
2079 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
2080 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002081 bufref_T bufref;
2082
2083 set_bufref(&bufref, buf);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002084 /* Try auto-writing the buffer. If this fails but the buffer no
2085 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002086 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
2087 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002088 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002089 break; /* didn't save - still changes */
2090 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 }
2092
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002093 if (i >= bufnum)
2094 goto theend;
2095
2096 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002097 exiting = FALSE;
2098#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2099 /*
2100 * When ":confirm" used, don't give an error message.
2101 */
2102 if (!(p_confirm || cmdmod.confirm))
2103#endif
2104 {
2105 /* There must be a wait_return for this message, do_buffer()
2106 * may cause a redraw. But wait_return() is a no-op when vgetc()
2107 * is busy (Quit used from window menu), then make sure we don't
2108 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002109 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002110 {
2111 msg_row = cmdline_row;
2112 msg_col = 0;
2113 msg_didout = FALSE;
2114 }
2115 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002116 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002117 {
2118 save = no_wait_return;
2119 no_wait_return = FALSE;
2120 wait_return(FALSE);
2121 no_wait_return = save;
2122 }
2123 }
2124
2125#ifdef FEAT_WINDOWS
2126 /* Try to find a window that contains the buffer. */
2127 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002128 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002129 if (wp->w_buffer == buf)
2130 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002131# ifdef FEAT_AUTOCMD
2132 bufref_T bufref;
2133
2134 set_bufref(&bufref, buf);
2135# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002136 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137# ifdef FEAT_AUTOCMD
2138 /* Paranoia: did autocms wipe out the buffer with changes? */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002139 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002140 {
2141 goto theend;
2142 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002144 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002146buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147#endif
2148
2149 /* Open the changed buffer in the current window. */
2150 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002151 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002153theend:
2154 vim_free(bufnrs);
2155 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002156}
2157
2158/*
2159 * return FAIL if there is no file name, OK if there is one
2160 * give error message for FAIL
2161 */
2162 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002163check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164{
2165 if (curbuf->b_ffname == NULL)
2166 {
2167 EMSG(_(e_noname));
2168 return FAIL;
2169 }
2170 return OK;
2171}
2172
2173/*
2174 * flush the contents of a buffer, unless it has no file name
2175 *
2176 * return FAIL for failure, OK otherwise
2177 */
2178 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002179buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180{
2181 int retval;
2182#ifdef FEAT_AUTOCMD
2183 buf_T *old_curbuf = curbuf;
2184#endif
2185
2186 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2187 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2188 FALSE, forceit, TRUE, FALSE));
2189#ifdef FEAT_AUTOCMD
2190 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002191 {
2192 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002193 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002194 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195#endif
2196 return retval;
2197}
2198
2199/*
2200 * Code to handle the argument list.
2201 */
2202
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002203static char_u *do_one_arg(char_u *str);
2204static int do_arglist(char_u *str, int what, int after);
2205static void alist_check_arg_idx(void);
2206static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002207#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002208static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002209#endif
2210#define AL_SET 1
2211#define AL_ADD 2
2212#define AL_DEL 3
2213
Bram Moolenaar071d4272004-06-13 20:20:40 +00002214/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002215 * Isolate one argument, taking backticks.
2216 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217 * Return a pointer to the start of the next argument.
2218 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002219 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002220do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221{
2222 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002223 int inbacktick;
2224
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225 inbacktick = FALSE;
2226 for (p = str; *str; ++str)
2227 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002228 /* When the backslash is used for escaping the special meaning of a
2229 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002230 if (rem_backslash(str))
2231 {
2232 *p++ = *str++;
2233 *p++ = *str;
2234 }
2235 else
2236 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002237 /* An item ends at a space not in backticks */
2238 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002239 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002240 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002241 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002242 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002243 }
2244 }
2245 str = skipwhite(str);
2246 *p = NUL;
2247
2248 return str;
2249}
2250
Bram Moolenaar86b68352004-12-27 21:59:20 +00002251/*
2252 * Separate the arguments in "str" and return a list of pointers in the
2253 * growarray "gap".
2254 */
2255 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002256get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002257{
2258 ga_init2(gap, (int)sizeof(char_u *), 20);
2259 while (*str != NUL)
2260 {
2261 if (ga_grow(gap, 1) == FAIL)
2262 {
2263 ga_clear(gap);
2264 return FAIL;
2265 }
2266 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2267
2268 /* Isolate one argument, change it in-place, put a NUL after it. */
2269 str = do_one_arg(str);
2270 }
2271 return OK;
2272}
2273
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002274#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002275/*
2276 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002277 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002278 * Return FAIL or OK.
2279 */
2280 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002281get_arglist_exp(
2282 char_u *str,
2283 int *fcountp,
2284 char_u ***fnamesp,
2285 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002286{
2287 garray_T ga;
2288 int i;
2289
2290 if (get_arglist(&ga, str) == FAIL)
2291 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002292 if (wig == TRUE)
2293 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2294 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2295 else
2296 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2297 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2298
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002299 ga_clear(&ga);
2300 return i;
2301}
2302#endif
2303
Bram Moolenaar071d4272004-06-13 20:20:40 +00002304#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2305/*
2306 * Redefine the argument list.
2307 */
2308 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002309set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310{
2311 do_arglist(str, AL_SET, 0);
2312}
2313#endif
2314
2315/*
2316 * "what" == AL_SET: Redefine the argument list to 'str'.
2317 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2318 * "what" == AL_DEL: remove files in 'str' from the argument list.
2319 *
2320 * Return FAIL for failure, OK otherwise.
2321 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002323do_arglist(
2324 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002325 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002326 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327{
2328 garray_T new_ga;
2329 int exp_count;
2330 char_u **exp_files;
2331 int i;
2332#ifdef FEAT_LISTCMDS
2333 char_u *p;
2334 int match;
2335#endif
2336
2337 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002338 * Set default argument for ":argadd" command.
2339 */
2340 if (what == AL_ADD && *str == NUL)
2341 {
2342 if (curbuf->b_ffname == NULL)
2343 return FAIL;
2344 str = curbuf->b_fname;
2345 }
2346
2347 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348 * Collect all file name arguments in "new_ga".
2349 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002350 if (get_arglist(&new_ga, str) == FAIL)
2351 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352
2353#ifdef FEAT_LISTCMDS
2354 if (what == AL_DEL)
2355 {
2356 regmatch_T regmatch;
2357 int didone;
2358
2359 /*
2360 * Delete the items: use each item as a regexp and find a match in the
2361 * argument list.
2362 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002363 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2365 {
2366 p = ((char_u **)new_ga.ga_data)[i];
2367 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2368 if (p == NULL)
2369 break;
2370 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2371 if (regmatch.regprog == NULL)
2372 {
2373 vim_free(p);
2374 break;
2375 }
2376
2377 didone = FALSE;
2378 for (match = 0; match < ARGCOUNT; ++match)
2379 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2380 (colnr_T)0))
2381 {
2382 didone = TRUE;
2383 vim_free(ARGLIST[match].ae_fname);
2384 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2385 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2386 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002387 if (curwin->w_arg_idx > match)
2388 --curwin->w_arg_idx;
2389 --match;
2390 }
2391
Bram Moolenaar473de612013-06-08 18:19:48 +02002392 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393 vim_free(p);
2394 if (!didone)
2395 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2396 }
2397 ga_clear(&new_ga);
2398 }
2399 else
2400#endif
2401 {
2402 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2403 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2404 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002405 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406 {
2407 EMSG(_(e_nomatch));
2408 return FAIL;
2409 }
2410
2411#ifdef FEAT_LISTCMDS
2412 if (what == AL_ADD)
2413 {
2414 (void)alist_add_list(exp_count, exp_files, after);
2415 vim_free(exp_files);
2416 }
2417 else /* what == AL_SET */
2418#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002419 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420 }
2421
2422 alist_check_arg_idx();
2423
2424 return OK;
2425}
2426
2427/*
2428 * Check the validity of the arg_idx for each other window.
2429 */
2430 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002431alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432{
2433#ifdef FEAT_WINDOWS
2434 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002435 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002436
Bram Moolenaarf740b292006-02-16 22:11:02 +00002437 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438 if (win->w_alist == curwin->w_alist)
2439 check_arg_idx(win);
2440#else
2441 check_arg_idx(curwin);
2442#endif
2443}
2444
2445/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002446 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002447 * index.
2448 */
2449 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002450editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002451{
2452 return !(win->w_arg_idx >= WARGCOUNT(win)
2453 || (win->w_buffer->b_fnum
2454 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2455 && (win->w_buffer->b_ffname == NULL
2456 || !(fullpathcmp(
2457 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2458 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2459}
2460
2461/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002462 * Check if window "win" is editing the w_arg_idx file in its argument list.
2463 */
2464 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002465check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002467 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 {
2469 /* We are not editing the current entry in the argument list.
2470 * Set "arg_had_last" if we are editing the last one. */
2471 win->w_arg_idx_invalid = TRUE;
2472 if (win->w_arg_idx != WARGCOUNT(win) - 1
2473 && arg_had_last == FALSE
2474#ifdef FEAT_WINDOWS
2475 && ALIST(win) == &global_alist
2476#endif
2477 && GARGCOUNT > 0
2478 && win->w_arg_idx < GARGCOUNT
2479 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2480 || (win->w_buffer->b_ffname != NULL
2481 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2482 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2483 arg_had_last = TRUE;
2484 }
2485 else
2486 {
2487 /* We are editing the current entry in the argument list.
2488 * Set "arg_had_last" if it's also the last one */
2489 win->w_arg_idx_invalid = FALSE;
2490 if (win->w_arg_idx == WARGCOUNT(win) - 1
2491#ifdef FEAT_WINDOWS
2492 && win->w_alist == &global_alist
2493#endif
2494 )
2495 arg_had_last = TRUE;
2496 }
2497}
2498
2499/*
2500 * ":args", ":argslocal" and ":argsglobal".
2501 */
2502 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002503ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504{
2505 int i;
2506
2507 if (eap->cmdidx != CMD_args)
2508 {
2509#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2510 alist_unlink(ALIST(curwin));
2511 if (eap->cmdidx == CMD_argglobal)
2512 ALIST(curwin) = &global_alist;
2513 else /* eap->cmdidx == CMD_arglocal */
2514 alist_new();
2515#else
2516 ex_ni(eap);
2517 return;
2518#endif
2519 }
2520
2521 if (!ends_excmd(*eap->arg))
2522 {
2523 /*
2524 * ":args file ..": define new argument list, handle like ":next"
2525 * Also for ":argslocal file .." and ":argsglobal file ..".
2526 */
2527 ex_next(eap);
2528 }
2529 else
2530#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2531 if (eap->cmdidx == CMD_args)
2532#endif
2533 {
2534 /*
2535 * ":args": list arguments.
2536 */
2537 if (ARGCOUNT > 0)
2538 {
2539 /* Overwrite the command, for a short list there is no scrolling
2540 * required and no wait_return(). */
2541 gotocmdline(TRUE);
2542 for (i = 0; i < ARGCOUNT; ++i)
2543 {
2544 if (i == curwin->w_arg_idx)
2545 msg_putchar('[');
2546 msg_outtrans(alist_name(&ARGLIST[i]));
2547 if (i == curwin->w_arg_idx)
2548 msg_putchar(']');
2549 msg_putchar(' ');
2550 }
2551 }
2552 }
2553#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2554 else if (eap->cmdidx == CMD_arglocal)
2555 {
2556 garray_T *gap = &curwin->w_alist->al_ga;
2557
2558 /*
2559 * ":argslocal": make a local copy of the global argument list.
2560 */
2561 if (ga_grow(gap, GARGCOUNT) == OK)
2562 for (i = 0; i < GARGCOUNT; ++i)
2563 if (GARGLIST[i].ae_fname != NULL)
2564 {
2565 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2566 vim_strsave(GARGLIST[i].ae_fname);
2567 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2568 GARGLIST[i].ae_fnum;
2569 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570 }
2571 }
2572#endif
2573}
2574
2575/*
2576 * ":previous", ":sprevious", ":Next" and ":sNext".
2577 */
2578 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002579ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580{
2581 /* If past the last one already, go to the last one. */
2582 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2583 do_argfile(eap, ARGCOUNT - 1);
2584 else
2585 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2586}
2587
2588/*
2589 * ":rewind", ":first", ":sfirst" and ":srewind".
2590 */
2591 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002592ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593{
2594 do_argfile(eap, 0);
2595}
2596
2597/*
2598 * ":last" and ":slast".
2599 */
2600 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002601ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602{
2603 do_argfile(eap, ARGCOUNT - 1);
2604}
2605
2606/*
2607 * ":argument" and ":sargument".
2608 */
2609 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002610ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002611{
2612 int i;
2613
2614 if (eap->addr_count > 0)
2615 i = eap->line2 - 1;
2616 else
2617 i = curwin->w_arg_idx;
2618 do_argfile(eap, i);
2619}
2620
2621/*
2622 * Edit file "argn" of the argument lists.
2623 */
2624 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002625do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626{
2627 int other;
2628 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002629 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630
2631 if (argn < 0 || argn >= ARGCOUNT)
2632 {
2633 if (ARGCOUNT <= 1)
2634 EMSG(_("E163: There is only one file to edit"));
2635 else if (argn < 0)
2636 EMSG(_("E164: Cannot go before first file"));
2637 else
2638 EMSG(_("E165: Cannot go beyond last file"));
2639 }
2640 else
2641 {
2642 setpcmark();
2643#ifdef FEAT_GUI
2644 need_mouse_correct = TRUE;
2645#endif
2646
2647#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002648 /* split window or create new tab page first */
2649 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650 {
2651 if (win_split(0, 0) == FAIL)
2652 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002653 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002654 }
2655 else
2656#endif
2657 {
2658 /*
2659 * if 'hidden' set, only check for changed file when re-editing
2660 * the same buffer
2661 */
2662 other = TRUE;
2663 if (P_HID(curbuf))
2664 {
2665 p = fix_fname(alist_name(&ARGLIST[argn]));
2666 other = otherfile(p);
2667 vim_free(p);
2668 }
2669 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002670 && check_changed(curbuf, CCGD_AW
2671 | (other ? 0 : CCGD_MULTWIN)
2672 | (eap->forceit ? CCGD_FORCEIT : 0)
2673 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674 return;
2675 }
2676
2677 curwin->w_arg_idx = argn;
2678 if (argn == ARGCOUNT - 1
2679#ifdef FEAT_WINDOWS
2680 && curwin->w_alist == &global_alist
2681#endif
2682 )
2683 arg_had_last = TRUE;
2684
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002685 /* Edit the file; always use the last known line number.
2686 * When it fails (e.g. Abort for already edited file) restore the
2687 * argument index. */
2688 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002690 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2691 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002692 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002694 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002695 setmark('\'');
2696 }
2697}
2698
2699/*
2700 * ":next", and commands that behave like it.
2701 */
2702 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002703ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002704{
2705 int i;
2706
2707 /*
2708 * check for changed buffer now, if this fails the argument list is not
2709 * redefined.
2710 */
2711 if ( P_HID(curbuf)
2712 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002713 || !check_changed(curbuf, CCGD_AW
2714 | (eap->forceit ? CCGD_FORCEIT : 0)
2715 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716 {
2717 if (*eap->arg != NUL) /* redefine file list */
2718 {
2719 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2720 return;
2721 i = 0;
2722 }
2723 else
2724 i = curwin->w_arg_idx + (int)eap->line2;
2725 do_argfile(eap, i);
2726 }
2727}
2728
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002729#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730/*
2731 * ":argedit"
2732 */
2733 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002734ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002735{
2736 int fnum;
2737 int i;
2738 char_u *s;
2739
2740 /* Add the argument to the buffer list and get the buffer number. */
2741 fnum = buflist_add(eap->arg, BLN_LISTED);
2742
2743 /* Check if this argument is already in the argument list. */
2744 for (i = 0; i < ARGCOUNT; ++i)
2745 if (ARGLIST[i].ae_fnum == fnum)
2746 break;
2747 if (i == ARGCOUNT)
2748 {
2749 /* Can't find it, add it to the argument list. */
2750 s = vim_strsave(eap->arg);
2751 if (s == NULL)
2752 return;
2753 i = alist_add_list(1, &s,
2754 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2755 if (i < 0)
2756 return;
2757 curwin->w_arg_idx = i;
2758 }
2759
2760 alist_check_arg_idx();
2761
2762 /* Edit the argument. */
2763 do_argfile(eap, i);
2764}
2765
2766/*
2767 * ":argadd"
2768 */
2769 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002770ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002771{
2772 do_arglist(eap->arg, AL_ADD,
2773 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2774#ifdef FEAT_TITLE
2775 maketitle();
2776#endif
2777}
2778
2779/*
2780 * ":argdelete"
2781 */
2782 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002783ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002784{
2785 int i;
2786 int n;
2787
2788 if (eap->addr_count > 0)
2789 {
2790 /* ":1,4argdel": Delete all arguments in the range. */
2791 if (eap->line2 > ARGCOUNT)
2792 eap->line2 = ARGCOUNT;
2793 n = eap->line2 - eap->line1 + 1;
2794 if (*eap->arg != NUL || n <= 0)
2795 EMSG(_(e_invarg));
2796 else
2797 {
2798 for (i = eap->line1; i <= eap->line2; ++i)
2799 vim_free(ARGLIST[i - 1].ae_fname);
2800 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2801 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2802 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002803 if (curwin->w_arg_idx >= eap->line2)
2804 curwin->w_arg_idx -= n;
2805 else if (curwin->w_arg_idx > eap->line1)
2806 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002807 if (ARGCOUNT == 0)
2808 curwin->w_arg_idx = 0;
2809 else if (curwin->w_arg_idx >= ARGCOUNT)
2810 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811 }
2812 }
2813 else if (*eap->arg == NUL)
2814 EMSG(_(e_argreq));
2815 else
2816 do_arglist(eap->arg, AL_DEL, 0);
2817#ifdef FEAT_TITLE
2818 maketitle();
2819#endif
2820}
2821
2822/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002823 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824 */
2825 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002826ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002827{
2828 int i;
2829#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002830 win_T *wp;
2831 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002833 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002834 int next_fnum = 0;
2835#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2836 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002838 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002839#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002840 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002841 int qf_idx;
2842#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843
2844#ifndef FEAT_WINDOWS
2845 if (eap->cmdidx == CMD_windo)
2846 {
2847 ex_ni(eap);
2848 return;
2849 }
2850#endif
2851
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002852#ifndef FEAT_QUICKFIX
2853 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2854 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2855 {
2856 ex_ni(eap);
2857 return;
2858 }
2859#endif
2860
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002862 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002863 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2864 * great speed improvement. */
2865 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002866#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002867#ifdef FEAT_CLIPBOARD
2868 start_global_changes();
2869#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870
2871 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002872 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002874 || !check_changed(curbuf, CCGD_AW
2875 | (eap->forceit ? CCGD_FORCEIT : 0)
2876 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002877 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002878 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002879 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002880#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002881 wp = firstwin;
2882 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002883#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002884 switch (eap->cmdidx)
2885 {
2886#ifdef FEAT_WINDOWS
2887 case CMD_windo:
2888 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2889 i++;
2890 break;
2891 case CMD_tabdo:
2892 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2893 i++;
2894 break;
2895#endif
2896 case CMD_argdo:
2897 i = eap->line1 - 1;
2898 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002899 default:
2900 break;
2901 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902 /* set pcmark now */
2903 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002904 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002905 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002906 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002907 || !buf->b_p_bl); buf = buf->b_next)
2908 if (buf->b_fnum > eap->line2)
2909 {
2910 buf = NULL;
2911 break;
2912 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002913 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002914 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002915 }
2916#ifdef FEAT_QUICKFIX
2917 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2918 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2919 {
2920 qf_size = qf_get_size(eap);
2921 if (qf_size <= 0 || eap->line1 > qf_size)
2922 buf = NULL;
2923 else
2924 {
2925 ex_cc(eap);
2926
2927 buf = curbuf;
2928 i = eap->line1 - 1;
2929 if (eap->addr_count <= 0)
2930 /* default is all the quickfix/location list entries */
2931 eap->line2 = qf_size;
2932 }
2933 }
2934#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935 else
2936 setpcmark();
2937 listcmd_busy = TRUE; /* avoids setting pcmark below */
2938
Bram Moolenaare25bb902015-02-27 20:33:37 +01002939 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940 {
2941 if (eap->cmdidx == CMD_argdo)
2942 {
2943 /* go to argument "i" */
2944 if (i == ARGCOUNT)
2945 break;
2946 /* Don't call do_argfile() when already there, it will try
2947 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002948 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002949 {
2950 /* Clear 'shm' to avoid that the file message overwrites
2951 * any output from the command. */
2952 p_shm_save = vim_strsave(p_shm);
2953 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002955 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2956 vim_free(p_shm_save);
2957 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958 if (curwin->w_arg_idx != i)
2959 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960 }
2961#ifdef FEAT_WINDOWS
2962 else if (eap->cmdidx == CMD_windo)
2963 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002964 /* go to window "wp" */
2965 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002966 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002967 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002968 if (curwin != wp)
2969 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002970 wp = curwin->w_next;
2971 }
2972 else if (eap->cmdidx == CMD_tabdo)
2973 {
2974 /* go to window "tp" */
2975 if (!valid_tabpage(tp))
2976 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002977 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002978 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002979 }
2980#endif
2981 else if (eap->cmdidx == CMD_bufdo)
2982 {
2983 /* Remember the number of the next listed buffer, in case
2984 * ":bwipe" is used or autocommands do something strange. */
2985 next_fnum = -1;
2986 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2987 if (buf->b_p_bl)
2988 {
2989 next_fnum = buf->b_fnum;
2990 break;
2991 }
2992 }
2993
Bram Moolenaara162bc52015-01-07 16:54:21 +01002994 ++i;
2995
Bram Moolenaar071d4272004-06-13 20:20:40 +00002996 /* execute the command */
2997 do_cmdline(eap->arg, eap->getline, eap->cookie,
2998 DOCMD_VERBOSE + DOCMD_NOWAIT);
2999
3000 if (eap->cmdidx == CMD_bufdo)
3001 {
3002 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01003003 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 break;
3005 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02003006 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003007 if (buf->b_fnum == next_fnum)
3008 break;
3009 if (buf == NULL)
3010 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003011
3012 /* Go to the next buffer. Clear 'shm' to avoid that the file
3013 * message overwrites any output from the command. */
3014 p_shm_save = vim_strsave(p_shm);
3015 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003017 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3018 vim_free(p_shm_save);
3019
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003020 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021 if (curbuf->b_fnum != next_fnum)
3022 break;
3023 }
3024
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003025#ifdef FEAT_QUICKFIX
3026 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
3027 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3028 {
3029 if (i >= qf_size || i >= eap->line2)
3030 break;
3031
3032 qf_idx = qf_get_cur_idx(eap);
3033
3034 ex_cnext(eap);
3035
3036 /* If jumping to the next quickfix entry fails, quit here */
3037 if (qf_get_cur_idx(eap) == qf_idx)
3038 break;
3039 }
3040#endif
3041
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042 if (eap->cmdidx == CMD_windo)
3043 {
3044 validate_cursor(); /* cursor may have moved */
3045#ifdef FEAT_SCROLLBIND
3046 /* required when 'scrollbind' has been set */
3047 if (curwin->w_p_scb)
3048 do_check_scrollbind(TRUE);
3049#endif
3050 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01003051
3052#ifdef FEAT_WINDOWS
3053 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
3054 if (i+1 > eap->line2)
3055 break;
3056#endif
3057 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
3058 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059 }
3060 listcmd_busy = FALSE;
3061 }
3062
3063#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003064 if (save_ei != NULL)
3065 {
3066 au_event_restore(save_ei);
3067 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
3068 curbuf->b_fname, TRUE, curbuf);
3069 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02003071#ifdef FEAT_CLIPBOARD
3072 end_global_changes();
3073#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074}
3075
3076/*
3077 * Add files[count] to the arglist of the current window after arg "after".
3078 * The file names in files[count] must have been allocated and are taken over.
3079 * Files[] itself is not taken over.
3080 * Returns index of first added argument. Returns -1 when failed (out of mem).
3081 */
3082 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003083alist_add_list(
3084 int count,
3085 char_u **files,
3086 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087{
3088 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003089 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090
3091 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
3092 {
3093 if (after < 0)
3094 after = 0;
3095 if (after > ARGCOUNT)
3096 after = ARGCOUNT;
3097 if (after < ARGCOUNT)
3098 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
3099 (ARGCOUNT - after) * sizeof(aentry_T));
3100 for (i = 0; i < count; ++i)
3101 {
3102 ARGLIST[after + i].ae_fname = files[i];
3103 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
3104 }
3105 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003106 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3107 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003108 return after;
3109 }
3110
3111 for (i = 0; i < count; ++i)
3112 vim_free(files[i]);
3113 return -1;
3114}
3115
3116#endif /* FEAT_LISTCMDS */
3117
3118#ifdef FEAT_EVAL
3119/*
3120 * ":compiler[!] {name}"
3121 */
3122 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003123ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003124{
3125 char_u *buf;
3126 char_u *old_cur_comp = NULL;
3127 char_u *p;
3128
3129 if (*eap->arg == NUL)
3130 {
3131 /* List all compiler scripts. */
3132 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3133 /* ) keep the indenter happy... */
3134 }
3135 else
3136 {
3137 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3138 if (buf != NULL)
3139 {
3140 if (eap->forceit)
3141 {
3142 /* ":compiler! {name}" sets global options */
3143 do_cmdline_cmd((char_u *)
3144 "command -nargs=* CompilerSet set <args>");
3145 }
3146 else
3147 {
3148 /* ":compiler! {name}" sets local options.
3149 * To remain backwards compatible "current_compiler" is always
3150 * used. A user's compiler plugin may set it, the distributed
3151 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003152 * "b:current_compiler" and restore "current_compiler".
3153 * Explicitly prepend "g:" to make it work in a function. */
3154 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003155 if (old_cur_comp != NULL)
3156 old_cur_comp = vim_strsave(old_cur_comp);
3157 do_cmdline_cmd((char_u *)
3158 "command -nargs=* CompilerSet setlocal <args>");
3159 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003160 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003161 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162
3163 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003164 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3166 vim_free(buf);
3167
3168 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3169
3170 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003171 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003172 if (p != NULL)
3173 set_internal_string_var((char_u *)"b:current_compiler", p);
3174
3175 /* Restore "current_compiler" for ":compiler {name}". */
3176 if (!eap->forceit)
3177 {
3178 if (old_cur_comp != NULL)
3179 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003180 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003181 old_cur_comp);
3182 vim_free(old_cur_comp);
3183 }
3184 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003185 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 }
3187 }
3188 }
3189}
3190#endif
3191
3192/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003193 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003194 */
3195 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003196ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003198 char_u *arg = eap->arg;
3199 char_u *p = skiptowhite(arg);
3200 int len = (int)(p - arg);
3201 int flags = eap->forceit ? DIP_ALL : 0;
3202
3203 if (STRNCMP(arg, "START", len) == 0)
3204 {
3205 flags += DIP_START + DIP_NORTP;
3206 arg = skipwhite(arg + len);
3207 }
3208 else if (STRNCMP(arg, "OPT", len) == 0)
3209 {
3210 flags += DIP_OPT + DIP_NORTP;
3211 arg = skipwhite(arg + len);
3212 }
3213 else if (STRNCMP(arg, "PACK", len) == 0)
3214 {
3215 flags += DIP_START + DIP_OPT + DIP_NORTP;
3216 arg = skipwhite(arg + len);
3217 }
3218 else if (STRNCMP(arg, "ALL", len) == 0)
3219 {
3220 flags += DIP_START + DIP_OPT;
3221 arg = skipwhite(arg + len);
3222 }
3223
3224 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225}
3226
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003228source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003229{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003230 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231}
3232
3233/*
3234 * Source the file "name" from all directories in 'runtimepath'.
3235 * "name" can contain wildcards.
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003236 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
Bram Moolenaar91715872016-03-03 17:13:03 +01003237 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003238 * return FAIL when no file could be sourced, OK otherwise.
3239 */
3240 int
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003241source_runtime(char_u *name, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242{
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003243 return do_in_runtimepath(name, flags, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244}
3245
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003246/*
3247 * Find the file "name" in all directories in "path" and invoke
3248 * "callback(fname, cookie)".
3249 * "name" can contain wildcards.
3250 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3251 * When "flags" has DIP_DIR: find directories instead of files.
3252 * When "flags" has DIP_ERR: give an error message if there is no match.
3253 *
3254 * return FAIL when no file could be sourced, OK otherwise.
3255 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003256 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003257do_in_path(
3258 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003259 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003260 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003261 void (*callback)(char_u *fname, void *ck),
3262 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003263{
3264 char_u *rtp;
3265 char_u *np;
3266 char_u *buf;
3267 char_u *rtp_copy;
3268 char_u *tail;
3269 int num_files;
3270 char_u **files;
3271 int i;
3272 int did_one = FALSE;
3273#ifdef AMIGA
3274 struct Process *proc = (struct Process *)FindTask(0L);
3275 APTR save_winptr = proc->pr_WindowPtr;
3276
3277 /* Avoid a requester here for a volume that doesn't exist. */
3278 proc->pr_WindowPtr = (APTR)-1L;
3279#endif
3280
3281 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3282 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003283 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284 buf = alloc(MAXPATHL);
3285 if (buf != NULL && rtp_copy != NULL)
3286 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003287 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003288 {
3289 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003290 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003291 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003292 verbose_leave();
3293 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003294
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295 /* Loop over all entries in 'runtimepath'. */
3296 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003297 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02003299 size_t buflen;
3300
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301 /* Copy the path from 'runtimepath' to buf[]. */
3302 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02003303 buflen = STRLEN(buf);
3304
3305 /* Skip after or non-after directories. */
3306 if (flags & (DIP_NOAFTER | DIP_AFTER))
3307 {
3308 int is_after = buflen >= 5
3309 && STRCMP(buf + buflen - 5, "after") == 0;
3310
3311 if ((is_after && (flags & DIP_NOAFTER))
3312 || (!is_after && (flags & DIP_AFTER)))
3313 continue;
3314 }
3315
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003316 if (name == NULL)
3317 {
3318 (*callback)(buf, (void *) &cookie);
3319 if (!did_one)
3320 did_one = (cookie == NULL);
3321 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02003322 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003323 {
3324 add_pathsep(buf);
3325 tail = buf + STRLEN(buf);
3326
3327 /* Loop over all patterns in "name" */
3328 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003329 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003330 {
3331 /* Append the pattern from "name" to buf[]. */
3332 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3333 "\t ");
3334
3335 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003336 {
3337 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003338 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003339 verbose_leave();
3340 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341
3342 /* Expand wildcards, invoke the callback for each match. */
3343 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003344 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 {
3346 for (i = 0; i < num_files; ++i)
3347 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003348 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003350 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003351 break;
3352 }
3353 FreeWild(num_files, files);
3354 }
3355 }
3356 }
3357 }
3358 }
3359 vim_free(buf);
3360 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003361 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003362 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003363 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3364
3365 if (flags & DIP_ERR)
3366 EMSG3(_(e_dirnotf), basepath, name);
3367 else if (p_verbose > 0)
3368 {
3369 verbose_enter();
3370 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3371 verbose_leave();
3372 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003373 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003374
3375#ifdef AMIGA
3376 proc->pr_WindowPtr = save_winptr;
3377#endif
3378
3379 return did_one ? OK : FAIL;
3380}
3381
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003382/*
3383 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3384 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003385 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3386 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003387 * Returns OK when at least one match found, FAIL otherwise.
3388 *
3389 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3390 * passed by reference in this case, setting it to NULL indicates that callback
3391 * has done its job.
3392 */
3393 int
3394do_in_runtimepath(
3395 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003396 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003397 void (*callback)(char_u *fname, void *ck),
3398 void *cookie)
3399{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003400 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003401 char_u *s;
3402 int len;
3403 char *start_dir = "pack/*/start/*/%s";
3404 char *opt_dir = "pack/*/opt/*/%s";
3405
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003406 if ((flags & DIP_NORTP) == 0)
3407 done = do_in_path(p_rtp, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003408
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003409 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003410 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003411 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003412 s = alloc(len);
3413 if (s == NULL)
3414 return FAIL;
3415 vim_snprintf((char *)s, len, start_dir, name);
3416 done = do_in_path(p_pp, s, flags, callback, cookie);
3417 vim_free(s);
3418 }
3419
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003420 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003421 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003422 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003423 s = alloc(len);
3424 if (s == NULL)
3425 return FAIL;
3426 vim_snprintf((char *)s, len, opt_dir, name);
3427 done = do_in_path(p_pp, s, flags, callback, cookie);
3428 vim_free(s);
3429 }
3430
3431 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003432}
3433
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003434/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003435 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003436 */
3437 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003438source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003439{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003440 int num_files;
3441 char_u **files;
3442 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003443
Bram Moolenaarf3654822016-03-04 22:12:23 +01003444 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003445 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003446 for (i = 0; i < num_files; ++i)
3447 (void)do_source(files[i], FALSE, DOSO_NONE);
3448 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003449 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003450}
3451
Bram Moolenaar49b27322016-04-05 21:13:00 +02003452/* used for "cookie" of add_pack_plugin() */
3453static int APP_ADD_DIR;
3454static int APP_LOAD;
3455static int APP_BOTH;
3456
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003457 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003458add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003459{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003460 char_u *p4, *p3, *p2, *p1, *p;
3461 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003462 int c;
3463 char_u *new_rtp;
3464 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003465 size_t oldlen;
3466 size_t addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003467 char_u *afterdir;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003468 size_t afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003469 char_u *ffname = fix_fname(fname);
Bram Moolenaarfef524b2016-07-02 22:07:22 +02003470 size_t fname_len;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003471
Bram Moolenaar91715872016-03-03 17:13:03 +01003472 if (ffname == NULL)
3473 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003474 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003475 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003476 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003477 p4 = p3 = p2 = p1 = get_past_head(ffname);
3478 for (p = p1; *p; mb_ptr_adv(p))
3479 if (vim_ispathsep_nocolon(*p))
3480 {
3481 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3482 }
3483
3484 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003485 * rtp/pack/name/start/name
3486 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003487 *
3488 * find the part up to "pack" in 'runtimepath' */
3489 c = *p4;
3490 *p4 = NUL;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003491
3492 /* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3493 fname_len = STRLEN(ffname);
3494 insp = p_rtp;
3495 for (;;)
3496 {
3497 if (vim_fnamencmp(insp, ffname, fname_len) == 0)
3498 break;
3499 insp = vim_strchr(insp, ',');
3500 if (insp == NULL)
3501 break;
3502 ++insp;
3503 }
3504
Bram Moolenaarf3654822016-03-04 22:12:23 +01003505 if (insp == NULL)
3506 /* not found, append at the end */
3507 insp = p_rtp + STRLEN(p_rtp);
3508 else
3509 {
3510 /* append after the matching directory. */
3511 insp += STRLEN(ffname);
3512 while (*insp != NUL && *insp != ',')
3513 ++insp;
3514 }
3515 *p4 = c;
3516
Bram Moolenaara5702442016-05-24 19:37:29 +02003517 /* check if rtp/pack/name/start/name/after exists */
3518 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3519 if (afterdir != NULL && mch_isdir(afterdir))
3520 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3521
Bram Moolenaarb0550662016-05-31 21:37:36 +02003522 oldlen = STRLEN(p_rtp);
3523 addlen = STRLEN(ffname) + 1; /* add one for comma */
3524 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003525 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003526 goto theend;
3527 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003528 mch_memmove(new_rtp, p_rtp, keep);
3529 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003530 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003531 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003532 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003533 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003534 if (afterlen > 0)
3535 {
3536 STRCAT(new_rtp, ",");
3537 STRCAT(new_rtp, afterdir);
3538 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003539 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3540 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003541 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003542 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003543
Bram Moolenaar49b27322016-04-05 21:13:00 +02003544 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003545 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003546 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003547 static char *ftpat = "%s/ftdetect/*.vim";
3548 int len;
3549 char_u *pat;
3550
3551 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3552 pat = alloc(len);
3553 if (pat == NULL)
3554 goto theend;
3555 vim_snprintf((char *)pat, len, plugpat, ffname);
3556 source_all_matches(pat);
3557
3558#ifdef FEAT_AUTOCMD
3559 {
3560 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3561
3562 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3563 * found when it loads. */
3564 if (cmd != NULL && eval_to_number(cmd) > 0)
3565 {
3566 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3567 vim_snprintf((char *)pat, len, ftpat, ffname);
3568 source_all_matches(pat);
3569 do_cmdline_cmd((char_u *)"augroup END");
3570 }
3571 vim_free(cmd);
3572 }
3573#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003574 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003575 }
3576
3577theend:
3578 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003579}
3580
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003581static int did_source_packages = FALSE;
3582
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003583/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003584 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003585 * Find plugins in the package directories and source them.
Bram Moolenaar66459b72016-08-06 19:01:55 +02003586 * "eap" is NULL when invoked during startup.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003587 */
3588 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003589ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003590{
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003591 if (!did_source_packages || (eap != NULL && eap->forceit))
3592 {
3593 did_source_packages = TRUE;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003594
3595 /* First do a round to add all directories to 'runtimepath', then load
3596 * the plugins. This allows for plugins to use an autoload directory
3597 * of another plugin. */
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003598 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003599 add_pack_plugin, &APP_ADD_DIR);
3600 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3601 add_pack_plugin, &APP_LOAD);
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003602 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003603}
3604
3605/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003606 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003607 */
3608 void
3609ex_packadd(exarg_T *eap)
3610{
3611 static char *plugpat = "pack/*/opt/%s";
3612 int len;
3613 char *pat;
3614
3615 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3616 pat = (char *)alloc(len);
3617 if (pat == NULL)
3618 return;
3619 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003620 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003621 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003622 vim_free(pat);
3623}
3624
Bram Moolenaar071d4272004-06-13 20:20:40 +00003625#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3626/*
3627 * ":options"
3628 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003629 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003630ex_options(
3631 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003632{
3633 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3634}
3635#endif
3636
3637/*
3638 * ":source {fname}"
3639 */
3640 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003641ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003642{
3643#ifdef FEAT_BROWSE
3644 if (cmdmod.browse)
3645 {
3646 char_u *fname = NULL;
3647
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003648 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003649 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3650 if (fname != NULL)
3651 {
3652 cmd_source(fname, eap);
3653 vim_free(fname);
3654 }
3655 }
3656 else
3657#endif
3658 cmd_source(eap->arg, eap);
3659}
3660
3661 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003662cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663{
3664 if (*fname == NUL)
3665 EMSG(_(e_argreq));
3666
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003668 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003669 * Need to execute the commands directly. This is required at least
3670 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671 * - ":g" command busy
3672 * - after ":argdo", ":windo" or ":bufdo"
3673 * - another command follows
3674 * - inside a loop
3675 */
3676 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3677#ifdef FEAT_EVAL
3678 || eap->cstack->cs_idx >= 0
3679#endif
3680 );
3681
3682 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003683 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003684 EMSG2(_(e_notopen), fname);
3685}
3686
3687/*
3688 * ":source" and associated commands.
3689 */
3690/*
3691 * Structure used to store info for each sourced file.
3692 * It is shared between do_source() and getsourceline().
3693 * This is required, because it needs to be handed to do_cmdline() and
3694 * sourcing can be done recursively.
3695 */
3696struct source_cookie
3697{
3698 FILE *fp; /* opened file for sourcing */
3699 char_u *nextline; /* if not NULL: line that was read ahead */
3700 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003701#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003702 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3703 int error; /* TRUE if LF found after CR-LF */
3704#endif
3705#ifdef FEAT_EVAL
3706 linenr_T breakpoint; /* next line with breakpoint or zero */
3707 char_u *fname; /* name of sourced file */
3708 int dbg_tick; /* debug_tick when breakpoint was set */
3709 int level; /* top nesting level of sourced file */
3710#endif
3711#ifdef FEAT_MBYTE
3712 vimconv_T conv; /* type of conversion */
3713#endif
3714};
3715
3716#ifdef FEAT_EVAL
3717/*
3718 * Return the address holding the next breakpoint line for a source cookie.
3719 */
3720 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003721source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003722{
3723 return &((struct source_cookie *)cookie)->breakpoint;
3724}
3725
3726/*
3727 * Return the address holding the debug tick for a source cookie.
3728 */
3729 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003730source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731{
3732 return &((struct source_cookie *)cookie)->dbg_tick;
3733}
3734
3735/*
3736 * Return the nesting level for a source cookie.
3737 */
3738 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003739source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003740{
3741 return ((struct source_cookie *)cookie)->level;
3742}
3743#endif
3744
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003745static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003747#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3748# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003749static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003750
3751/*
3752 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003753 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754 */
3755 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003756fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003757{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003758# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003759 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3760# else
3761 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003762# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003763
3764 if (fd_tmp == -1)
3765 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003766
3767# ifdef HAVE_FD_CLOEXEC
3768 {
3769 int fdflags = fcntl(fd_tmp, F_GETFD);
3770 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003771 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003772 }
3773# endif
3774
Bram Moolenaar071d4272004-06-13 20:20:40 +00003775 return fdopen(fd_tmp, READBIN);
3776}
3777#endif
3778
3779
3780/*
3781 * do_source: Read the file "fname" and execute its lines as EX commands.
3782 *
3783 * This function may be called recursively!
3784 *
3785 * return FAIL if file could not be opened, OK otherwise
3786 */
3787 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003788do_source(
3789 char_u *fname,
3790 int check_other, /* check for .vimrc and _vimrc */
3791 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003792{
3793 struct source_cookie cookie;
3794 char_u *save_sourcing_name;
3795 linenr_T save_sourcing_lnum;
3796 char_u *p;
3797 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003798 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799 int retval = FAIL;
3800#ifdef FEAT_EVAL
3801 scid_T save_current_SID;
3802 static scid_T last_current_SID = 0;
3803 void *save_funccalp;
3804 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003805 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003806# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003807 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 int stat_ok;
3809# endif
3810#endif
3811#ifdef STARTUPTIME
3812 struct timeval tv_rel;
3813 struct timeval tv_start;
3814#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003815#ifdef FEAT_PROFILE
3816 proftime_T wait_start;
3817#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003818
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 if (p == NULL)
3821 return retval;
3822 fname_exp = fix_fname(p);
3823 vim_free(p);
3824 if (fname_exp == NULL)
3825 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826 if (mch_isdir(fname_exp))
3827 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003828 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829 goto theend;
3830 }
3831
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003832#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003833 /* Apply SourceCmd autocommands, they should get the file and source it. */
3834 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3835 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3836 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003837 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003838# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003839 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003840# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003841 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003842# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003843 goto theend;
3844 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003845
3846 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003847 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3848#endif
3849
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003850#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003851 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3852#else
3853 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3854#endif
3855 if (cookie.fp == NULL && check_other)
3856 {
3857 /*
3858 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3859 * and ".exrc" by "_exrc" or vice versa.
3860 */
3861 p = gettail(fname_exp);
3862 if ((*p == '.' || *p == '_')
3863 && (STRICMP(p + 1, "vimrc") == 0
3864 || STRICMP(p + 1, "gvimrc") == 0
3865 || STRICMP(p + 1, "exrc") == 0))
3866 {
3867 if (*p == '_')
3868 *p = '.';
3869 else
3870 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003871#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003872 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3873#else
3874 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3875#endif
3876 }
3877 }
3878
3879 if (cookie.fp == NULL)
3880 {
3881 if (p_verbose > 0)
3882 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003883 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003884 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003885 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003886 else
3887 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003888 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003889 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003890 }
3891 goto theend;
3892 }
3893
3894 /*
3895 * The file exists.
3896 * - In verbose mode, give a message.
3897 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3898 */
3899 if (p_verbose > 1)
3900 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003901 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003902 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003903 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003904 else
3905 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003906 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003907 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003909 if (is_vimrc == DOSO_VIMRC)
3910 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3911 else if (is_vimrc == DOSO_GVIMRC)
3912 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003913
3914#ifdef USE_CRNL
3915 /* If no automatic file format: Set default to CR-NL. */
3916 if (*p_ffs == NUL)
3917 cookie.fileformat = EOL_DOS;
3918 else
3919 cookie.fileformat = EOL_UNKNOWN;
3920 cookie.error = FALSE;
3921#endif
3922
3923#ifdef USE_CR
3924 /* If no automatic file format: Set default to CR. */
3925 if (*p_ffs == NUL)
3926 cookie.fileformat = EOL_MAC;
3927 else
3928 cookie.fileformat = EOL_UNKNOWN;
3929 cookie.error = FALSE;
3930#endif
3931
3932 cookie.nextline = NULL;
3933 cookie.finished = FALSE;
3934
3935#ifdef FEAT_EVAL
3936 /*
3937 * Check if this script has a breakpoint.
3938 */
3939 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3940 cookie.fname = fname_exp;
3941 cookie.dbg_tick = debug_tick;
3942
3943 cookie.level = ex_nesting_level;
3944#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003945
3946 /*
3947 * Keep the sourcing name/lnum, for recursive calls.
3948 */
3949 save_sourcing_name = sourcing_name;
3950 sourcing_name = fname_exp;
3951 save_sourcing_lnum = sourcing_lnum;
3952 sourcing_lnum = 0;
3953
Bram Moolenaar73881402009-02-04 16:50:47 +00003954#ifdef FEAT_MBYTE
3955 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3956
3957 /* Read the first line so we can check for a UTF-8 BOM. */
3958 firstline = getsourceline(0, (void *)&cookie, 0);
3959 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3960 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3961 {
3962 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3963 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3964 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003965 if (p == NULL)
3966 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003967 if (p != NULL)
3968 {
3969 vim_free(firstline);
3970 firstline = p;
3971 }
3972 }
3973#endif
3974
Bram Moolenaar071d4272004-06-13 20:20:40 +00003975#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003976 if (time_fd != NULL)
3977 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003978#endif
3979
3980#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003981# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003982 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003983 prof_child_enter(&wait_start); /* entering a child now */
3984# endif
3985
3986 /* Don't use local function variables, if called from a function.
3987 * Also starts profiling timer for nested script. */
3988 save_funccalp = save_funccal();
3989
Bram Moolenaar071d4272004-06-13 20:20:40 +00003990 /*
3991 * Check if this script was sourced before to finds its SID.
3992 * If it's new, generate a new SID.
3993 */
3994 save_current_SID = current_SID;
3995# ifdef UNIX
3996 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3997# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003998 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3999 {
4000 si = &SCRIPT_ITEM(current_SID);
4001 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002 && (
4003# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00004004 /* Compare dev/ino when possible, it catches symbolic
4005 * links. Also compare file names, the inode may change
4006 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004007 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004008 && (si->sn_dev == st.st_dev
4009 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004010# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004011 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004012 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004013 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014 if (current_SID == 0)
4015 {
4016 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004017 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
4018 == FAIL)
4019 goto almosttheend;
4020 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004021 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00004022 ++script_items.ga_len;
4023 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
4024# ifdef FEAT_PROFILE
4025 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004026# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004028 si = &SCRIPT_ITEM(current_SID);
4029 si->sn_name = fname_exp;
4030 fname_exp = NULL;
4031# ifdef UNIX
4032 if (stat_ok)
4033 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004034 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004035 si->sn_dev = st.st_dev;
4036 si->sn_ino = st.st_ino;
4037 }
4038 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004039 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004040# endif
4041
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042 /* Allocate the local script variables to use for this script. */
4043 new_script_vars(current_SID);
4044 }
4045
Bram Moolenaar05159a02005-02-26 23:04:13 +00004046# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004047 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004048 {
4049 int forceit;
4050
4051 /* Check if we do profiling for this script. */
4052 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
4053 {
4054 script_do_profile(si);
4055 si->sn_pr_force = forceit;
4056 }
4057 if (si->sn_prof_on)
4058 {
4059 ++si->sn_pr_count;
4060 profile_start(&si->sn_pr_start);
4061 profile_zero(&si->sn_pr_children);
4062 }
4063 }
4064# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004065#endif
4066
4067 /*
4068 * Call do_cmdline, which will call getsourceline() to get the lines.
4069 */
Bram Moolenaar73881402009-02-04 16:50:47 +00004070 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004071 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004073
4074#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004075 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004076 {
4077 /* Get "si" again, "script_items" may have been reallocated. */
4078 si = &SCRIPT_ITEM(current_SID);
4079 if (si->sn_prof_on)
4080 {
4081 profile_end(&si->sn_pr_start);
4082 profile_sub_wait(&wait_start, &si->sn_pr_start);
4083 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004084 profile_self(&si->sn_pr_self, &si->sn_pr_start,
4085 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004086 }
4087 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004088#endif
4089
4090 if (got_int)
4091 EMSG(_(e_interr));
4092 sourcing_name = save_sourcing_name;
4093 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094 if (p_verbose > 1)
4095 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004096 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00004097 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004099 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004100 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101 }
4102#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004103 if (time_fd != NULL)
4104 {
4105 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
4106 time_msg((char *)IObuff, &tv_start);
4107 time_pop(&tv_rel);
4108 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004109#endif
4110
4111#ifdef FEAT_EVAL
4112 /*
4113 * After a "finish" in debug mode, need to break at first command of next
4114 * sourced file.
4115 */
4116 if (save_debug_break_level > ex_nesting_level
4117 && debug_break_level == ex_nesting_level)
4118 ++debug_break_level;
4119#endif
4120
Bram Moolenaar05159a02005-02-26 23:04:13 +00004121#ifdef FEAT_EVAL
4122almosttheend:
4123 current_SID = save_current_SID;
4124 restore_funccal(save_funccalp);
4125# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004126 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004127 prof_child_exit(&wait_start); /* leaving a child now */
4128# endif
4129#endif
4130 fclose(cookie.fp);
4131 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004132 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004133#ifdef FEAT_MBYTE
4134 convert_setup(&cookie.conv, NULL, NULL);
4135#endif
4136
Bram Moolenaar071d4272004-06-13 20:20:40 +00004137theend:
4138 vim_free(fname_exp);
4139 return retval;
4140}
4141
4142#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004143
Bram Moolenaar071d4272004-06-13 20:20:40 +00004144/*
4145 * ":scriptnames"
4146 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004147 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004148ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004149{
4150 int i;
4151
Bram Moolenaar05159a02005-02-26 23:04:13 +00004152 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4153 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004154 {
4155 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4156 NameBuff, MAXPATHL, TRUE);
4157 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004158 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159}
4160
4161# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4162/*
4163 * Fix slashes in the list of script names for 'shellslash'.
4164 */
4165 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004166scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167{
4168 int i;
4169
Bram Moolenaar05159a02005-02-26 23:04:13 +00004170 for (i = 1; i <= script_items.ga_len; ++i)
4171 if (SCRIPT_ITEM(i).sn_name != NULL)
4172 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004173}
4174# endif
4175
4176/*
4177 * Get a pointer to a script name. Used for ":verbose set".
4178 */
4179 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004180get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181{
4182 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004183 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004185 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004186 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004187 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004188 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004189 return (char_u *)_("environment variable");
4190 if (id == SID_ERROR)
4191 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004192 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004193}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004194
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004195# if defined(EXITFREE) || defined(PROTO)
4196 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004197free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004198{
4199 int i;
4200
4201 for (i = script_items.ga_len; i > 0; --i)
4202 vim_free(SCRIPT_ITEM(i).sn_name);
4203 ga_clear(&script_items);
4204}
4205# endif
4206
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207#endif
4208
4209#if defined(USE_CR) || defined(PROTO)
4210
4211# if defined(__MSL__) && (__MSL__ >= 22)
4212/*
4213 * Newer version of the Metrowerks library handle DOS and UNIX files
4214 * without help.
4215 * Test with earlier versions, MSL 2.2 is the library supplied with
4216 * Codewarrior Pro 2.
4217 */
4218 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004219fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220{
4221 return fgets(s, n, stream);
4222}
4223# else
4224/*
4225 * Version of fgets() which also works for lines ending in a <CR> only
4226 * (Macintosh format).
4227 * For older versions of the Metrowerks library.
4228 * At least CodeWarrior 9 needed this code.
4229 */
4230 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004231fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004232{
4233 int c = 0;
4234 int char_read = 0;
4235
4236 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4237 {
4238 c = fgetc(stream);
4239 s[char_read++] = c;
4240 /* If the file is in DOS format, we need to skip a NL after a CR. I
4241 * thought it was the other way around, but this appears to work... */
4242 if (c == '\n')
4243 {
4244 c = fgetc(stream);
4245 if (c != '\r')
4246 ungetc(c, stream);
4247 }
4248 }
4249
4250 s[char_read] = 0;
4251 if (char_read == 0)
4252 return NULL;
4253
4254 if (feof(stream) && char_read == 1)
4255 return NULL;
4256
4257 return s;
4258}
4259# endif
4260#endif
4261
4262/*
4263 * Get one full line from a sourced file.
4264 * Called by do_cmdline() when it's called from do_source().
4265 *
4266 * Return a pointer to the line in allocated memory.
4267 * Return NULL for end-of-file or some error.
4268 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004269 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004270getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271{
4272 struct source_cookie *sp = (struct source_cookie *)cookie;
4273 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004274 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004275
4276#ifdef FEAT_EVAL
4277 /* If breakpoints have been added/deleted need to check for it. */
4278 if (sp->dbg_tick < debug_tick)
4279 {
4280 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4281 sp->dbg_tick = debug_tick;
4282 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004283# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004284 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004285 script_line_end();
4286# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287#endif
4288 /*
4289 * Get current line. If there is a read-ahead line, use it, otherwise get
4290 * one now.
4291 */
4292 if (sp->finished)
4293 line = NULL;
4294 else if (sp->nextline == NULL)
4295 line = get_one_sourceline(sp);
4296 else
4297 {
4298 line = sp->nextline;
4299 sp->nextline = NULL;
4300 ++sourcing_lnum;
4301 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004302#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004303 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004304 script_line_start();
4305#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004306
4307 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4308 * contain the 'C' flag. */
4309 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4310 {
4311 /* compensate for the one line read-ahead */
4312 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004313
4314 /* Get the next line and concatenate it when it starts with a
4315 * backslash. We always need to read the next line, keep it in
4316 * sp->nextline. */
4317 sp->nextline = get_one_sourceline(sp);
4318 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004320 garray_T ga;
4321
Bram Moolenaarb549a732012-02-22 18:29:33 +01004322 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004323 ga_concat(&ga, line);
4324 ga_concat(&ga, p + 1);
4325 for (;;)
4326 {
4327 vim_free(sp->nextline);
4328 sp->nextline = get_one_sourceline(sp);
4329 if (sp->nextline == NULL)
4330 break;
4331 p = skipwhite(sp->nextline);
4332 if (*p != '\\')
4333 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004334 /* Adjust the growsize to the current length to speed up
4335 * concatenating many lines. */
4336 if (ga.ga_len > 400)
4337 {
4338 if (ga.ga_len > 8000)
4339 ga.ga_growsize = 8000;
4340 else
4341 ga.ga_growsize = ga.ga_len;
4342 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004343 ga_concat(&ga, p + 1);
4344 }
4345 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004347 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348 }
4349 }
4350
4351#ifdef FEAT_MBYTE
4352 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4353 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004354 char_u *s;
4355
Bram Moolenaar071d4272004-06-13 20:20:40 +00004356 /* Convert the encoding of the script line. */
4357 s = string_convert(&sp->conv, line, NULL);
4358 if (s != NULL)
4359 {
4360 vim_free(line);
4361 line = s;
4362 }
4363 }
4364#endif
4365
4366#ifdef FEAT_EVAL
4367 /* Did we encounter a breakpoint? */
4368 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4369 {
4370 dbg_breakpoint(sp->fname, sourcing_lnum);
4371 /* Find next breakpoint. */
4372 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4373 sp->dbg_tick = debug_tick;
4374 }
4375#endif
4376
4377 return line;
4378}
4379
4380 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004381get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382{
4383 garray_T ga;
4384 int len;
4385 int c;
4386 char_u *buf;
4387#ifdef USE_CRNL
4388 int has_cr; /* CR-LF found */
4389#endif
4390#ifdef USE_CR
4391 char_u *scan;
4392#endif
4393 int have_read = FALSE;
4394
4395 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004396 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397
4398 /*
4399 * Loop until there is a finished line (or end-of-file).
4400 */
4401 sourcing_lnum++;
4402 for (;;)
4403 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004404 /* make room to read at least 120 (more) characters */
4405 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004406 break;
4407 buf = (char_u *)ga.ga_data;
4408
4409#ifdef USE_CR
4410 if (sp->fileformat == EOL_MAC)
4411 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004412 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4413 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414 break;
4415 }
4416 else
4417#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004418 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4419 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004420 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004421 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422#ifdef USE_CRNL
4423 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4424 * CTRL-Z by its own, or after a NL. */
4425 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4426 && sp->fileformat == EOL_DOS
4427 && buf[len - 1] == Ctrl_Z)
4428 {
4429 buf[len - 1] = NUL;
4430 break;
4431 }
4432#endif
4433
4434#ifdef USE_CR
4435 /* If the read doesn't stop on a new line, and there's
4436 * some CR then we assume a Mac format */
4437 if (sp->fileformat == EOL_UNKNOWN)
4438 {
4439 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4440 sp->fileformat = EOL_MAC;
4441 else
4442 sp->fileformat = EOL_UNIX;
4443 }
4444
4445 if (sp->fileformat == EOL_MAC)
4446 {
4447 scan = vim_strchr(buf, '\r');
4448
4449 if (scan != NULL)
4450 {
4451 *scan = '\n';
4452 if (*(scan + 1) != 0)
4453 {
4454 *(scan + 1) = 0;
4455 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4456 }
4457 }
4458 len = STRLEN(buf);
4459 }
4460#endif
4461
4462 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004463 ga.ga_len = len;
4464
4465 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004466 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004467 continue;
4468
4469 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4470 {
4471#ifdef USE_CRNL
4472 has_cr = (len >= 2 && buf[len - 2] == '\r');
4473 if (sp->fileformat == EOL_UNKNOWN)
4474 {
4475 if (has_cr)
4476 sp->fileformat = EOL_DOS;
4477 else
4478 sp->fileformat = EOL_UNIX;
4479 }
4480
4481 if (sp->fileformat == EOL_DOS)
4482 {
4483 if (has_cr) /* replace trailing CR */
4484 {
4485 buf[len - 2] = '\n';
4486 --len;
4487 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 }
4489 else /* lines like ":map xx yy^M" will have failed */
4490 {
4491 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004492 {
4493 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004495 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496 sp->error = TRUE;
4497 sp->fileformat = EOL_UNIX;
4498 }
4499 }
4500#endif
4501 /* The '\n' is escaped if there is an odd number of ^V's just
4502 * before it, first set "c" just before the 'V's and then check
4503 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4504 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4505 ;
4506 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4507 {
4508 sourcing_lnum++;
4509 continue;
4510 }
4511
4512 buf[len - 1] = NUL; /* remove the NL */
4513 }
4514
4515 /*
4516 * Check for ^C here now and then, so recursive :so can be broken.
4517 */
4518 line_breakcheck();
4519 break;
4520 }
4521
4522 if (have_read)
4523 return (char_u *)ga.ga_data;
4524
4525 vim_free(ga.ga_data);
4526 return NULL;
4527}
4528
Bram Moolenaar05159a02005-02-26 23:04:13 +00004529#if defined(FEAT_PROFILE) || defined(PROTO)
4530/*
4531 * Called when starting to read a script line.
4532 * "sourcing_lnum" must be correct!
4533 * When skipping lines it may not actually be executed, but we won't find out
4534 * until later and we need to store the time now.
4535 */
4536 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004537script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004538{
4539 scriptitem_T *si;
4540 sn_prl_T *pp;
4541
4542 if (current_SID <= 0 || current_SID > script_items.ga_len)
4543 return;
4544 si = &SCRIPT_ITEM(current_SID);
4545 if (si->sn_prof_on && sourcing_lnum >= 1)
4546 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004547 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004548 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004549 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004550 si->sn_prl_idx = sourcing_lnum - 1;
4551 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4552 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4553 {
4554 /* Zero counters for a line that was not used before. */
4555 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4556 pp->snp_count = 0;
4557 profile_zero(&pp->sn_prl_total);
4558 profile_zero(&pp->sn_prl_self);
4559 ++si->sn_prl_ga.ga_len;
4560 }
4561 si->sn_prl_execed = FALSE;
4562 profile_start(&si->sn_prl_start);
4563 profile_zero(&si->sn_prl_children);
4564 profile_get_wait(&si->sn_prl_wait);
4565 }
4566}
4567
4568/*
4569 * Called when actually executing a function line.
4570 */
4571 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004572script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004573{
4574 scriptitem_T *si;
4575
4576 if (current_SID <= 0 || current_SID > script_items.ga_len)
4577 return;
4578 si = &SCRIPT_ITEM(current_SID);
4579 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4580 si->sn_prl_execed = TRUE;
4581}
4582
4583/*
4584 * Called when done with a function line.
4585 */
4586 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004587script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004588{
4589 scriptitem_T *si;
4590 sn_prl_T *pp;
4591
4592 if (current_SID <= 0 || current_SID > script_items.ga_len)
4593 return;
4594 si = &SCRIPT_ITEM(current_SID);
4595 if (si->sn_prof_on && si->sn_prl_idx >= 0
4596 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4597 {
4598 if (si->sn_prl_execed)
4599 {
4600 pp = &PRL_ITEM(si, si->sn_prl_idx);
4601 ++pp->snp_count;
4602 profile_end(&si->sn_prl_start);
4603 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004604 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004605 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4606 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004607 }
4608 si->sn_prl_idx = -1;
4609 }
4610}
4611#endif
4612
Bram Moolenaar071d4272004-06-13 20:20:40 +00004613/*
4614 * ":scriptencoding": Set encoding conversion for a sourced script.
4615 * Without the multi-byte feature it's simply ignored.
4616 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004618ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619{
4620#ifdef FEAT_MBYTE
4621 struct source_cookie *sp;
4622 char_u *name;
4623
4624 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4625 {
4626 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4627 return;
4628 }
4629
4630 if (*eap->arg != NUL)
4631 {
4632 name = enc_canonize(eap->arg);
4633 if (name == NULL) /* out of memory */
4634 return;
4635 }
4636 else
4637 name = eap->arg;
4638
4639 /* Setup for conversion from the specified encoding to 'encoding'. */
4640 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4641 convert_setup(&sp->conv, name, p_enc);
4642
4643 if (name != eap->arg)
4644 vim_free(name);
4645#endif
4646}
4647
4648#if defined(FEAT_EVAL) || defined(PROTO)
4649/*
4650 * ":finish": Mark a sourced file as finished.
4651 */
4652 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004653ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654{
4655 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4656 do_finish(eap, FALSE);
4657 else
4658 EMSG(_("E168: :finish used outside of a sourced file"));
4659}
4660
4661/*
4662 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4663 * Also called for a pending finish at the ":endtry" or after returning from
4664 * an extra do_cmdline(). "reanimate" is used in the latter case.
4665 */
4666 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004667do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004668{
4669 int idx;
4670
4671 if (reanimate)
4672 ((struct source_cookie *)getline_cookie(eap->getline,
4673 eap->cookie))->finished = FALSE;
4674
4675 /*
4676 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4677 * not in its finally clause (which then is to be executed next) is found.
4678 * In this case, make the ":finish" pending for execution at the ":endtry".
4679 * Otherwise, finish normally.
4680 */
4681 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4682 if (idx >= 0)
4683 {
4684 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4685 report_make_pending(CSTP_FINISH, NULL);
4686 }
4687 else
4688 ((struct source_cookie *)getline_cookie(eap->getline,
4689 eap->cookie))->finished = TRUE;
4690}
4691
4692
4693/*
4694 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4695 * message for missing ":endif".
4696 * Return FALSE when not sourcing a file.
4697 */
4698 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004699source_finished(
4700 char_u *(*fgetline)(int, void *, int),
4701 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004703 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004704 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004705 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004706}
4707#endif
4708
4709#if defined(FEAT_LISTCMDS) || defined(PROTO)
4710/*
4711 * ":checktime [buffer]"
4712 */
4713 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004714ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004715{
4716 buf_T *buf;
4717 int save_no_check_timestamps = no_check_timestamps;
4718
4719 no_check_timestamps = 0;
4720 if (eap->addr_count == 0) /* default is all buffers */
4721 check_timestamps(FALSE);
4722 else
4723 {
4724 buf = buflist_findnr((int)eap->line2);
4725 if (buf != NULL) /* cannot happen? */
4726 (void)buf_check_timestamp(buf, FALSE);
4727 }
4728 no_check_timestamps = save_no_check_timestamps;
4729}
4730#endif
4731
Bram Moolenaar071d4272004-06-13 20:20:40 +00004732#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4733 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004734# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004735static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004737 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004738get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004740 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004741
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004742 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004743 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004744
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004745# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004746 if (loc != NULL)
4747 {
4748 char_u *p;
4749
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004750 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4751 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004752 p = vim_strchr(loc, '=');
4753 if (p != NULL)
4754 {
4755 loc = ++p;
4756 while (*p != NUL) /* remove trailing newline */
4757 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004758 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759 {
4760 *p = NUL;
4761 break;
4762 }
4763 ++p;
4764 }
4765 }
4766 }
4767# endif
4768
4769 return loc;
4770}
4771#endif
4772
4773
4774#ifdef WIN32
4775/*
4776 * On MS-Windows locale names are strings like "German_Germany.1252", but
4777 * gettext expects "de". Try to translate one into another here for a few
4778 * supported languages.
4779 */
4780 static char_u *
4781gettext_lang(char_u *name)
4782{
4783 int i;
4784 static char *(mtable[]) = {
4785 "afrikaans", "af",
4786 "czech", "cs",
4787 "dutch", "nl",
4788 "german", "de",
4789 "english_united kingdom", "en_GB",
4790 "spanish", "es",
4791 "french", "fr",
4792 "italian", "it",
4793 "japanese", "ja",
4794 "korean", "ko",
4795 "norwegian", "no",
4796 "polish", "pl",
4797 "russian", "ru",
4798 "slovak", "sk",
4799 "swedish", "sv",
4800 "ukrainian", "uk",
4801 "chinese_china", "zh_CN",
4802 "chinese_taiwan", "zh_TW",
4803 NULL};
4804
4805 for (i = 0; mtable[i] != NULL; i += 2)
4806 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004807 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808 return name;
4809}
4810#endif
4811
4812#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4813/*
4814 * Obtain the current messages language. Used to set the default for
4815 * 'helplang'. May return NULL or an empty string.
4816 */
4817 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004818get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004819{
4820 char_u *p;
4821
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004822# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004823# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004824 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004825# else
4826 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004827 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4828 * and LC_MONETARY may be set differently for a Japanese working in the
4829 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004830 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004831# endif
4832# else
4833 p = mch_getenv((char_u *)"LC_ALL");
4834 if (p == NULL || *p == NUL)
4835 {
4836 p = mch_getenv((char_u *)"LC_MESSAGES");
4837 if (p == NULL || *p == NUL)
4838 p = mch_getenv((char_u *)"LANG");
4839 }
4840# endif
4841# ifdef WIN32
4842 p = gettext_lang(p);
4843# endif
4844 return p;
4845}
4846#endif
4847
Bram Moolenaardef9e822004-12-31 20:58:58 +00004848/* Complicated #if; matches with where get_mess_env() is used below. */
4849#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4850 && defined(LC_MESSAGES))) \
4851 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4852 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4853 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004854static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004855
4856/*
4857 * Get the language used for messages from the environment.
4858 */
4859 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004860get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004861{
4862 char_u *p;
4863
4864 p = mch_getenv((char_u *)"LC_ALL");
4865 if (p == NULL || *p == NUL)
4866 {
4867 p = mch_getenv((char_u *)"LC_MESSAGES");
4868 if (p == NULL || *p == NUL)
4869 {
4870 p = mch_getenv((char_u *)"LANG");
4871 if (p != NULL && VIM_ISDIGIT(*p))
4872 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004873# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004875 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004876# endif
4877 }
4878 }
4879 return p;
4880}
4881#endif
4882
4883#if defined(FEAT_EVAL) || defined(PROTO)
4884
4885/*
4886 * Set the "v:lang" variable according to the current locale setting.
4887 * Also do "v:lc_time"and "v:ctype".
4888 */
4889 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004890set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004891{
4892 char_u *loc;
4893
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004894# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004895 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004896# else
4897 /* setlocale() not supported: use the default value */
4898 loc = (char_u *)"C";
4899# endif
4900 set_vim_var_string(VV_CTYPE, loc, -1);
4901
4902 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4903 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004904# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004905 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004906# else
4907 loc = get_mess_env();
4908# endif
4909 set_vim_var_string(VV_LANG, loc, -1);
4910
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004911# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004912 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004913# endif
4914 set_vim_var_string(VV_LC_TIME, loc, -1);
4915}
4916#endif
4917
4918#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4919 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4920/*
4921 * ":language": Set the language (locale).
4922 */
4923 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004924ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004925{
4926 char *loc;
4927 char_u *p;
4928 char_u *name;
4929 int what = LC_ALL;
4930 char *whatstr = "";
4931#ifdef LC_MESSAGES
4932# define VIM_LC_MESSAGES LC_MESSAGES
4933#else
4934# define VIM_LC_MESSAGES 6789
4935#endif
4936
4937 name = eap->arg;
4938
4939 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4940 * Allow abbreviation, but require at least 3 characters to avoid
4941 * confusion with a two letter language name "me" or "ct". */
4942 p = skiptowhite(eap->arg);
4943 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4944 {
4945 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4946 {
4947 what = VIM_LC_MESSAGES;
4948 name = skipwhite(p);
4949 whatstr = "messages ";
4950 }
4951 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4952 {
4953 what = LC_CTYPE;
4954 name = skipwhite(p);
4955 whatstr = "ctype ";
4956 }
4957 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4958 {
4959 what = LC_TIME;
4960 name = skipwhite(p);
4961 whatstr = "time ";
4962 }
4963 }
4964
4965 if (*name == NUL)
4966 {
4967#ifndef LC_MESSAGES
4968 if (what == VIM_LC_MESSAGES)
4969 p = get_mess_env();
4970 else
4971#endif
4972 p = (char_u *)setlocale(what, NULL);
4973 if (p == NULL || *p == NUL)
4974 p = (char_u *)"Unknown";
4975 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4976 }
4977 else
4978 {
4979#ifndef LC_MESSAGES
4980 if (what == VIM_LC_MESSAGES)
4981 loc = "";
4982 else
4983#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004984 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004985 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004986#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4987 /* Make sure strtod() uses a decimal point, not a comma. */
4988 setlocale(LC_NUMERIC, "C");
4989#endif
4990 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004991 if (loc == NULL)
4992 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4993 else
4994 {
4995#ifdef HAVE_NL_MSG_CAT_CNTR
4996 /* Need to do this for GNU gettext, otherwise cached translations
4997 * will be used again. */
4998 extern int _nl_msg_cat_cntr;
4999
5000 ++_nl_msg_cat_cntr;
5001#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00005002 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005003 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
5004
5005 if (what != LC_TIME)
5006 {
5007 /* Tell gettext() what to translate to. It apparently doesn't
5008 * use the currently effective locale. Also do this when
5009 * FEAT_GETTEXT isn't defined, so that shell commands use this
5010 * value. */
5011 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005012 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005013 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02005014
5015 /* Clear $LANGUAGE because GNU gettext uses it. */
5016 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005017# ifdef WIN32
5018 /* Apparently MS-Windows printf() may cause a crash when
5019 * we give it 8-bit text while it's expecting text in the
5020 * current locale. This call avoids that. */
5021 setlocale(LC_CTYPE, "C");
5022# endif
5023 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005024 if (what != LC_CTYPE)
5025 {
5026 char_u *mname;
5027#ifdef WIN32
5028 mname = gettext_lang(name);
5029#else
5030 mname = name;
5031#endif
5032 vim_setenv((char_u *)"LC_MESSAGES", mname);
5033#ifdef FEAT_MULTI_LANG
5034 set_helplang_default(mname);
5035#endif
5036 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005037 }
5038
5039# ifdef FEAT_EVAL
5040 /* Set v:lang, v:lc_time and v:ctype to the final result. */
5041 set_lang_var();
5042# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02005043# ifdef FEAT_TITLE
5044 maketitle();
5045# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005046 }
5047 }
5048}
5049
5050# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005051
5052static char_u **locales = NULL; /* Array of all available locales */
5053static int did_init_locales = FALSE;
5054
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01005055static void init_locales(void);
5056static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005057
5058/*
5059 * Lazy initialization of all available locales.
5060 */
5061 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005062init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005063{
5064 if (!did_init_locales)
5065 {
5066 did_init_locales = TRUE;
5067 locales = find_locales();
5068 }
5069}
5070
5071/* Return an array of strings for all available locales + NULL for the
5072 * last element. Return NULL in case of error. */
5073 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005074find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005075{
5076 garray_T locales_ga;
5077 char_u *loc;
5078
5079 /* Find all available locales by running command "locale -a". If this
5080 * doesn't work we won't have completion. */
5081 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02005082 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005083 if (locale_a == NULL)
5084 return NULL;
5085 ga_init2(&locales_ga, sizeof(char_u *), 20);
5086
5087 /* Transform locale_a string where each locale is separated by "\n"
5088 * into an array of locale strings. */
5089 loc = (char_u *)strtok((char *)locale_a, "\n");
5090
5091 while (loc != NULL)
5092 {
5093 if (ga_grow(&locales_ga, 1) == FAIL)
5094 break;
5095 loc = vim_strsave(loc);
5096 if (loc == NULL)
5097 break;
5098
5099 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
5100 loc = (char_u *)strtok(NULL, "\n");
5101 }
5102 vim_free(locale_a);
5103 if (ga_grow(&locales_ga, 1) == FAIL)
5104 {
5105 ga_clear(&locales_ga);
5106 return NULL;
5107 }
5108 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
5109 return (char_u **)locales_ga.ga_data;
5110}
5111
5112# if defined(EXITFREE) || defined(PROTO)
5113 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005114free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005115{
5116 int i;
5117 if (locales != NULL)
5118 {
5119 for (i = 0; locales[i] != NULL; i++)
5120 vim_free(locales[i]);
5121 vim_free(locales);
5122 locales = NULL;
5123 }
5124}
5125# endif
5126
Bram Moolenaar071d4272004-06-13 20:20:40 +00005127/*
5128 * Function given to ExpandGeneric() to obtain the possible arguments of the
5129 * ":language" command.
5130 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005131 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005132get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005133{
5134 if (idx == 0)
5135 return (char_u *)"messages";
5136 if (idx == 1)
5137 return (char_u *)"ctype";
5138 if (idx == 2)
5139 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005140
5141 init_locales();
5142 if (locales == NULL)
5143 return NULL;
5144 return locales[idx - 3];
5145}
5146
5147/*
5148 * Function given to ExpandGeneric() to obtain the available locales.
5149 */
5150 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005151get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005152{
5153 init_locales();
5154 if (locales == NULL)
5155 return NULL;
5156 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005157}
5158# endif
5159
5160#endif