blob: acaef9fcef4b524963d2d8baa5d004a82d8acd94 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
Bram Moolenaarf1f60f82016-01-16 15:40:53 +010071static int get_maxbacktrace_level(void);
72static void do_setdebugtracelevel(char_u *arg);
73static void do_checkbacktracelevel(void);
74static void do_showbacktrace(char_u *cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +000075
76/*
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
79 */
80 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010081do_debug(char_u *cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +000082{
83 int save_msg_scroll = msg_scroll;
84 int save_State = State;
85 int save_did_emsg = did_emsg;
86 int save_cmd_silent = cmd_silent;
87 int save_msg_silent = msg_silent;
88 int save_emsg_silent = emsg_silent;
89 int save_redir_off = redir_off;
90 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000091 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000092 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 int save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 int n;
95 char_u *cmdline = NULL;
96 char_u *p;
97 char *tail = NULL;
98 static int last_cmd = 0;
99#define CMD_CONT 1
100#define CMD_NEXT 2
101#define CMD_STEP 3
102#define CMD_FINISH 4
103#define CMD_QUIT 5
104#define CMD_INTERRUPT 6
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100105#define CMD_BACKTRACE 7
106#define CMD_FRAME 8
107#define CMD_UP 9
108#define CMD_DOWN 10
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109
110#ifdef ALWAYS_USE_GUI
111 /* Can't do this when there is no terminal for input/output. */
112 if (!gui.in_use)
113 {
114 /* Break as soon as possible. */
115 debug_break_level = 9999;
116 return;
117 }
118#endif
119
120 /* Make sure we are in raw mode and start termcap mode. Might have side
121 * effects... */
122 settmode(TMODE_RAW);
123 starttermcap();
124
125 ++RedrawingDisabled; /* don't redisplay the window */
126 ++no_wait_return; /* don't wait for return */
127 did_emsg = FALSE; /* don't use error from debugged stuff */
128 cmd_silent = FALSE; /* display commands */
129 msg_silent = FALSE; /* display messages */
130 emsg_silent = FALSE; /* display error messages */
131 redir_off = TRUE; /* don't redirect debug commands */
132
133 State = NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134
135 if (!debug_did_msg)
136 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
137 if (sourcing_name != NULL)
138 msg(sourcing_name);
139 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000142 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143
144 /*
145 * Repeat getting a command and executing it.
146 */
147 for (;;)
148 {
149 msg_scroll = TRUE;
150 need_wait_return = FALSE;
Bram Moolenaar85b11762016-02-27 18:13:23 +0100151
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 save_ex_normal_busy = ex_normal_busy;
158 ex_normal_busy = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000160 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 typeahead_saved = TRUE;
163 save_ignore_script = ignore_script;
164 ignore_script = TRUE;
165 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166
Bram Moolenaardc303bc2016-05-17 17:45:38 +0200167 vim_free(cmdline);
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000168 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000170 if (typeahead_saved)
171 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000173 ignore_script = save_ignore_script;
174 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176
177 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100178 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 if (cmdline != NULL)
180 {
181 /* If this is a debug command, set "last_cmd".
182 * If not, reset "last_cmd".
183 * For a blank line use previous command. */
184 p = skipwhite(cmdline);
185 if (*p != NUL)
186 {
187 switch (*p)
188 {
189 case 'c': last_cmd = CMD_CONT;
190 tail = "ont";
191 break;
192 case 'n': last_cmd = CMD_NEXT;
193 tail = "ext";
194 break;
195 case 's': last_cmd = CMD_STEP;
196 tail = "tep";
197 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100198 case 'f':
199 last_cmd = 0;
200 if (p[1] == 'r')
201 {
202 last_cmd = CMD_FRAME;
203 tail = "rame";
204 }
205 else
206 {
207 last_cmd = CMD_FINISH;
208 tail = "inish";
209 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210 break;
211 case 'q': last_cmd = CMD_QUIT;
212 tail = "uit";
213 break;
214 case 'i': last_cmd = CMD_INTERRUPT;
215 tail = "nterrupt";
216 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100217 case 'b': last_cmd = CMD_BACKTRACE;
218 if (p[1] == 't')
219 tail = "t";
220 else
221 tail = "acktrace";
222 break;
223 case 'w': last_cmd = CMD_BACKTRACE;
224 tail = "here";
225 break;
226 case 'u': last_cmd = CMD_UP;
227 tail = "p";
228 break;
229 case 'd': last_cmd = CMD_DOWN;
230 tail = "own";
231 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 default: last_cmd = 0;
233 }
234 if (last_cmd != 0)
235 {
236 /* Check that the tail matches. */
237 ++p;
238 while (*p != NUL && *p == *tail)
239 {
240 ++p;
241 ++tail;
242 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100243 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 last_cmd = 0;
245 }
246 }
247
248 if (last_cmd != 0)
249 {
250 /* Execute debug command: decided where to break next and
251 * return. */
252 switch (last_cmd)
253 {
254 case CMD_CONT:
255 debug_break_level = -1;
256 break;
257 case CMD_NEXT:
258 debug_break_level = ex_nesting_level;
259 break;
260 case CMD_STEP:
261 debug_break_level = 9999;
262 break;
263 case CMD_FINISH:
264 debug_break_level = ex_nesting_level - 1;
265 break;
266 case CMD_QUIT:
267 got_int = TRUE;
268 debug_break_level = -1;
269 break;
270 case CMD_INTERRUPT:
271 got_int = TRUE;
272 debug_break_level = 9999;
273 /* Do not repeat ">interrupt" cmd, continue stepping. */
274 last_cmd = CMD_STEP;
275 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100276 case CMD_BACKTRACE:
277 do_showbacktrace(cmd);
278 continue;
279 case CMD_FRAME:
280 if (*p == NUL)
281 {
282 do_showbacktrace(cmd);
283 }
284 else
285 {
286 p = skipwhite(p);
287 do_setdebugtracelevel(p);
288 }
289 continue;
290 case CMD_UP:
291 debug_backtrace_level++;
292 do_checkbacktracelevel();
293 continue;
294 case CMD_DOWN:
295 debug_backtrace_level--;
296 do_checkbacktracelevel();
297 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100299 /* Going out reset backtrace_level */
300 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301 break;
302 }
303
304 /* don't debug this command */
305 n = debug_break_level;
306 debug_break_level = -1;
307 (void)do_cmdline(cmdline, getexline, NULL,
308 DOCMD_VERBOSE|DOCMD_EXCRESET);
309 debug_break_level = n;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 }
311 lines_left = Rows - 1;
312 }
313 vim_free(cmdline);
314
315 --RedrawingDisabled;
316 --no_wait_return;
317 redraw_all_later(NOT_VALID);
318 need_wait_return = FALSE;
319 msg_scroll = save_msg_scroll;
320 lines_left = Rows - 1;
321 State = save_State;
322 did_emsg = save_did_emsg;
323 cmd_silent = save_cmd_silent;
324 msg_silent = save_msg_silent;
325 emsg_silent = save_emsg_silent;
326 redir_off = save_redir_off;
327
328 /* Only print the message again when typing a command before coming back
329 * here. */
330 debug_did_msg = TRUE;
331}
332
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100333 static int
334get_maxbacktrace_level(void)
335{
336 char *p, *q;
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200337 int maxbacktrace = 0;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100338
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100339 if (sourcing_name != NULL)
340 {
341 p = (char *)sourcing_name;
342 while ((q = strstr(p, "..")) != NULL)
343 {
344 p = q + 2;
345 maxbacktrace++;
346 }
347 }
348 return maxbacktrace;
349}
350
351 static void
352do_setdebugtracelevel(char_u *arg)
353{
354 int level;
355
356 level = atoi((char *)arg);
357 if (*arg == '+' || level < 0)
358 debug_backtrace_level += level;
359 else
360 debug_backtrace_level = level;
361
362 do_checkbacktracelevel();
363}
364
365 static void
366do_checkbacktracelevel(void)
367{
368 if (debug_backtrace_level < 0)
369 {
370 debug_backtrace_level = 0;
371 MSG(_("frame is zero"));
372 }
373 else
374 {
375 int max = get_maxbacktrace_level();
376
377 if (debug_backtrace_level > max)
378 {
379 debug_backtrace_level = max;
380 smsg((char_u *)_("frame at highest level: %d"), max);
381 }
382 }
383}
384
385 static void
386do_showbacktrace(char_u *cmd)
387{
388 char *cur;
389 char *next;
390 int i = 0;
391 int max = get_maxbacktrace_level();
392
393 if (sourcing_name != NULL)
394 {
395 cur = (char *)sourcing_name;
396 while (!got_int)
397 {
398 next = strstr(cur, "..");
399 if (next != NULL)
400 *next = NUL;
401 if (i == max - debug_backtrace_level)
402 smsg((char_u *)"->%d %s", max - i, cur);
403 else
404 smsg((char_u *)" %d %s", max - i, cur);
405 ++i;
406 if (next == NULL)
407 break;
408 *next = '.';
409 cur = next + 2;
410 }
411 }
412 if (sourcing_lnum != 0)
413 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
414 else
415 smsg((char_u *)_("cmd: %s"), cmd);
416}
417
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418/*
419 * ":debug".
420 */
421 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100422ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423{
424 int debug_break_level_save = debug_break_level;
425
426 debug_break_level = 9999;
427 do_cmdline_cmd(eap->arg);
428 debug_break_level = debug_break_level_save;
429}
430
431static char_u *debug_breakpoint_name = NULL;
432static linenr_T debug_breakpoint_lnum;
433
434/*
435 * When debugging or a breakpoint is set on a skipped command, no debug prompt
436 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
437 * debug_skipped_name is then set to the source name in the breakpoint case. If
438 * a skipped command decides itself that a debug prompt should be displayed, it
439 * can do so by calling dbg_check_skipped().
440 */
441static int debug_skipped;
442static char_u *debug_skipped_name;
443
444/*
445 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
446 * at or below the break level. But only when the line is actually
447 * executed. Return TRUE and set breakpoint_name for skipped commands that
448 * decide to execute something themselves.
449 * Called from do_one_cmd() before executing a command.
450 */
451 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100452dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453{
454 char_u *p;
455
456 debug_skipped = FALSE;
457 if (debug_breakpoint_name != NULL)
458 {
459 if (!eap->skip)
460 {
461 /* replace K_SNR with "<SNR>" */
462 if (debug_breakpoint_name[0] == K_SPECIAL
463 && debug_breakpoint_name[1] == KS_EXTRA
464 && debug_breakpoint_name[2] == (int)KE_SNR)
465 p = (char_u *)"<SNR>";
466 else
467 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000468 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
469 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 debug_breakpoint_name + (*p == NUL ? 0 : 3),
471 (long)debug_breakpoint_lnum);
472 debug_breakpoint_name = NULL;
473 do_debug(eap->cmd);
474 }
475 else
476 {
477 debug_skipped = TRUE;
478 debug_skipped_name = debug_breakpoint_name;
479 debug_breakpoint_name = NULL;
480 }
481 }
482 else if (ex_nesting_level <= debug_break_level)
483 {
484 if (!eap->skip)
485 do_debug(eap->cmd);
486 else
487 {
488 debug_skipped = TRUE;
489 debug_skipped_name = NULL;
490 }
491 }
492}
493
494/*
495 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
496 * set. Return TRUE when the debug mode is entered this time.
497 */
498 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100499dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500{
501 int prev_got_int;
502
503 if (debug_skipped)
504 {
505 /*
506 * Save the value of got_int and reset it. We don't want a previous
507 * interruption cause flushing the input buffer.
508 */
509 prev_got_int = got_int;
510 got_int = FALSE;
511 debug_breakpoint_name = debug_skipped_name;
512 /* eap->skip is TRUE */
513 eap->skip = FALSE;
514 (void)dbg_check_breakpoint(eap);
515 eap->skip = TRUE;
516 got_int |= prev_got_int;
517 return TRUE;
518 }
519 return FALSE;
520}
521
522/*
523 * The list of breakpoints: dbg_breakp.
524 * This is a grow-array of structs.
525 */
526struct debuggy
527{
528 int dbg_nr; /* breakpoint number */
529 int dbg_type; /* DBG_FUNC or DBG_FILE */
530 char_u *dbg_name; /* function or file name */
531 regprog_T *dbg_prog; /* regexp program */
532 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534};
535
536static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000537#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
538#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539static int last_breakp = 0; /* nr of last defined breakpoint */
540
Bram Moolenaar05159a02005-02-26 23:04:13 +0000541#ifdef FEAT_PROFILE
542/* Profiling uses file and func names similar to breakpoints. */
543static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
544#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545#define DBG_FUNC 1
546#define DBG_FILE 2
547
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100548static int dbg_parsearg(char_u *arg, garray_T *gap);
549static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550
551/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000552 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
553 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
554 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 * Returns FAIL for failure.
556 */
557 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100558dbg_parsearg(
559 char_u *arg,
560 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561{
562 char_u *p = arg;
563 char_u *q;
564 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000565 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566
Bram Moolenaar05159a02005-02-26 23:04:13 +0000567 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000569 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570
571 /* Find "func" or "file". */
572 if (STRNCMP(p, "func", 4) == 0)
573 bp->dbg_type = DBG_FUNC;
574 else if (STRNCMP(p, "file", 4) == 0)
575 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000576 else if (
577#ifdef FEAT_PROFILE
578 gap != &prof_ga &&
579#endif
580 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000581 {
582 if (curbuf->b_ffname == NULL)
583 {
584 EMSG(_(e_noname));
585 return FAIL;
586 }
587 bp->dbg_type = DBG_FILE;
588 here = TRUE;
589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590 else
591 {
592 EMSG2(_(e_invarg2), p);
593 return FAIL;
594 }
595 p = skipwhite(p + 4);
596
597 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000598 if (here)
599 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000600 else if (
601#ifdef FEAT_PROFILE
602 gap != &prof_ga &&
603#endif
604 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 {
606 bp->dbg_lnum = getdigits(&p);
607 p = skipwhite(p);
608 }
609 else
610 bp->dbg_lnum = 0;
611
612 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000613 if ((!here && *p == NUL)
614 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
616 {
617 EMSG2(_(e_invarg2), arg);
618 return FAIL;
619 }
620
621 if (bp->dbg_type == DBG_FUNC)
622 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000623 else if (here)
624 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 else
626 {
627 /* Expand the file name in the same way as do_source(). This means
628 * doing it twice, so that $DIR/file gets expanded when $DIR is
629 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 if (q == NULL)
632 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 vim_free(q);
635 if (p == NULL)
636 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000637 if (*p != '*')
638 {
639 bp->dbg_name = fix_fname(p);
640 vim_free(p);
641 }
642 else
643 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 }
645
646 if (bp->dbg_name == NULL)
647 return FAIL;
648 return OK;
649}
650
651/*
652 * ":breakadd".
653 */
654 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100655ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656{
657 struct debuggy *bp;
658 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000659 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660
Bram Moolenaar05159a02005-02-26 23:04:13 +0000661 gap = &dbg_breakp;
662#ifdef FEAT_PROFILE
663 if (eap->cmdidx == CMD_profile)
664 gap = &prof_ga;
665#endif
666
667 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000669 bp = &DEBUGGY(gap, gap->ga_len);
670 bp->dbg_forceit = eap->forceit;
671
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
673 if (pat != NULL)
674 {
675 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
676 vim_free(pat);
677 }
678 if (pat == NULL || bp->dbg_prog == NULL)
679 vim_free(bp->dbg_name);
680 else
681 {
682 if (bp->dbg_lnum == 0) /* default line number is 1 */
683 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000684#ifdef FEAT_PROFILE
685 if (eap->cmdidx != CMD_profile)
686#endif
687 {
688 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
689 ++debug_tick;
690 }
691 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 }
693 }
694}
695
696/*
697 * ":debuggreedy".
698 */
699 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100700ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701{
702 if (eap->addr_count == 0 || eap->line2 != 0)
703 debug_greedy = TRUE;
704 else
705 debug_greedy = FALSE;
706}
707
708/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000709 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 */
711 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100712ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713{
714 struct debuggy *bp, *bpi;
715 int nr;
716 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000717 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 int i;
719 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000720 garray_T *gap;
721
722 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000723 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200724 {
725#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000726 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200727#else
728 ex_ni(eap);
729 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000730#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200731 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732
733 if (vim_isdigit(*eap->arg))
734 {
735 /* ":breakdel {nr}" */
736 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000737 for (i = 0; i < gap->ga_len; ++i)
738 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 {
740 todel = i;
741 break;
742 }
743 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000744 else if (*eap->arg == '*')
745 {
746 todel = 0;
747 del_all = TRUE;
748 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 else
750 {
751 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000752 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000754 bp = &DEBUGGY(gap, gap->ga_len);
755 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000757 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 if (bp->dbg_type == bpi->dbg_type
759 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
760 && (bp->dbg_lnum == bpi->dbg_lnum
761 || (bp->dbg_lnum == 0
762 && (best_lnum == 0
763 || bpi->dbg_lnum < best_lnum))))
764 {
765 todel = i;
766 best_lnum = bpi->dbg_lnum;
767 }
768 }
769 vim_free(bp->dbg_name);
770 }
771
772 if (todel < 0)
773 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
774 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000775 {
776 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000777 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000778 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200779 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000780 --gap->ga_len;
781 if (todel < gap->ga_len)
782 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
783 (gap->ga_len - todel) * sizeof(struct debuggy));
784#ifdef FEAT_PROFILE
785 if (eap->cmdidx == CMD_breakdel)
786#endif
787 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000788 if (!del_all)
789 break;
790 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000791
792 /* If all breakpoints were removed clear the array. */
793 if (gap->ga_len == 0)
794 ga_clear(gap);
795 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796}
797
798/*
799 * ":breaklist".
800 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100802ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803{
804 struct debuggy *bp;
805 int i;
806
807 if (dbg_breakp.ga_len == 0)
808 MSG(_("No breakpoints defined"));
809 else
810 for (i = 0; i < dbg_breakp.ga_len; ++i)
811 {
812 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200813 if (bp->dbg_type == DBG_FILE)
814 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 smsg((char_u *)_("%3d %s %s line %ld"),
816 bp->dbg_nr,
817 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200818 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 (long)bp->dbg_lnum);
820 }
821}
822
823/*
824 * Find a breakpoint for a function or sourced file.
825 * Returns line number at which to break; zero when no matching breakpoint.
826 */
827 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100828dbg_find_breakpoint(
829 int file, /* TRUE for a file, FALSE for a function */
830 char_u *fname, /* file or function name */
831 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000833 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
834}
835
836#if defined(FEAT_PROFILE) || defined(PROTO)
837/*
838 * Return TRUE if profiling is on for a function or sourced file.
839 */
840 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100841has_profiling(
842 int file, /* TRUE for a file, FALSE for a function */
843 char_u *fname, /* file or function name */
844 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845{
846 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
847 != (linenr_T)0);
848}
849#endif
850
851/*
852 * Common code for dbg_find_breakpoint() and has_profiling().
853 */
854 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100855debuggy_find(
856 int file, /* TRUE for a file, FALSE for a function */
857 char_u *fname, /* file or function name */
858 linenr_T after, /* after this line number */
859 garray_T *gap, /* either &dbg_breakp or &prof_ga */
860 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 struct debuggy *bp;
863 int i;
864 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 char_u *name = fname;
866 int prev_got_int;
867
Bram Moolenaar05159a02005-02-26 23:04:13 +0000868 /* Return quickly when there are no breakpoints. */
869 if (gap->ga_len == 0)
870 return (linenr_T)0;
871
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 /* Replace K_SNR in function name with "<SNR>". */
873 if (!file && fname[0] == K_SPECIAL)
874 {
875 name = alloc((unsigned)STRLEN(fname) + 3);
876 if (name == NULL)
877 name = fname;
878 else
879 {
880 STRCPY(name, "<SNR>");
881 STRCPY(name + 5, fname + 3);
882 }
883 }
884
Bram Moolenaar05159a02005-02-26 23:04:13 +0000885 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000887 /* Skip entries that are not useful or are for a line that is beyond
888 * an already found breakpoint. */
889 bp = &DEBUGGY(gap, i);
890 if (((bp->dbg_type == DBG_FILE) == file && (
891#ifdef FEAT_PROFILE
892 gap == &prof_ga ||
893#endif
894 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000897 * Save the value of got_int and reset it. We don't want a
898 * previous interruption cancel matching, only hitting CTRL-C
899 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900 */
901 prev_got_int = got_int;
902 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100903 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000904 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000906 if (fp != NULL)
907 *fp = bp->dbg_forceit;
908 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 got_int |= prev_got_int;
910 }
911 }
912 if (name != fname)
913 vim_free(name);
914
915 return lnum;
916}
917
918/*
919 * Called when a breakpoint was encountered.
920 */
921 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100922dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923{
924 /* We need to check if this line is actually executed in do_one_cmd() */
925 debug_breakpoint_name = name;
926 debug_breakpoint_lnum = lnum;
927}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000928
929
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000930# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000931/*
932 * Store the current time in "tm".
933 */
934 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100935profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000936{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000937# ifdef WIN3264
938 QueryPerformanceCounter(tm);
939# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000940 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000941# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000942}
943
944/*
945 * Compute the elapsed time from "tm" till now and store in "tm".
946 */
947 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100948profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000949{
950 proftime_T now;
951
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000952# ifdef WIN3264
953 QueryPerformanceCounter(&now);
954 tm->QuadPart = now.QuadPart - tm->QuadPart;
955# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000956 gettimeofday(&now, NULL);
957 tm->tv_usec = now.tv_usec - tm->tv_usec;
958 tm->tv_sec = now.tv_sec - tm->tv_sec;
959 if (tm->tv_usec < 0)
960 {
961 tm->tv_usec += 1000000;
962 --tm->tv_sec;
963 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000964# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000965}
966
967/*
968 * Subtract the time "tm2" from "tm".
969 */
970 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100971profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000972{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000973# ifdef WIN3264
974 tm->QuadPart -= tm2->QuadPart;
975# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000976 tm->tv_usec -= tm2->tv_usec;
977 tm->tv_sec -= tm2->tv_sec;
978 if (tm->tv_usec < 0)
979 {
980 tm->tv_usec += 1000000;
981 --tm->tv_sec;
982 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000983# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000984}
985
986/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000987 * Return a string that represents the time in "tm".
988 * Uses a static buffer!
989 */
990 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100991profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000992{
993 static char buf[50];
994
995# ifdef WIN3264
996 LARGE_INTEGER fr;
997
998 QueryPerformanceFrequency(&fr);
999 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1000# else
1001 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001002# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001003 return buf;
1004}
1005
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001006# if defined(FEAT_FLOAT) || defined(PROTO)
1007/*
1008 * Return a float that represents the time in "tm".
1009 */
1010 float_T
1011profile_float(proftime_T *tm)
1012{
1013# ifdef WIN3264
1014 LARGE_INTEGER fr;
1015
1016 QueryPerformanceFrequency(&fr);
1017 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
1018# else
1019 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
1020# endif
1021}
1022# endif
1023
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001024/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001025 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001026 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001027 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001028profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001029{
1030 if (msec <= 0) /* no limit */
1031 profile_zero(tm);
1032 else
1033 {
1034# ifdef WIN3264
1035 LARGE_INTEGER fr;
1036
1037 QueryPerformanceCounter(tm);
1038 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001039 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001040# else
1041 long usec;
1042
1043 gettimeofday(tm, NULL);
1044 usec = (long)tm->tv_usec + (long)msec * 1000;
1045 tm->tv_usec = usec % 1000000L;
1046 tm->tv_sec += usec / 1000000L;
1047# endif
1048 }
1049}
1050
1051/*
1052 * Return TRUE if the current time is past "tm".
1053 */
1054 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001055profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001056{
1057 proftime_T now;
1058
1059# ifdef WIN3264
1060 if (tm->QuadPart == 0) /* timer was not set */
1061 return FALSE;
1062 QueryPerformanceCounter(&now);
1063 return (now.QuadPart > tm->QuadPart);
1064# else
1065 if (tm->tv_sec == 0) /* timer was not set */
1066 return FALSE;
1067 gettimeofday(&now, NULL);
1068 return (now.tv_sec > tm->tv_sec
1069 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1070# endif
1071}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001072
1073/*
1074 * Set the time in "tm" to zero.
1075 */
1076 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001077profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001078{
1079# ifdef WIN3264
1080 tm->QuadPart = 0;
1081# else
1082 tm->tv_usec = 0;
1083 tm->tv_sec = 0;
1084# endif
1085}
1086
Bram Moolenaar76929292008-01-06 19:07:36 +00001087# endif /* FEAT_PROFILE || FEAT_RELTIME */
1088
Bram Moolenaar975b5272016-03-15 23:10:59 +01001089# if defined(FEAT_TIMERS) || defined(PROTO)
1090static timer_T *first_timer = NULL;
1091static int last_timer_id = 0;
1092
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001093static timer_T *current_timer = NULL;
1094static int free_current_timer = FALSE;
1095
Bram Moolenaar975b5272016-03-15 23:10:59 +01001096/*
1097 * Insert a timer in the list of timers.
1098 */
1099 static void
1100insert_timer(timer_T *timer)
1101{
1102 timer->tr_next = first_timer;
1103 timer->tr_prev = NULL;
1104 if (first_timer != NULL)
1105 first_timer->tr_prev = timer;
1106 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +02001107 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001108}
1109
1110/*
1111 * Take a timer out of the list of timers.
1112 */
1113 static void
1114remove_timer(timer_T *timer)
1115{
1116 if (timer->tr_prev == NULL)
1117 first_timer = timer->tr_next;
1118 else
1119 timer->tr_prev->tr_next = timer->tr_next;
1120 if (timer->tr_next != NULL)
1121 timer->tr_next->tr_prev = timer->tr_prev;
1122}
1123
1124 static void
1125free_timer(timer_T *timer)
1126{
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001127 if (timer == current_timer)
1128 free_current_timer = TRUE;
1129 else
1130 {
1131 free_callback(timer->tr_callback, timer->tr_partial);
1132 vim_free(timer);
1133 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001134}
1135
1136/*
1137 * Create a timer and return it. NULL if out of memory.
1138 * Caller should set the callback.
1139 */
1140 timer_T *
1141create_timer(long msec, int repeat)
1142{
1143 timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
1144
1145 if (timer == NULL)
1146 return NULL;
1147 timer->tr_id = ++last_timer_id;
1148 insert_timer(timer);
1149 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001150 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001151 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001152
1153 profile_setlimit(msec, &timer->tr_due);
1154 return timer;
1155}
1156
1157/*
1158 * Invoke the callback of "timer".
1159 */
1160 static void
1161timer_callback(timer_T *timer)
1162{
1163 typval_T rettv;
1164 int dummy;
1165 typval_T argv[2];
1166
1167 argv[0].v_type = VAR_NUMBER;
1168 argv[0].vval.v_number = timer->tr_id;
1169 argv[1].v_type = VAR_UNKNOWN;
1170
1171 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
Bram Moolenaardf48fb42016-07-22 21:50:18 +02001172 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar975b5272016-03-15 23:10:59 +01001173 timer->tr_partial, NULL);
1174 clear_tv(&rettv);
1175}
1176
1177/*
1178 * Call timers that are due.
1179 * Return the time in msec until the next timer is due.
1180 */
1181 long
Bram Moolenaarcf089462016-06-12 21:18:43 +02001182check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001183{
1184 timer_T *timer;
1185 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001186 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001187 proftime_T now;
1188 int did_one = FALSE;
1189# ifdef WIN3264
1190 LARGE_INTEGER fr;
1191
1192 QueryPerformanceFrequency(&fr);
1193# endif
1194 while (!got_int)
1195 {
1196 profile_start(&now);
1197 next_due = -1;
1198 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1199 {
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001200 if (timer->tr_paused)
1201 continue;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001202# ifdef WIN3264
1203 this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
1204 / (double)fr.QuadPart) * 1000);
1205# else
1206 this_due = (timer->tr_due.tv_sec - now.tv_sec) * 1000
1207 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1208# endif
1209 if (this_due <= 1)
1210 {
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001211 current_timer = timer;
1212 free_current_timer = FALSE;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001213 timer_callback(timer);
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001214 current_timer = NULL;
1215
Bram Moolenaar975b5272016-03-15 23:10:59 +01001216 did_one = TRUE;
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001217 if (timer->tr_repeat != 0 && !free_current_timer)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001218 {
1219 profile_setlimit(timer->tr_interval, &timer->tr_due);
1220 if (timer->tr_repeat > 0)
1221 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001222 }
1223 else
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001224 {
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001225 remove_timer(timer);
Bram Moolenaara5d41212016-09-02 22:18:49 +02001226 free_timer(timer);
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001227 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001228 /* the callback may do anything, start all over */
1229 break;
1230 }
1231 if (next_due == -1 || next_due > this_due)
1232 next_due = this_due;
1233 }
1234 if (timer == NULL)
1235 break;
1236 }
1237
1238 if (did_one)
1239 redraw_after_callback();
1240
1241 return next_due;
1242}
1243
1244/*
1245 * Find a timer by ID. Returns NULL if not found;
1246 */
1247 timer_T *
1248find_timer(int id)
1249{
1250 timer_T *timer;
1251
1252 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1253 if (timer->tr_id == id)
1254 break;
1255 return timer;
1256}
1257
1258
1259/*
1260 * Stop a timer and delete it.
1261 */
1262 void
1263stop_timer(timer_T *timer)
1264{
1265 remove_timer(timer);
1266 free_timer(timer);
1267}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001268
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001269 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001270stop_all_timers(void)
1271{
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001272 while (first_timer != NULL)
1273 stop_timer(first_timer);
1274}
1275
1276 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001277add_timer_info(typval_T *rettv, timer_T *timer)
1278{
1279 list_T *list = rettv->vval.v_list;
1280 dict_T *dict = dict_alloc();
1281 dictitem_T *di;
1282 long remaining;
1283 proftime_T now;
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001284# ifdef WIN3264
1285 LARGE_INTEGER fr;
1286#endif
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001287
1288 if (dict == NULL)
1289 return;
1290 list_append_dict(list, dict);
1291
1292 dict_add_nr_str(dict, "id", (long)timer->tr_id, NULL);
1293 dict_add_nr_str(dict, "time", (long)timer->tr_interval, NULL);
1294
1295 profile_start(&now);
1296# ifdef WIN3264
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001297 QueryPerformanceFrequency(&fr);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001298 remaining = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
1299 / (double)fr.QuadPart) * 1000);
1300# else
1301 remaining = (timer->tr_due.tv_sec - now.tv_sec) * 1000
1302 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1303# endif
1304 dict_add_nr_str(dict, "remaining", (long)remaining, NULL);
1305
1306 dict_add_nr_str(dict, "repeat",
1307 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1), NULL);
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001308 dict_add_nr_str(dict, "paused", (long)(timer->tr_paused), NULL);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001309
1310 di = dictitem_alloc((char_u *)"callback");
1311 if (di != NULL)
1312 {
1313 if (dict_add(dict, di) == FAIL)
1314 vim_free(di);
1315 else if (timer->tr_partial != NULL)
1316 {
1317 di->di_tv.v_type = VAR_PARTIAL;
1318 di->di_tv.vval.v_partial = timer->tr_partial;
1319 ++timer->tr_partial->pt_refcount;
1320 }
1321 else
1322 {
1323 di->di_tv.v_type = VAR_FUNC;
1324 di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
1325 }
1326 di->di_tv.v_lock = 0;
1327 }
1328}
1329
1330 void
1331add_timer_info_all(typval_T *rettv)
1332{
1333 timer_T *timer;
1334
1335 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1336 add_timer_info(rettv, timer);
1337}
1338
Bram Moolenaare3188e22016-05-31 21:13:04 +02001339/*
1340 * Mark references in partials of timers.
1341 */
1342 int
1343set_ref_in_timer(int copyID)
1344{
1345 int abort = FALSE;
1346 timer_T *timer;
1347 typval_T tv;
1348
1349 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1350 {
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +02001351 if (timer->tr_partial != NULL)
1352 {
1353 tv.v_type = VAR_PARTIAL;
1354 tv.vval.v_partial = timer->tr_partial;
1355 }
1356 else
1357 {
1358 tv.v_type = VAR_FUNC;
1359 tv.vval.v_string = timer->tr_callback;
1360 }
Bram Moolenaare3188e22016-05-31 21:13:04 +02001361 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1362 }
1363 return abort;
1364}
Bram Moolenaar623e2632016-07-30 22:47:56 +02001365
1366# if defined(EXITFREE) || defined(PROTO)
1367 void
1368timer_free_all()
1369{
1370 timer_T *timer;
1371
1372 while (first_timer != NULL)
1373 {
1374 timer = first_timer;
1375 remove_timer(timer);
1376 free_timer(timer);
1377 }
1378}
1379# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +01001380# endif
1381
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001382#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1383# if defined(HAVE_MATH_H)
1384# include <math.h>
1385# endif
1386
1387/*
1388 * Divide the time "tm" by "count" and store in "tm2".
1389 */
1390 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001391profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001392{
1393 if (count == 0)
1394 profile_zero(tm2);
1395 else
1396 {
1397# ifdef WIN3264
1398 tm2->QuadPart = tm->QuadPart / count;
1399# else
1400 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1401
1402 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001403 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001404# endif
1405 }
1406}
1407#endif
1408
Bram Moolenaar76929292008-01-06 19:07:36 +00001409# if defined(FEAT_PROFILE) || defined(PROTO)
1410/*
1411 * Functions for profiling.
1412 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001413static void script_do_profile(scriptitem_T *si);
1414static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001415static proftime_T prof_wait_time;
1416
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001417/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001418 * Add the time "tm2" to "tm".
1419 */
1420 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001421profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001422{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001423# ifdef WIN3264
1424 tm->QuadPart += tm2->QuadPart;
1425# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001426 tm->tv_usec += tm2->tv_usec;
1427 tm->tv_sec += tm2->tv_sec;
1428 if (tm->tv_usec >= 1000000)
1429 {
1430 tm->tv_usec -= 1000000;
1431 ++tm->tv_sec;
1432 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001433# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001434}
1435
1436/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001437 * Add the "self" time from the total time and the children's time.
1438 */
1439 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001440profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001441{
1442 /* Check that the result won't be negative. Can happen with recursive
1443 * calls. */
1444#ifdef WIN3264
1445 if (total->QuadPart <= children->QuadPart)
1446 return;
1447#else
1448 if (total->tv_sec < children->tv_sec
1449 || (total->tv_sec == children->tv_sec
1450 && total->tv_usec <= children->tv_usec))
1451 return;
1452#endif
1453 profile_add(self, total);
1454 profile_sub(self, children);
1455}
1456
1457/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001458 * Get the current waittime.
1459 */
1460 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001461profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001462{
1463 *tm = prof_wait_time;
1464}
1465
1466/*
1467 * Subtract the passed waittime since "tm" from "tma".
1468 */
1469 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001470profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001471{
1472 proftime_T tm3 = prof_wait_time;
1473
1474 profile_sub(&tm3, tm);
1475 profile_sub(tma, &tm3);
1476}
1477
1478/*
1479 * Return TRUE if "tm1" and "tm2" are equal.
1480 */
1481 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001482profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001483{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001484# ifdef WIN3264
1485 return (tm1->QuadPart == tm2->QuadPart);
1486# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001487 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001488# endif
1489}
1490
1491/*
1492 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1493 */
1494 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001495profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001496{
1497# ifdef WIN3264
1498 return (int)(tm2->QuadPart - tm1->QuadPart);
1499# else
1500 if (tm1->tv_sec == tm2->tv_sec)
1501 return tm2->tv_usec - tm1->tv_usec;
1502 return tm2->tv_sec - tm1->tv_sec;
1503# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001504}
1505
Bram Moolenaar05159a02005-02-26 23:04:13 +00001506static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001507static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001508
1509/*
1510 * ":profile cmd args"
1511 */
1512 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001513ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001514{
1515 char_u *e;
1516 int len;
1517
1518 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001519 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001520 e = skipwhite(e);
1521
1522 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1523 {
1524 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001525 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001526 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001527 profile_zero(&prof_wait_time);
1528 set_vim_var_nr(VV_PROFILING, 1L);
1529 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001530 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001531 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001532 else if (STRCMP(eap->arg, "pause") == 0)
1533 {
1534 if (do_profiling == PROF_YES)
1535 profile_start(&pause_time);
1536 do_profiling = PROF_PAUSED;
1537 }
1538 else if (STRCMP(eap->arg, "continue") == 0)
1539 {
1540 if (do_profiling == PROF_PAUSED)
1541 {
1542 profile_end(&pause_time);
1543 profile_add(&prof_wait_time, &pause_time);
1544 }
1545 do_profiling = PROF_YES;
1546 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001547 else
1548 {
1549 /* The rest is similar to ":breakadd". */
1550 ex_breakadd(eap);
1551 }
1552}
1553
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001554/* Command line expansion for :profile. */
1555static enum
1556{
1557 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001558 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001559} pexpand_what;
1560
1561static char *pexpand_cmds[] = {
1562 "start",
1563#define PROFCMD_START 0
1564 "pause",
1565#define PROFCMD_PAUSE 1
1566 "continue",
1567#define PROFCMD_CONTINUE 2
1568 "func",
1569#define PROFCMD_FUNC 3
1570 "file",
1571#define PROFCMD_FILE 4
1572 NULL
1573#define PROFCMD_LAST 5
1574};
1575
1576/*
1577 * Function given to ExpandGeneric() to obtain the profile command
1578 * specific expansion.
1579 */
1580 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001581get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001582{
1583 switch (pexpand_what)
1584 {
1585 case PEXP_SUBCMD:
1586 return (char_u *)pexpand_cmds[idx];
1587 /* case PEXP_FUNC: TODO */
1588 default:
1589 return NULL;
1590 }
1591}
1592
1593/*
1594 * Handle command line completion for :profile command.
1595 */
1596 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001597set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001598{
1599 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001600
1601 /* Default: expand subcommands. */
1602 xp->xp_context = EXPAND_PROFILE;
1603 pexpand_what = PEXP_SUBCMD;
1604 xp->xp_pattern = arg;
1605
1606 end_subcmd = skiptowhite(arg);
1607 if (*end_subcmd == NUL)
1608 return;
1609
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001610 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001611 {
1612 xp->xp_context = EXPAND_FILES;
1613 xp->xp_pattern = skipwhite(end_subcmd);
1614 return;
1615 }
1616
1617 /* TODO: expand function names after "func" */
1618 xp->xp_context = EXPAND_NOTHING;
1619}
1620
Bram Moolenaar05159a02005-02-26 23:04:13 +00001621/*
1622 * Dump the profiling info.
1623 */
1624 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001625profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001626{
1627 FILE *fd;
1628
1629 if (profile_fname != NULL)
1630 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001631 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001632 if (fd == NULL)
1633 EMSG2(_(e_notopen), profile_fname);
1634 else
1635 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001636 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001637 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001638 fclose(fd);
1639 }
1640 }
1641}
1642
1643/*
1644 * Start profiling script "fp".
1645 */
1646 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001647script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001648{
1649 si->sn_pr_count = 0;
1650 profile_zero(&si->sn_pr_total);
1651 profile_zero(&si->sn_pr_self);
1652
1653 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1654 si->sn_prl_idx = -1;
1655 si->sn_prof_on = TRUE;
1656 si->sn_pr_nest = 0;
1657}
1658
1659/*
1660 * save time when starting to invoke another script or function.
1661 */
1662 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001663script_prof_save(
1664 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001665{
1666 scriptitem_T *si;
1667
1668 if (current_SID > 0 && current_SID <= script_items.ga_len)
1669 {
1670 si = &SCRIPT_ITEM(current_SID);
1671 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1672 profile_start(&si->sn_pr_child);
1673 }
1674 profile_get_wait(tm);
1675}
1676
1677/*
1678 * Count time spent in children after invoking another script or function.
1679 */
1680 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001681script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001682{
1683 scriptitem_T *si;
1684
1685 if (current_SID > 0 && current_SID <= script_items.ga_len)
1686 {
1687 si = &SCRIPT_ITEM(current_SID);
1688 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1689 {
1690 profile_end(&si->sn_pr_child);
1691 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1692 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1693 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1694 }
1695 }
1696}
1697
1698static proftime_T inchar_time;
1699
1700/*
1701 * Called when starting to wait for the user to type a character.
1702 */
1703 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001704prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001705{
1706 profile_start(&inchar_time);
1707}
1708
1709/*
1710 * Called when finished waiting for the user to type a character.
1711 */
1712 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001713prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001714{
1715 profile_end(&inchar_time);
1716 profile_add(&prof_wait_time, &inchar_time);
1717}
1718
1719/*
1720 * Dump the profiling results for all scripts in file "fd".
1721 */
1722 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001723script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001724{
1725 int id;
1726 scriptitem_T *si;
1727 int i;
1728 FILE *sfd;
1729 sn_prl_T *pp;
1730
1731 for (id = 1; id <= script_items.ga_len; ++id)
1732 {
1733 si = &SCRIPT_ITEM(id);
1734 if (si->sn_prof_on)
1735 {
1736 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1737 if (si->sn_pr_count == 1)
1738 fprintf(fd, "Sourced 1 time\n");
1739 else
1740 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1741 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1742 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1743 fprintf(fd, "\n");
1744 fprintf(fd, "count total (s) self (s)\n");
1745
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001746 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001747 if (sfd == NULL)
1748 fprintf(fd, "Cannot open file!\n");
1749 else
1750 {
1751 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1752 {
1753 if (vim_fgets(IObuff, IOSIZE, sfd))
1754 break;
1755 pp = &PRL_ITEM(si, i);
1756 if (pp->snp_count > 0)
1757 {
1758 fprintf(fd, "%5d ", pp->snp_count);
1759 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1760 fprintf(fd, " ");
1761 else
1762 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1763 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1764 }
1765 else
1766 fprintf(fd, " ");
1767 fprintf(fd, "%s", IObuff);
1768 }
1769 fclose(sfd);
1770 }
1771 fprintf(fd, "\n");
1772 }
1773 }
1774}
1775
1776/*
1777 * Return TRUE when a function defined in the current script should be
1778 * profiled.
1779 */
1780 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001781prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001782{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001783 if (current_SID > 0)
1784 return SCRIPT_ITEM(current_SID).sn_pr_force;
1785 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001786}
1787
1788# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789#endif
1790
1791/*
1792 * If 'autowrite' option set, try to write the file.
1793 * Careful: autocommands may make "buf" invalid!
1794 *
1795 * return FAIL for failure, OK otherwise
1796 */
1797 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001798autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001799{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001800 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001801 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001802
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803 if (!(p_aw || p_awa) || !p_write
1804#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001805 /* never autowrite a "nofile" or "nowrite" buffer */
1806 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001807#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001808 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001810 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001811 r = buf_write_all(buf, forceit);
1812
1813 /* Writing may succeed but the buffer still changed, e.g., when there is a
1814 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001815 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001816 r = FAIL;
1817 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818}
1819
1820/*
1821 * flush all buffers, except the ones that are readonly
1822 */
1823 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001824autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001825{
1826 buf_T *buf;
1827
1828 if (!(p_aw || p_awa) || !p_write)
1829 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001830 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831 if (bufIsChanged(buf) && !buf->b_p_ro)
1832 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001833#ifdef FEAT_AUTOCMD
1834 bufref_T bufref;
1835
1836 set_bufref(&bufref, buf);
1837#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 (void)buf_write_all(buf, FALSE);
1839#ifdef FEAT_AUTOCMD
1840 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001841 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001842 buf = firstbuf;
1843#endif
1844 }
1845}
1846
1847/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001848 * Return TRUE if buffer was changed and cannot be abandoned.
1849 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001852check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001854 int forceit = (flags & CCGD_FORCEIT);
1855#ifdef FEAT_AUTOCMD
1856 bufref_T bufref;
1857
1858 set_bufref(&bufref, buf);
1859#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001860
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861 if ( !forceit
1862 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001863 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1864 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865 {
1866#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1867 if ((p_confirm || cmdmod.confirm) && p_write)
1868 {
1869 buf_T *buf2;
1870 int count = 0;
1871
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001872 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001873 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874 if (bufIsChanged(buf2)
1875 && (buf2->b_ffname != NULL
1876# ifdef FEAT_BROWSE
1877 || cmdmod.browse
1878# endif
1879 ))
1880 ++count;
1881# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001882 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 /* Autocommand deleted buffer, oops! It's not changed now. */
1884 return FALSE;
1885# endif
1886 dialog_changed(buf, count > 1);
1887# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001888 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 /* Autocommand deleted buffer, oops! It's not changed now. */
1890 return FALSE;
1891# endif
1892 return bufIsChanged(buf);
1893 }
1894#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001895 if (flags & CCGD_EXCMD)
1896 EMSG(_(e_nowrtmsg));
1897 else
1898 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 return TRUE;
1900 }
1901 return FALSE;
1902}
1903
1904#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1905
1906#if defined(FEAT_BROWSE) || defined(PROTO)
1907/*
1908 * When wanting to write a file without a file name, ask the user for a name.
1909 */
1910 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001911browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912{
1913 if (buf->b_fname == NULL)
1914 {
1915 char_u *fname;
1916
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001917 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1918 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919 if (fname != NULL)
1920 {
1921 if (setfname(buf, fname, NULL, TRUE) == OK)
1922 buf->b_flags |= BF_NOTEDITED;
1923 vim_free(fname);
1924 }
1925 }
1926}
1927#endif
1928
1929/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001930 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 * Must check 'write' option first!
1932 */
1933 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001934dialog_changed(
1935 buf_T *buf,
1936 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001938 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939 int ret;
1940 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001941 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001943 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944 (buf->b_fname != NULL) ?
1945 buf->b_fname : (char_u *)_("Untitled"));
1946 if (checkall)
1947 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1948 else
1949 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1950
Bram Moolenaar8218f602012-04-25 17:32:18 +02001951 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1952 * function. */
1953 ea.append = ea.forceit = FALSE;
1954
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955 if (ret == VIM_YES)
1956 {
1957#ifdef FEAT_BROWSE
1958 /* May get file name, when there is none */
1959 browse_save_fname(buf);
1960#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001961 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1962 buf->b_fname, buf->b_ffname, FALSE) == OK)
1963 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001964 (void)buf_write_all(buf, FALSE);
1965 }
1966 else if (ret == VIM_NO)
1967 {
1968 unchanged(buf, TRUE);
1969 }
1970 else if (ret == VIM_ALL)
1971 {
1972 /*
1973 * Write all modified files that can be written.
1974 * Skip readonly buffers, these need to be confirmed
1975 * individually.
1976 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001977 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001978 {
1979 if (bufIsChanged(buf2)
1980 && (buf2->b_ffname != NULL
1981#ifdef FEAT_BROWSE
1982 || cmdmod.browse
1983#endif
1984 )
1985 && !buf2->b_p_ro)
1986 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001987#ifdef FEAT_AUTOCMD
1988 bufref_T bufref;
1989
1990 set_bufref(&bufref, buf2);
1991#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992#ifdef FEAT_BROWSE
1993 /* May get file name, when there is none */
1994 browse_save_fname(buf2);
1995#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001996 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1997 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1998 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999 (void)buf_write_all(buf2, FALSE);
2000#ifdef FEAT_AUTOCMD
2001 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002002 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002003 buf2 = firstbuf;
2004#endif
2005 }
2006 }
2007 }
2008 else if (ret == VIM_DISCARDALL)
2009 {
2010 /*
2011 * mark all buffers as unchanged
2012 */
Bram Moolenaar29323592016-07-24 22:04:11 +02002013 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002014 unchanged(buf2, TRUE);
2015 }
2016}
2017#endif
2018
2019/*
2020 * Return TRUE if the buffer "buf" can be abandoned, either by making it
2021 * hidden, autowriting it or unloading it.
2022 */
2023 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002024can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025{
2026 return ( P_HID(buf)
2027 || !bufIsChanged(buf)
2028 || buf->b_nwindows > 1
2029 || autowrite(buf, forceit) == OK
2030 || forceit);
2031}
2032
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002033static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002034
2035/*
2036 * Add a buffer number to "bufnrs", unless it's already there.
2037 */
2038 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002039add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002040{
2041 int i;
2042
2043 for (i = 0; i < *bufnump; ++i)
2044 if (bufnrs[i] == nr)
2045 return;
2046 bufnrs[*bufnump] = nr;
2047 *bufnump = *bufnump + 1;
2048}
2049
Bram Moolenaar071d4272004-06-13 20:20:40 +00002050/*
2051 * Return TRUE if any buffer was changed and cannot be abandoned.
2052 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01002053 * When "unload" is true the current buffer is unloaded instead of making it
2054 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002055 */
2056 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002057check_changed_any(
2058 int hidden, /* Only check hidden buffers */
2059 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002061 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062 buf_T *buf;
2063 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002064 int i;
2065 int bufnum = 0;
2066 int bufcount = 0;
2067 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002069 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002070 win_T *wp;
2071#endif
2072
Bram Moolenaar29323592016-07-24 22:04:11 +02002073 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002074 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002076 if (bufcount == 0)
2077 return FALSE;
2078
2079 bufnrs = (int *)alloc(sizeof(int) * bufcount);
2080 if (bufnrs == NULL)
2081 return FALSE;
2082
2083 /* curbuf */
2084 bufnrs[bufnum++] = curbuf->b_fnum;
2085#ifdef FEAT_WINDOWS
2086 /* buf in curtab */
2087 FOR_ALL_WINDOWS(wp)
2088 if (wp->w_buffer != curbuf)
2089 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2090
2091 /* buf in other tab */
Bram Moolenaar29323592016-07-24 22:04:11 +02002092 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002093 if (tp != curtab)
2094 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
2095 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2096#endif
2097 /* any other buf */
Bram Moolenaar29323592016-07-24 22:04:11 +02002098 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002099 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
2100
2101 for (i = 0; i < bufnum; ++i)
2102 {
2103 buf = buflist_findnr(bufnrs[i]);
2104 if (buf == NULL)
2105 continue;
2106 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
2107 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002108 bufref_T bufref;
2109
2110 set_bufref(&bufref, buf);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002111 /* Try auto-writing the buffer. If this fails but the buffer no
2112 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002113 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
2114 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002115 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002116 break; /* didn't save - still changes */
2117 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002118 }
2119
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002120 if (i >= bufnum)
2121 goto theend;
2122
2123 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124 exiting = FALSE;
2125#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2126 /*
2127 * When ":confirm" used, don't give an error message.
2128 */
2129 if (!(p_confirm || cmdmod.confirm))
2130#endif
2131 {
2132 /* There must be a wait_return for this message, do_buffer()
2133 * may cause a redraw. But wait_return() is a no-op when vgetc()
2134 * is busy (Quit used from window menu), then make sure we don't
2135 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002136 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137 {
2138 msg_row = cmdline_row;
2139 msg_col = 0;
2140 msg_didout = FALSE;
2141 }
2142 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002143 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002144 {
2145 save = no_wait_return;
2146 no_wait_return = FALSE;
2147 wait_return(FALSE);
2148 no_wait_return = save;
2149 }
2150 }
2151
2152#ifdef FEAT_WINDOWS
2153 /* Try to find a window that contains the buffer. */
2154 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002155 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002156 if (wp->w_buffer == buf)
2157 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002158# ifdef FEAT_AUTOCMD
2159 bufref_T bufref;
2160
2161 set_bufref(&bufref, buf);
2162# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002163 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164# ifdef FEAT_AUTOCMD
2165 /* Paranoia: did autocms wipe out the buffer with changes? */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002166 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002167 {
2168 goto theend;
2169 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002171 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002173buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002174#endif
2175
2176 /* Open the changed buffer in the current window. */
2177 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002178 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002179
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002180theend:
2181 vim_free(bufnrs);
2182 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183}
2184
2185/*
2186 * return FAIL if there is no file name, OK if there is one
2187 * give error message for FAIL
2188 */
2189 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002190check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002191{
2192 if (curbuf->b_ffname == NULL)
2193 {
2194 EMSG(_(e_noname));
2195 return FAIL;
2196 }
2197 return OK;
2198}
2199
2200/*
2201 * flush the contents of a buffer, unless it has no file name
2202 *
2203 * return FAIL for failure, OK otherwise
2204 */
2205 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002206buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002207{
2208 int retval;
2209#ifdef FEAT_AUTOCMD
2210 buf_T *old_curbuf = curbuf;
2211#endif
2212
2213 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2214 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2215 FALSE, forceit, TRUE, FALSE));
2216#ifdef FEAT_AUTOCMD
2217 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002218 {
2219 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002221 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002222#endif
2223 return retval;
2224}
2225
2226/*
2227 * Code to handle the argument list.
2228 */
2229
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002230static char_u *do_one_arg(char_u *str);
2231static int do_arglist(char_u *str, int what, int after);
2232static void alist_check_arg_idx(void);
2233static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002234#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002235static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002236#endif
2237#define AL_SET 1
2238#define AL_ADD 2
2239#define AL_DEL 3
2240
Bram Moolenaar071d4272004-06-13 20:20:40 +00002241/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002242 * Isolate one argument, taking backticks.
2243 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002244 * Return a pointer to the start of the next argument.
2245 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002246 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002247do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248{
2249 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002250 int inbacktick;
2251
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 inbacktick = FALSE;
2253 for (p = str; *str; ++str)
2254 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002255 /* When the backslash is used for escaping the special meaning of a
2256 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 if (rem_backslash(str))
2258 {
2259 *p++ = *str++;
2260 *p++ = *str;
2261 }
2262 else
2263 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002264 /* An item ends at a space not in backticks */
2265 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002267 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002268 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002269 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 }
2271 }
2272 str = skipwhite(str);
2273 *p = NUL;
2274
2275 return str;
2276}
2277
Bram Moolenaar86b68352004-12-27 21:59:20 +00002278/*
2279 * Separate the arguments in "str" and return a list of pointers in the
2280 * growarray "gap".
2281 */
2282 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002283get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002284{
2285 ga_init2(gap, (int)sizeof(char_u *), 20);
2286 while (*str != NUL)
2287 {
2288 if (ga_grow(gap, 1) == FAIL)
2289 {
2290 ga_clear(gap);
2291 return FAIL;
2292 }
2293 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2294
2295 /* Isolate one argument, change it in-place, put a NUL after it. */
2296 str = do_one_arg(str);
2297 }
2298 return OK;
2299}
2300
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002301#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002302/*
2303 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002304 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002305 * Return FAIL or OK.
2306 */
2307 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002308get_arglist_exp(
2309 char_u *str,
2310 int *fcountp,
2311 char_u ***fnamesp,
2312 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002313{
2314 garray_T ga;
2315 int i;
2316
2317 if (get_arglist(&ga, str) == FAIL)
2318 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002319 if (wig == TRUE)
2320 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2321 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2322 else
2323 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2324 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2325
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002326 ga_clear(&ga);
2327 return i;
2328}
2329#endif
2330
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2332/*
2333 * Redefine the argument list.
2334 */
2335 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002336set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337{
2338 do_arglist(str, AL_SET, 0);
2339}
2340#endif
2341
2342/*
2343 * "what" == AL_SET: Redefine the argument list to 'str'.
2344 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2345 * "what" == AL_DEL: remove files in 'str' from the argument list.
2346 *
2347 * Return FAIL for failure, OK otherwise.
2348 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002350do_arglist(
2351 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002352 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002353 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354{
2355 garray_T new_ga;
2356 int exp_count;
2357 char_u **exp_files;
2358 int i;
2359#ifdef FEAT_LISTCMDS
2360 char_u *p;
2361 int match;
2362#endif
2363
2364 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002365 * Set default argument for ":argadd" command.
2366 */
2367 if (what == AL_ADD && *str == NUL)
2368 {
2369 if (curbuf->b_ffname == NULL)
2370 return FAIL;
2371 str = curbuf->b_fname;
2372 }
2373
2374 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 * Collect all file name arguments in "new_ga".
2376 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002377 if (get_arglist(&new_ga, str) == FAIL)
2378 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379
2380#ifdef FEAT_LISTCMDS
2381 if (what == AL_DEL)
2382 {
2383 regmatch_T regmatch;
2384 int didone;
2385
2386 /*
2387 * Delete the items: use each item as a regexp and find a match in the
2388 * argument list.
2389 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002390 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002391 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2392 {
2393 p = ((char_u **)new_ga.ga_data)[i];
2394 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2395 if (p == NULL)
2396 break;
2397 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2398 if (regmatch.regprog == NULL)
2399 {
2400 vim_free(p);
2401 break;
2402 }
2403
2404 didone = FALSE;
2405 for (match = 0; match < ARGCOUNT; ++match)
2406 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2407 (colnr_T)0))
2408 {
2409 didone = TRUE;
2410 vim_free(ARGLIST[match].ae_fname);
2411 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2412 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2413 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 if (curwin->w_arg_idx > match)
2415 --curwin->w_arg_idx;
2416 --match;
2417 }
2418
Bram Moolenaar473de612013-06-08 18:19:48 +02002419 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420 vim_free(p);
2421 if (!didone)
2422 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2423 }
2424 ga_clear(&new_ga);
2425 }
2426 else
2427#endif
2428 {
2429 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2430 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2431 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002432 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433 {
2434 EMSG(_(e_nomatch));
2435 return FAIL;
2436 }
2437
2438#ifdef FEAT_LISTCMDS
2439 if (what == AL_ADD)
2440 {
2441 (void)alist_add_list(exp_count, exp_files, after);
2442 vim_free(exp_files);
2443 }
2444 else /* what == AL_SET */
2445#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002446 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 }
2448
2449 alist_check_arg_idx();
2450
2451 return OK;
2452}
2453
2454/*
2455 * Check the validity of the arg_idx for each other window.
2456 */
2457 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002458alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459{
2460#ifdef FEAT_WINDOWS
2461 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002462 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463
Bram Moolenaarf740b292006-02-16 22:11:02 +00002464 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002465 if (win->w_alist == curwin->w_alist)
2466 check_arg_idx(win);
2467#else
2468 check_arg_idx(curwin);
2469#endif
2470}
2471
2472/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002473 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002474 * index.
2475 */
2476 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002477editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002478{
2479 return !(win->w_arg_idx >= WARGCOUNT(win)
2480 || (win->w_buffer->b_fnum
2481 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2482 && (win->w_buffer->b_ffname == NULL
2483 || !(fullpathcmp(
2484 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2485 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2486}
2487
2488/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002489 * Check if window "win" is editing the w_arg_idx file in its argument list.
2490 */
2491 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002492check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002493{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002494 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495 {
2496 /* We are not editing the current entry in the argument list.
2497 * Set "arg_had_last" if we are editing the last one. */
2498 win->w_arg_idx_invalid = TRUE;
2499 if (win->w_arg_idx != WARGCOUNT(win) - 1
2500 && arg_had_last == FALSE
2501#ifdef FEAT_WINDOWS
2502 && ALIST(win) == &global_alist
2503#endif
2504 && GARGCOUNT > 0
2505 && win->w_arg_idx < GARGCOUNT
2506 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2507 || (win->w_buffer->b_ffname != NULL
2508 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2509 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2510 arg_had_last = TRUE;
2511 }
2512 else
2513 {
2514 /* We are editing the current entry in the argument list.
2515 * Set "arg_had_last" if it's also the last one */
2516 win->w_arg_idx_invalid = FALSE;
2517 if (win->w_arg_idx == WARGCOUNT(win) - 1
2518#ifdef FEAT_WINDOWS
2519 && win->w_alist == &global_alist
2520#endif
2521 )
2522 arg_had_last = TRUE;
2523 }
2524}
2525
2526/*
2527 * ":args", ":argslocal" and ":argsglobal".
2528 */
2529 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002530ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531{
2532 int i;
2533
2534 if (eap->cmdidx != CMD_args)
2535 {
2536#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2537 alist_unlink(ALIST(curwin));
2538 if (eap->cmdidx == CMD_argglobal)
2539 ALIST(curwin) = &global_alist;
2540 else /* eap->cmdidx == CMD_arglocal */
2541 alist_new();
2542#else
2543 ex_ni(eap);
2544 return;
2545#endif
2546 }
2547
2548 if (!ends_excmd(*eap->arg))
2549 {
2550 /*
2551 * ":args file ..": define new argument list, handle like ":next"
2552 * Also for ":argslocal file .." and ":argsglobal file ..".
2553 */
2554 ex_next(eap);
2555 }
2556 else
2557#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2558 if (eap->cmdidx == CMD_args)
2559#endif
2560 {
2561 /*
2562 * ":args": list arguments.
2563 */
2564 if (ARGCOUNT > 0)
2565 {
2566 /* Overwrite the command, for a short list there is no scrolling
2567 * required and no wait_return(). */
2568 gotocmdline(TRUE);
2569 for (i = 0; i < ARGCOUNT; ++i)
2570 {
2571 if (i == curwin->w_arg_idx)
2572 msg_putchar('[');
2573 msg_outtrans(alist_name(&ARGLIST[i]));
2574 if (i == curwin->w_arg_idx)
2575 msg_putchar(']');
2576 msg_putchar(' ');
2577 }
2578 }
2579 }
2580#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2581 else if (eap->cmdidx == CMD_arglocal)
2582 {
2583 garray_T *gap = &curwin->w_alist->al_ga;
2584
2585 /*
2586 * ":argslocal": make a local copy of the global argument list.
2587 */
2588 if (ga_grow(gap, GARGCOUNT) == OK)
2589 for (i = 0; i < GARGCOUNT; ++i)
2590 if (GARGLIST[i].ae_fname != NULL)
2591 {
2592 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2593 vim_strsave(GARGLIST[i].ae_fname);
2594 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2595 GARGLIST[i].ae_fnum;
2596 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597 }
2598 }
2599#endif
2600}
2601
2602/*
2603 * ":previous", ":sprevious", ":Next" and ":sNext".
2604 */
2605 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002606ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607{
2608 /* If past the last one already, go to the last one. */
2609 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2610 do_argfile(eap, ARGCOUNT - 1);
2611 else
2612 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2613}
2614
2615/*
2616 * ":rewind", ":first", ":sfirst" and ":srewind".
2617 */
2618 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002619ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620{
2621 do_argfile(eap, 0);
2622}
2623
2624/*
2625 * ":last" and ":slast".
2626 */
2627 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002628ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002629{
2630 do_argfile(eap, ARGCOUNT - 1);
2631}
2632
2633/*
2634 * ":argument" and ":sargument".
2635 */
2636 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002637ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002638{
2639 int i;
2640
2641 if (eap->addr_count > 0)
2642 i = eap->line2 - 1;
2643 else
2644 i = curwin->w_arg_idx;
2645 do_argfile(eap, i);
2646}
2647
2648/*
2649 * Edit file "argn" of the argument lists.
2650 */
2651 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002652do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653{
2654 int other;
2655 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002656 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002657
2658 if (argn < 0 || argn >= ARGCOUNT)
2659 {
2660 if (ARGCOUNT <= 1)
2661 EMSG(_("E163: There is only one file to edit"));
2662 else if (argn < 0)
2663 EMSG(_("E164: Cannot go before first file"));
2664 else
2665 EMSG(_("E165: Cannot go beyond last file"));
2666 }
2667 else
2668 {
2669 setpcmark();
2670#ifdef FEAT_GUI
2671 need_mouse_correct = TRUE;
2672#endif
2673
2674#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002675 /* split window or create new tab page first */
2676 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677 {
2678 if (win_split(0, 0) == FAIL)
2679 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002680 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 }
2682 else
2683#endif
2684 {
2685 /*
2686 * if 'hidden' set, only check for changed file when re-editing
2687 * the same buffer
2688 */
2689 other = TRUE;
2690 if (P_HID(curbuf))
2691 {
2692 p = fix_fname(alist_name(&ARGLIST[argn]));
2693 other = otherfile(p);
2694 vim_free(p);
2695 }
2696 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002697 && check_changed(curbuf, CCGD_AW
2698 | (other ? 0 : CCGD_MULTWIN)
2699 | (eap->forceit ? CCGD_FORCEIT : 0)
2700 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002701 return;
2702 }
2703
2704 curwin->w_arg_idx = argn;
2705 if (argn == ARGCOUNT - 1
2706#ifdef FEAT_WINDOWS
2707 && curwin->w_alist == &global_alist
2708#endif
2709 )
2710 arg_had_last = TRUE;
2711
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002712 /* Edit the file; always use the last known line number.
2713 * When it fails (e.g. Abort for already edited file) restore the
2714 * argument index. */
2715 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002717 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2718 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002719 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002721 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 setmark('\'');
2723 }
2724}
2725
2726/*
2727 * ":next", and commands that behave like it.
2728 */
2729 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002730ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002731{
2732 int i;
2733
2734 /*
2735 * check for changed buffer now, if this fails the argument list is not
2736 * redefined.
2737 */
2738 if ( P_HID(curbuf)
2739 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002740 || !check_changed(curbuf, CCGD_AW
2741 | (eap->forceit ? CCGD_FORCEIT : 0)
2742 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743 {
2744 if (*eap->arg != NUL) /* redefine file list */
2745 {
2746 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2747 return;
2748 i = 0;
2749 }
2750 else
2751 i = curwin->w_arg_idx + (int)eap->line2;
2752 do_argfile(eap, i);
2753 }
2754}
2755
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002756#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757/*
2758 * ":argedit"
2759 */
2760 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002761ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002762{
2763 int fnum;
2764 int i;
2765 char_u *s;
2766
2767 /* Add the argument to the buffer list and get the buffer number. */
2768 fnum = buflist_add(eap->arg, BLN_LISTED);
2769
2770 /* Check if this argument is already in the argument list. */
2771 for (i = 0; i < ARGCOUNT; ++i)
2772 if (ARGLIST[i].ae_fnum == fnum)
2773 break;
2774 if (i == ARGCOUNT)
2775 {
2776 /* Can't find it, add it to the argument list. */
2777 s = vim_strsave(eap->arg);
2778 if (s == NULL)
2779 return;
2780 i = alist_add_list(1, &s,
2781 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2782 if (i < 0)
2783 return;
2784 curwin->w_arg_idx = i;
2785 }
2786
2787 alist_check_arg_idx();
2788
2789 /* Edit the argument. */
2790 do_argfile(eap, i);
2791}
2792
2793/*
2794 * ":argadd"
2795 */
2796 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002797ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798{
2799 do_arglist(eap->arg, AL_ADD,
2800 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2801#ifdef FEAT_TITLE
2802 maketitle();
2803#endif
2804}
2805
2806/*
2807 * ":argdelete"
2808 */
2809 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002810ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811{
2812 int i;
2813 int n;
2814
2815 if (eap->addr_count > 0)
2816 {
2817 /* ":1,4argdel": Delete all arguments in the range. */
2818 if (eap->line2 > ARGCOUNT)
2819 eap->line2 = ARGCOUNT;
2820 n = eap->line2 - eap->line1 + 1;
2821 if (*eap->arg != NUL || n <= 0)
2822 EMSG(_(e_invarg));
2823 else
2824 {
2825 for (i = eap->line1; i <= eap->line2; ++i)
2826 vim_free(ARGLIST[i - 1].ae_fname);
2827 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2828 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2829 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002830 if (curwin->w_arg_idx >= eap->line2)
2831 curwin->w_arg_idx -= n;
2832 else if (curwin->w_arg_idx > eap->line1)
2833 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002834 if (ARGCOUNT == 0)
2835 curwin->w_arg_idx = 0;
2836 else if (curwin->w_arg_idx >= ARGCOUNT)
2837 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002838 }
2839 }
2840 else if (*eap->arg == NUL)
2841 EMSG(_(e_argreq));
2842 else
2843 do_arglist(eap->arg, AL_DEL, 0);
2844#ifdef FEAT_TITLE
2845 maketitle();
2846#endif
2847}
2848
2849/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002850 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851 */
2852 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002853ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002854{
2855 int i;
2856#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002857 win_T *wp;
2858 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002859#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002860 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861 int next_fnum = 0;
2862#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2863 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002864#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002865 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002866#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002867 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002868 int qf_idx;
2869#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870
2871#ifndef FEAT_WINDOWS
2872 if (eap->cmdidx == CMD_windo)
2873 {
2874 ex_ni(eap);
2875 return;
2876 }
2877#endif
2878
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002879#ifndef FEAT_QUICKFIX
2880 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2881 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2882 {
2883 ex_ni(eap);
2884 return;
2885 }
2886#endif
2887
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002889 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002890 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2891 * great speed improvement. */
2892 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002894#ifdef FEAT_CLIPBOARD
2895 start_global_changes();
2896#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897
2898 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002899 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002901 || !check_changed(curbuf, CCGD_AW
2902 | (eap->forceit ? CCGD_FORCEIT : 0)
2903 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002906 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002908 wp = firstwin;
2909 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002911 switch (eap->cmdidx)
2912 {
2913#ifdef FEAT_WINDOWS
2914 case CMD_windo:
2915 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2916 i++;
2917 break;
2918 case CMD_tabdo:
2919 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2920 i++;
2921 break;
2922#endif
2923 case CMD_argdo:
2924 i = eap->line1 - 1;
2925 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002926 default:
2927 break;
2928 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002929 /* set pcmark now */
2930 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002931 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002932 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002933 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002934 || !buf->b_p_bl); buf = buf->b_next)
2935 if (buf->b_fnum > eap->line2)
2936 {
2937 buf = NULL;
2938 break;
2939 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002940 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002941 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002942 }
2943#ifdef FEAT_QUICKFIX
2944 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2945 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2946 {
2947 qf_size = qf_get_size(eap);
2948 if (qf_size <= 0 || eap->line1 > qf_size)
2949 buf = NULL;
2950 else
2951 {
2952 ex_cc(eap);
2953
2954 buf = curbuf;
2955 i = eap->line1 - 1;
2956 if (eap->addr_count <= 0)
2957 /* default is all the quickfix/location list entries */
2958 eap->line2 = qf_size;
2959 }
2960 }
2961#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002962 else
2963 setpcmark();
2964 listcmd_busy = TRUE; /* avoids setting pcmark below */
2965
Bram Moolenaare25bb902015-02-27 20:33:37 +01002966 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967 {
2968 if (eap->cmdidx == CMD_argdo)
2969 {
2970 /* go to argument "i" */
2971 if (i == ARGCOUNT)
2972 break;
2973 /* Don't call do_argfile() when already there, it will try
2974 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002975 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002976 {
2977 /* Clear 'shm' to avoid that the file message overwrites
2978 * any output from the command. */
2979 p_shm_save = vim_strsave(p_shm);
2980 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002981 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002982 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2983 vim_free(p_shm_save);
2984 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002985 if (curwin->w_arg_idx != i)
2986 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987 }
2988#ifdef FEAT_WINDOWS
2989 else if (eap->cmdidx == CMD_windo)
2990 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002991 /* go to window "wp" */
2992 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002993 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002994 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002995 if (curwin != wp)
2996 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002997 wp = curwin->w_next;
2998 }
2999 else if (eap->cmdidx == CMD_tabdo)
3000 {
3001 /* go to window "tp" */
3002 if (!valid_tabpage(tp))
3003 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003004 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003005 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003006 }
3007#endif
3008 else if (eap->cmdidx == CMD_bufdo)
3009 {
3010 /* Remember the number of the next listed buffer, in case
3011 * ":bwipe" is used or autocommands do something strange. */
3012 next_fnum = -1;
3013 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
3014 if (buf->b_p_bl)
3015 {
3016 next_fnum = buf->b_fnum;
3017 break;
3018 }
3019 }
3020
Bram Moolenaara162bc52015-01-07 16:54:21 +01003021 ++i;
3022
Bram Moolenaar071d4272004-06-13 20:20:40 +00003023 /* execute the command */
3024 do_cmdline(eap->arg, eap->getline, eap->cookie,
3025 DOCMD_VERBOSE + DOCMD_NOWAIT);
3026
3027 if (eap->cmdidx == CMD_bufdo)
3028 {
3029 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01003030 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031 break;
3032 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02003033 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034 if (buf->b_fnum == next_fnum)
3035 break;
3036 if (buf == NULL)
3037 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003038
3039 /* Go to the next buffer. Clear 'shm' to avoid that the file
3040 * message overwrites any output from the command. */
3041 p_shm_save = vim_strsave(p_shm);
3042 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003043 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003044 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3045 vim_free(p_shm_save);
3046
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003047 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048 if (curbuf->b_fnum != next_fnum)
3049 break;
3050 }
3051
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003052#ifdef FEAT_QUICKFIX
3053 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
3054 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3055 {
3056 if (i >= qf_size || i >= eap->line2)
3057 break;
3058
3059 qf_idx = qf_get_cur_idx(eap);
3060
3061 ex_cnext(eap);
3062
3063 /* If jumping to the next quickfix entry fails, quit here */
3064 if (qf_get_cur_idx(eap) == qf_idx)
3065 break;
3066 }
3067#endif
3068
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069 if (eap->cmdidx == CMD_windo)
3070 {
3071 validate_cursor(); /* cursor may have moved */
3072#ifdef FEAT_SCROLLBIND
3073 /* required when 'scrollbind' has been set */
3074 if (curwin->w_p_scb)
3075 do_check_scrollbind(TRUE);
3076#endif
3077 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01003078
3079#ifdef FEAT_WINDOWS
3080 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
3081 if (i+1 > eap->line2)
3082 break;
3083#endif
3084 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
3085 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086 }
3087 listcmd_busy = FALSE;
3088 }
3089
3090#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003091 if (save_ei != NULL)
3092 {
3093 au_event_restore(save_ei);
3094 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
3095 curbuf->b_fname, TRUE, curbuf);
3096 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003097#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02003098#ifdef FEAT_CLIPBOARD
3099 end_global_changes();
3100#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101}
3102
3103/*
3104 * Add files[count] to the arglist of the current window after arg "after".
3105 * The file names in files[count] must have been allocated and are taken over.
3106 * Files[] itself is not taken over.
3107 * Returns index of first added argument. Returns -1 when failed (out of mem).
3108 */
3109 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003110alist_add_list(
3111 int count,
3112 char_u **files,
3113 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114{
3115 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003116 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003117
3118 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
3119 {
3120 if (after < 0)
3121 after = 0;
3122 if (after > ARGCOUNT)
3123 after = ARGCOUNT;
3124 if (after < ARGCOUNT)
3125 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
3126 (ARGCOUNT - after) * sizeof(aentry_T));
3127 for (i = 0; i < count; ++i)
3128 {
3129 ARGLIST[after + i].ae_fname = files[i];
3130 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
3131 }
3132 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003133 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3134 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 return after;
3136 }
3137
3138 for (i = 0; i < count; ++i)
3139 vim_free(files[i]);
3140 return -1;
3141}
3142
3143#endif /* FEAT_LISTCMDS */
3144
3145#ifdef FEAT_EVAL
3146/*
3147 * ":compiler[!] {name}"
3148 */
3149 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003150ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151{
3152 char_u *buf;
3153 char_u *old_cur_comp = NULL;
3154 char_u *p;
3155
3156 if (*eap->arg == NUL)
3157 {
3158 /* List all compiler scripts. */
3159 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3160 /* ) keep the indenter happy... */
3161 }
3162 else
3163 {
3164 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3165 if (buf != NULL)
3166 {
3167 if (eap->forceit)
3168 {
3169 /* ":compiler! {name}" sets global options */
3170 do_cmdline_cmd((char_u *)
3171 "command -nargs=* CompilerSet set <args>");
3172 }
3173 else
3174 {
3175 /* ":compiler! {name}" sets local options.
3176 * To remain backwards compatible "current_compiler" is always
3177 * used. A user's compiler plugin may set it, the distributed
3178 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003179 * "b:current_compiler" and restore "current_compiler".
3180 * Explicitly prepend "g:" to make it work in a function. */
3181 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003182 if (old_cur_comp != NULL)
3183 old_cur_comp = vim_strsave(old_cur_comp);
3184 do_cmdline_cmd((char_u *)
3185 "command -nargs=* CompilerSet setlocal <args>");
3186 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003187 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003188 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189
3190 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003191 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3193 vim_free(buf);
3194
3195 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3196
3197 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003198 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003199 if (p != NULL)
3200 set_internal_string_var((char_u *)"b:current_compiler", p);
3201
3202 /* Restore "current_compiler" for ":compiler {name}". */
3203 if (!eap->forceit)
3204 {
3205 if (old_cur_comp != NULL)
3206 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003207 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208 old_cur_comp);
3209 vim_free(old_cur_comp);
3210 }
3211 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003212 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213 }
3214 }
3215 }
3216}
3217#endif
3218
3219/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003220 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221 */
3222 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003223ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003224{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003225 char_u *arg = eap->arg;
3226 char_u *p = skiptowhite(arg);
3227 int len = (int)(p - arg);
3228 int flags = eap->forceit ? DIP_ALL : 0;
3229
3230 if (STRNCMP(arg, "START", len) == 0)
3231 {
3232 flags += DIP_START + DIP_NORTP;
3233 arg = skipwhite(arg + len);
3234 }
3235 else if (STRNCMP(arg, "OPT", len) == 0)
3236 {
3237 flags += DIP_OPT + DIP_NORTP;
3238 arg = skipwhite(arg + len);
3239 }
3240 else if (STRNCMP(arg, "PACK", len) == 0)
3241 {
3242 flags += DIP_START + DIP_OPT + DIP_NORTP;
3243 arg = skipwhite(arg + len);
3244 }
3245 else if (STRNCMP(arg, "ALL", len) == 0)
3246 {
3247 flags += DIP_START + DIP_OPT;
3248 arg = skipwhite(arg + len);
3249 }
3250
3251 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003252}
3253
Bram Moolenaar071d4272004-06-13 20:20:40 +00003254 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003255source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003257 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258}
3259
3260/*
3261 * Source the file "name" from all directories in 'runtimepath'.
3262 * "name" can contain wildcards.
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003263 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
Bram Moolenaar91715872016-03-03 17:13:03 +01003264 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 * return FAIL when no file could be sourced, OK otherwise.
3266 */
3267 int
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003268source_runtime(char_u *name, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269{
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003270 return do_in_runtimepath(name, flags, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271}
3272
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003273/*
3274 * Find the file "name" in all directories in "path" and invoke
3275 * "callback(fname, cookie)".
3276 * "name" can contain wildcards.
3277 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3278 * When "flags" has DIP_DIR: find directories instead of files.
3279 * When "flags" has DIP_ERR: give an error message if there is no match.
3280 *
3281 * return FAIL when no file could be sourced, OK otherwise.
3282 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003283 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003284do_in_path(
3285 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003286 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003287 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003288 void (*callback)(char_u *fname, void *ck),
3289 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290{
3291 char_u *rtp;
3292 char_u *np;
3293 char_u *buf;
3294 char_u *rtp_copy;
3295 char_u *tail;
3296 int num_files;
3297 char_u **files;
3298 int i;
3299 int did_one = FALSE;
3300#ifdef AMIGA
3301 struct Process *proc = (struct Process *)FindTask(0L);
3302 APTR save_winptr = proc->pr_WindowPtr;
3303
3304 /* Avoid a requester here for a volume that doesn't exist. */
3305 proc->pr_WindowPtr = (APTR)-1L;
3306#endif
3307
3308 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3309 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003310 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003311 buf = alloc(MAXPATHL);
3312 if (buf != NULL && rtp_copy != NULL)
3313 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003314 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003315 {
3316 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003317 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003318 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003319 verbose_leave();
3320 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003321
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322 /* Loop over all entries in 'runtimepath'. */
3323 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003324 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02003326 size_t buflen;
3327
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328 /* Copy the path from 'runtimepath' to buf[]. */
3329 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02003330 buflen = STRLEN(buf);
3331
3332 /* Skip after or non-after directories. */
3333 if (flags & (DIP_NOAFTER | DIP_AFTER))
3334 {
3335 int is_after = buflen >= 5
3336 && STRCMP(buf + buflen - 5, "after") == 0;
3337
3338 if ((is_after && (flags & DIP_NOAFTER))
3339 || (!is_after && (flags & DIP_AFTER)))
3340 continue;
3341 }
3342
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003343 if (name == NULL)
3344 {
3345 (*callback)(buf, (void *) &cookie);
3346 if (!did_one)
3347 did_one = (cookie == NULL);
3348 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02003349 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003350 {
3351 add_pathsep(buf);
3352 tail = buf + STRLEN(buf);
3353
3354 /* Loop over all patterns in "name" */
3355 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003356 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003357 {
3358 /* Append the pattern from "name" to buf[]. */
3359 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3360 "\t ");
3361
3362 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003363 {
3364 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003365 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003366 verbose_leave();
3367 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368
3369 /* Expand wildcards, invoke the callback for each match. */
3370 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003371 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372 {
3373 for (i = 0; i < num_files; ++i)
3374 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003375 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003376 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003377 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003378 break;
3379 }
3380 FreeWild(num_files, files);
3381 }
3382 }
3383 }
3384 }
3385 }
3386 vim_free(buf);
3387 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003388 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003389 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003390 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3391
3392 if (flags & DIP_ERR)
3393 EMSG3(_(e_dirnotf), basepath, name);
3394 else if (p_verbose > 0)
3395 {
3396 verbose_enter();
3397 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3398 verbose_leave();
3399 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003400 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003401
3402#ifdef AMIGA
3403 proc->pr_WindowPtr = save_winptr;
3404#endif
3405
3406 return did_one ? OK : FAIL;
3407}
3408
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003409/*
3410 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3411 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003412 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3413 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003414 * Returns OK when at least one match found, FAIL otherwise.
3415 *
3416 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3417 * passed by reference in this case, setting it to NULL indicates that callback
3418 * has done its job.
3419 */
3420 int
3421do_in_runtimepath(
3422 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003423 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003424 void (*callback)(char_u *fname, void *ck),
3425 void *cookie)
3426{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003427 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003428 char_u *s;
3429 int len;
3430 char *start_dir = "pack/*/start/*/%s";
3431 char *opt_dir = "pack/*/opt/*/%s";
3432
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003433 if ((flags & DIP_NORTP) == 0)
3434 done = do_in_path(p_rtp, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003435
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003436 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003437 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003438 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003439 s = alloc(len);
3440 if (s == NULL)
3441 return FAIL;
3442 vim_snprintf((char *)s, len, start_dir, name);
3443 done = do_in_path(p_pp, s, flags, callback, cookie);
3444 vim_free(s);
3445 }
3446
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003447 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003448 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003449 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003450 s = alloc(len);
3451 if (s == NULL)
3452 return FAIL;
3453 vim_snprintf((char *)s, len, opt_dir, name);
3454 done = do_in_path(p_pp, s, flags, callback, cookie);
3455 vim_free(s);
3456 }
3457
3458 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003459}
3460
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003461/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003462 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003463 */
3464 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003465source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003466{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003467 int num_files;
3468 char_u **files;
3469 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003470
Bram Moolenaarf3654822016-03-04 22:12:23 +01003471 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003472 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003473 for (i = 0; i < num_files; ++i)
3474 (void)do_source(files[i], FALSE, DOSO_NONE);
3475 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003476 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003477}
3478
Bram Moolenaar49b27322016-04-05 21:13:00 +02003479/* used for "cookie" of add_pack_plugin() */
3480static int APP_ADD_DIR;
3481static int APP_LOAD;
3482static int APP_BOTH;
3483
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003484 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003485add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003486{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003487 char_u *p4, *p3, *p2, *p1, *p;
3488 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003489 int c;
3490 char_u *new_rtp;
3491 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003492 size_t oldlen;
3493 size_t addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003494 char_u *afterdir;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003495 size_t afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003496 char_u *ffname = fix_fname(fname);
Bram Moolenaarfef524b2016-07-02 22:07:22 +02003497 size_t fname_len;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003498
Bram Moolenaar91715872016-03-03 17:13:03 +01003499 if (ffname == NULL)
3500 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003501 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003502 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003503 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003504 p4 = p3 = p2 = p1 = get_past_head(ffname);
3505 for (p = p1; *p; mb_ptr_adv(p))
3506 if (vim_ispathsep_nocolon(*p))
3507 {
3508 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3509 }
3510
3511 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003512 * rtp/pack/name/start/name
3513 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003514 *
3515 * find the part up to "pack" in 'runtimepath' */
3516 c = *p4;
3517 *p4 = NUL;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003518
3519 /* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3520 fname_len = STRLEN(ffname);
3521 insp = p_rtp;
3522 for (;;)
3523 {
3524 if (vim_fnamencmp(insp, ffname, fname_len) == 0)
3525 break;
3526 insp = vim_strchr(insp, ',');
3527 if (insp == NULL)
3528 break;
3529 ++insp;
3530 }
3531
Bram Moolenaarf3654822016-03-04 22:12:23 +01003532 if (insp == NULL)
3533 /* not found, append at the end */
3534 insp = p_rtp + STRLEN(p_rtp);
3535 else
3536 {
3537 /* append after the matching directory. */
3538 insp += STRLEN(ffname);
3539 while (*insp != NUL && *insp != ',')
3540 ++insp;
3541 }
3542 *p4 = c;
3543
Bram Moolenaara5702442016-05-24 19:37:29 +02003544 /* check if rtp/pack/name/start/name/after exists */
3545 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3546 if (afterdir != NULL && mch_isdir(afterdir))
3547 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3548
Bram Moolenaarb0550662016-05-31 21:37:36 +02003549 oldlen = STRLEN(p_rtp);
3550 addlen = STRLEN(ffname) + 1; /* add one for comma */
3551 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003552 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003553 goto theend;
3554 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003555 mch_memmove(new_rtp, p_rtp, keep);
3556 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003557 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003558 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003559 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003560 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003561 if (afterlen > 0)
3562 {
3563 STRCAT(new_rtp, ",");
3564 STRCAT(new_rtp, afterdir);
3565 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003566 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3567 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003568 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003569 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003570
Bram Moolenaar49b27322016-04-05 21:13:00 +02003571 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003572 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003573 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003574 static char *ftpat = "%s/ftdetect/*.vim";
3575 int len;
3576 char_u *pat;
3577
3578 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3579 pat = alloc(len);
3580 if (pat == NULL)
3581 goto theend;
3582 vim_snprintf((char *)pat, len, plugpat, ffname);
3583 source_all_matches(pat);
3584
3585#ifdef FEAT_AUTOCMD
3586 {
3587 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3588
3589 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3590 * found when it loads. */
3591 if (cmd != NULL && eval_to_number(cmd) > 0)
3592 {
3593 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3594 vim_snprintf((char *)pat, len, ftpat, ffname);
3595 source_all_matches(pat);
3596 do_cmdline_cmd((char_u *)"augroup END");
3597 }
3598 vim_free(cmd);
3599 }
3600#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003601 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003602 }
3603
3604theend:
3605 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003606}
3607
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003608static int did_source_packages = FALSE;
3609
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003610/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003611 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003612 * Find plugins in the package directories and source them.
Bram Moolenaar66459b72016-08-06 19:01:55 +02003613 * "eap" is NULL when invoked during startup.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003614 */
3615 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003616ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003617{
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003618 if (!did_source_packages || (eap != NULL && eap->forceit))
3619 {
3620 did_source_packages = TRUE;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003621
3622 /* First do a round to add all directories to 'runtimepath', then load
3623 * the plugins. This allows for plugins to use an autoload directory
3624 * of another plugin. */
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003625 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003626 add_pack_plugin, &APP_ADD_DIR);
3627 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3628 add_pack_plugin, &APP_LOAD);
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003629 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003630}
3631
3632/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003633 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003634 */
3635 void
3636ex_packadd(exarg_T *eap)
3637{
3638 static char *plugpat = "pack/*/opt/%s";
3639 int len;
3640 char *pat;
3641
3642 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3643 pat = (char *)alloc(len);
3644 if (pat == NULL)
3645 return;
3646 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003647 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003648 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003649 vim_free(pat);
3650}
3651
Bram Moolenaar071d4272004-06-13 20:20:40 +00003652#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3653/*
3654 * ":options"
3655 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003656 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003657ex_options(
3658 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659{
3660 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3661}
3662#endif
3663
3664/*
3665 * ":source {fname}"
3666 */
3667 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003668ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669{
3670#ifdef FEAT_BROWSE
3671 if (cmdmod.browse)
3672 {
3673 char_u *fname = NULL;
3674
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003675 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3677 if (fname != NULL)
3678 {
3679 cmd_source(fname, eap);
3680 vim_free(fname);
3681 }
3682 }
3683 else
3684#endif
3685 cmd_source(eap->arg, eap);
3686}
3687
3688 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003689cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690{
3691 if (*fname == NUL)
3692 EMSG(_(e_argreq));
3693
Bram Moolenaar071d4272004-06-13 20:20:40 +00003694 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003695 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003696 * Need to execute the commands directly. This is required at least
3697 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003698 * - ":g" command busy
3699 * - after ":argdo", ":windo" or ":bufdo"
3700 * - another command follows
3701 * - inside a loop
3702 */
3703 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3704#ifdef FEAT_EVAL
3705 || eap->cstack->cs_idx >= 0
3706#endif
3707 );
3708
3709 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003710 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711 EMSG2(_(e_notopen), fname);
3712}
3713
3714/*
3715 * ":source" and associated commands.
3716 */
3717/*
3718 * Structure used to store info for each sourced file.
3719 * It is shared between do_source() and getsourceline().
3720 * This is required, because it needs to be handed to do_cmdline() and
3721 * sourcing can be done recursively.
3722 */
3723struct source_cookie
3724{
3725 FILE *fp; /* opened file for sourcing */
3726 char_u *nextline; /* if not NULL: line that was read ahead */
3727 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003728#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3730 int error; /* TRUE if LF found after CR-LF */
3731#endif
3732#ifdef FEAT_EVAL
3733 linenr_T breakpoint; /* next line with breakpoint or zero */
3734 char_u *fname; /* name of sourced file */
3735 int dbg_tick; /* debug_tick when breakpoint was set */
3736 int level; /* top nesting level of sourced file */
3737#endif
3738#ifdef FEAT_MBYTE
3739 vimconv_T conv; /* type of conversion */
3740#endif
3741};
3742
3743#ifdef FEAT_EVAL
3744/*
3745 * Return the address holding the next breakpoint line for a source cookie.
3746 */
3747 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003748source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749{
3750 return &((struct source_cookie *)cookie)->breakpoint;
3751}
3752
3753/*
3754 * Return the address holding the debug tick for a source cookie.
3755 */
3756 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003757source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758{
3759 return &((struct source_cookie *)cookie)->dbg_tick;
3760}
3761
3762/*
3763 * Return the nesting level for a source cookie.
3764 */
3765 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003766source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003767{
3768 return ((struct source_cookie *)cookie)->level;
3769}
3770#endif
3771
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003772static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003773
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003774#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3775# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003776static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777
3778/*
3779 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003780 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003781 */
3782 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003783fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003784{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003785# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003786 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3787# else
3788 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003789# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790
3791 if (fd_tmp == -1)
3792 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003793
3794# ifdef HAVE_FD_CLOEXEC
3795 {
3796 int fdflags = fcntl(fd_tmp, F_GETFD);
3797 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003798 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003799 }
3800# endif
3801
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802 return fdopen(fd_tmp, READBIN);
3803}
3804#endif
3805
3806
3807/*
3808 * do_source: Read the file "fname" and execute its lines as EX commands.
3809 *
3810 * This function may be called recursively!
3811 *
3812 * return FAIL if file could not be opened, OK otherwise
3813 */
3814 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003815do_source(
3816 char_u *fname,
3817 int check_other, /* check for .vimrc and _vimrc */
3818 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819{
3820 struct source_cookie cookie;
3821 char_u *save_sourcing_name;
3822 linenr_T save_sourcing_lnum;
3823 char_u *p;
3824 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003825 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826 int retval = FAIL;
3827#ifdef FEAT_EVAL
3828 scid_T save_current_SID;
3829 static scid_T last_current_SID = 0;
3830 void *save_funccalp;
3831 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003832 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003833# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003834 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 int stat_ok;
3836# endif
3837#endif
3838#ifdef STARTUPTIME
3839 struct timeval tv_rel;
3840 struct timeval tv_start;
3841#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003842#ifdef FEAT_PROFILE
3843 proftime_T wait_start;
3844#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003845
Bram Moolenaar071d4272004-06-13 20:20:40 +00003846 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003847 if (p == NULL)
3848 return retval;
3849 fname_exp = fix_fname(p);
3850 vim_free(p);
3851 if (fname_exp == NULL)
3852 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003853 if (mch_isdir(fname_exp))
3854 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003855 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856 goto theend;
3857 }
3858
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003859#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003860 /* Apply SourceCmd autocommands, they should get the file and source it. */
3861 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3862 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3863 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003864 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003865# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003866 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003867# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003868 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003869# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003870 goto theend;
3871 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003872
3873 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003874 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3875#endif
3876
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003877#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003878 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3879#else
3880 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3881#endif
3882 if (cookie.fp == NULL && check_other)
3883 {
3884 /*
3885 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3886 * and ".exrc" by "_exrc" or vice versa.
3887 */
3888 p = gettail(fname_exp);
3889 if ((*p == '.' || *p == '_')
3890 && (STRICMP(p + 1, "vimrc") == 0
3891 || STRICMP(p + 1, "gvimrc") == 0
3892 || STRICMP(p + 1, "exrc") == 0))
3893 {
3894 if (*p == '_')
3895 *p = '.';
3896 else
3897 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003898#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003899 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3900#else
3901 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3902#endif
3903 }
3904 }
3905
3906 if (cookie.fp == NULL)
3907 {
3908 if (p_verbose > 0)
3909 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003910 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003911 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003912 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003913 else
3914 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003915 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003916 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917 }
3918 goto theend;
3919 }
3920
3921 /*
3922 * The file exists.
3923 * - In verbose mode, give a message.
3924 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3925 */
3926 if (p_verbose > 1)
3927 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003928 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003929 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003930 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003931 else
3932 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003933 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003934 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003935 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003936 if (is_vimrc == DOSO_VIMRC)
3937 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3938 else if (is_vimrc == DOSO_GVIMRC)
3939 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940
3941#ifdef USE_CRNL
3942 /* If no automatic file format: Set default to CR-NL. */
3943 if (*p_ffs == NUL)
3944 cookie.fileformat = EOL_DOS;
3945 else
3946 cookie.fileformat = EOL_UNKNOWN;
3947 cookie.error = FALSE;
3948#endif
3949
3950#ifdef USE_CR
3951 /* If no automatic file format: Set default to CR. */
3952 if (*p_ffs == NUL)
3953 cookie.fileformat = EOL_MAC;
3954 else
3955 cookie.fileformat = EOL_UNKNOWN;
3956 cookie.error = FALSE;
3957#endif
3958
3959 cookie.nextline = NULL;
3960 cookie.finished = FALSE;
3961
3962#ifdef FEAT_EVAL
3963 /*
3964 * Check if this script has a breakpoint.
3965 */
3966 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3967 cookie.fname = fname_exp;
3968 cookie.dbg_tick = debug_tick;
3969
3970 cookie.level = ex_nesting_level;
3971#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003972
3973 /*
3974 * Keep the sourcing name/lnum, for recursive calls.
3975 */
3976 save_sourcing_name = sourcing_name;
3977 sourcing_name = fname_exp;
3978 save_sourcing_lnum = sourcing_lnum;
3979 sourcing_lnum = 0;
3980
Bram Moolenaar73881402009-02-04 16:50:47 +00003981#ifdef FEAT_MBYTE
3982 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3983
3984 /* Read the first line so we can check for a UTF-8 BOM. */
3985 firstline = getsourceline(0, (void *)&cookie, 0);
3986 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3987 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3988 {
3989 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3990 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3991 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003992 if (p == NULL)
3993 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003994 if (p != NULL)
3995 {
3996 vim_free(firstline);
3997 firstline = p;
3998 }
3999 }
4000#endif
4001
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004003 if (time_fd != NULL)
4004 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004005#endif
4006
4007#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00004008# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004009 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004010 prof_child_enter(&wait_start); /* entering a child now */
4011# endif
4012
4013 /* Don't use local function variables, if called from a function.
4014 * Also starts profiling timer for nested script. */
4015 save_funccalp = save_funccal();
4016
Bram Moolenaar071d4272004-06-13 20:20:40 +00004017 /*
4018 * Check if this script was sourced before to finds its SID.
4019 * If it's new, generate a new SID.
4020 */
4021 save_current_SID = current_SID;
4022# ifdef UNIX
4023 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
4024# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004025 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
4026 {
4027 si = &SCRIPT_ITEM(current_SID);
4028 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004029 && (
4030# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00004031 /* Compare dev/ino when possible, it catches symbolic
4032 * links. Also compare file names, the inode may change
4033 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004034 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004035 && (si->sn_dev == st.st_dev
4036 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004037# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004038 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004040 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004041 if (current_SID == 0)
4042 {
4043 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004044 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
4045 == FAIL)
4046 goto almosttheend;
4047 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004048 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00004049 ++script_items.ga_len;
4050 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
4051# ifdef FEAT_PROFILE
4052 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004053# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004055 si = &SCRIPT_ITEM(current_SID);
4056 si->sn_name = fname_exp;
4057 fname_exp = NULL;
4058# ifdef UNIX
4059 if (stat_ok)
4060 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004061 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004062 si->sn_dev = st.st_dev;
4063 si->sn_ino = st.st_ino;
4064 }
4065 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004066 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004067# endif
4068
Bram Moolenaar071d4272004-06-13 20:20:40 +00004069 /* Allocate the local script variables to use for this script. */
4070 new_script_vars(current_SID);
4071 }
4072
Bram Moolenaar05159a02005-02-26 23:04:13 +00004073# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004074 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004075 {
4076 int forceit;
4077
4078 /* Check if we do profiling for this script. */
4079 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
4080 {
4081 script_do_profile(si);
4082 si->sn_pr_force = forceit;
4083 }
4084 if (si->sn_prof_on)
4085 {
4086 ++si->sn_pr_count;
4087 profile_start(&si->sn_pr_start);
4088 profile_zero(&si->sn_pr_children);
4089 }
4090 }
4091# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092#endif
4093
4094 /*
4095 * Call do_cmdline, which will call getsourceline() to get the lines.
4096 */
Bram Moolenaar73881402009-02-04 16:50:47 +00004097 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004099 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004100
4101#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004102 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004103 {
4104 /* Get "si" again, "script_items" may have been reallocated. */
4105 si = &SCRIPT_ITEM(current_SID);
4106 if (si->sn_prof_on)
4107 {
4108 profile_end(&si->sn_pr_start);
4109 profile_sub_wait(&wait_start, &si->sn_pr_start);
4110 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004111 profile_self(&si->sn_pr_self, &si->sn_pr_start,
4112 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004113 }
4114 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115#endif
4116
4117 if (got_int)
4118 EMSG(_(e_interr));
4119 sourcing_name = save_sourcing_name;
4120 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121 if (p_verbose > 1)
4122 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004123 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00004124 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004125 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004126 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004127 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004128 }
4129#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004130 if (time_fd != NULL)
4131 {
4132 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
4133 time_msg((char *)IObuff, &tv_start);
4134 time_pop(&tv_rel);
4135 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004136#endif
4137
4138#ifdef FEAT_EVAL
4139 /*
4140 * After a "finish" in debug mode, need to break at first command of next
4141 * sourced file.
4142 */
4143 if (save_debug_break_level > ex_nesting_level
4144 && debug_break_level == ex_nesting_level)
4145 ++debug_break_level;
4146#endif
4147
Bram Moolenaar05159a02005-02-26 23:04:13 +00004148#ifdef FEAT_EVAL
4149almosttheend:
4150 current_SID = save_current_SID;
4151 restore_funccal(save_funccalp);
4152# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004153 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004154 prof_child_exit(&wait_start); /* leaving a child now */
4155# endif
4156#endif
4157 fclose(cookie.fp);
4158 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004159 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004160#ifdef FEAT_MBYTE
4161 convert_setup(&cookie.conv, NULL, NULL);
4162#endif
4163
Bram Moolenaar071d4272004-06-13 20:20:40 +00004164theend:
4165 vim_free(fname_exp);
4166 return retval;
4167}
4168
4169#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004170
Bram Moolenaar071d4272004-06-13 20:20:40 +00004171/*
4172 * ":scriptnames"
4173 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004174 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004175ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176{
4177 int i;
4178
Bram Moolenaar05159a02005-02-26 23:04:13 +00004179 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4180 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004181 {
4182 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4183 NameBuff, MAXPATHL, TRUE);
4184 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004185 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004186}
4187
4188# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4189/*
4190 * Fix slashes in the list of script names for 'shellslash'.
4191 */
4192 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004193scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194{
4195 int i;
4196
Bram Moolenaar05159a02005-02-26 23:04:13 +00004197 for (i = 1; i <= script_items.ga_len; ++i)
4198 if (SCRIPT_ITEM(i).sn_name != NULL)
4199 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004200}
4201# endif
4202
4203/*
4204 * Get a pointer to a script name. Used for ":verbose set".
4205 */
4206 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004207get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004208{
4209 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004210 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004211 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004212 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004213 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004214 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004215 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004216 return (char_u *)_("environment variable");
4217 if (id == SID_ERROR)
4218 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004219 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004221
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004222# if defined(EXITFREE) || defined(PROTO)
4223 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004224free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004225{
4226 int i;
4227
4228 for (i = script_items.ga_len; i > 0; --i)
4229 vim_free(SCRIPT_ITEM(i).sn_name);
4230 ga_clear(&script_items);
4231}
4232# endif
4233
Bram Moolenaar071d4272004-06-13 20:20:40 +00004234#endif
4235
4236#if defined(USE_CR) || defined(PROTO)
4237
4238# if defined(__MSL__) && (__MSL__ >= 22)
4239/*
4240 * Newer version of the Metrowerks library handle DOS and UNIX files
4241 * without help.
4242 * Test with earlier versions, MSL 2.2 is the library supplied with
4243 * Codewarrior Pro 2.
4244 */
4245 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004246fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004247{
4248 return fgets(s, n, stream);
4249}
4250# else
4251/*
4252 * Version of fgets() which also works for lines ending in a <CR> only
4253 * (Macintosh format).
4254 * For older versions of the Metrowerks library.
4255 * At least CodeWarrior 9 needed this code.
4256 */
4257 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004258fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004259{
4260 int c = 0;
4261 int char_read = 0;
4262
4263 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4264 {
4265 c = fgetc(stream);
4266 s[char_read++] = c;
4267 /* If the file is in DOS format, we need to skip a NL after a CR. I
4268 * thought it was the other way around, but this appears to work... */
4269 if (c == '\n')
4270 {
4271 c = fgetc(stream);
4272 if (c != '\r')
4273 ungetc(c, stream);
4274 }
4275 }
4276
4277 s[char_read] = 0;
4278 if (char_read == 0)
4279 return NULL;
4280
4281 if (feof(stream) && char_read == 1)
4282 return NULL;
4283
4284 return s;
4285}
4286# endif
4287#endif
4288
4289/*
4290 * Get one full line from a sourced file.
4291 * Called by do_cmdline() when it's called from do_source().
4292 *
4293 * Return a pointer to the line in allocated memory.
4294 * Return NULL for end-of-file or some error.
4295 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004296 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004297getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298{
4299 struct source_cookie *sp = (struct source_cookie *)cookie;
4300 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004301 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004302
4303#ifdef FEAT_EVAL
4304 /* If breakpoints have been added/deleted need to check for it. */
4305 if (sp->dbg_tick < debug_tick)
4306 {
4307 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4308 sp->dbg_tick = debug_tick;
4309 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004310# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004311 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004312 script_line_end();
4313# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314#endif
4315 /*
4316 * Get current line. If there is a read-ahead line, use it, otherwise get
4317 * one now.
4318 */
4319 if (sp->finished)
4320 line = NULL;
4321 else if (sp->nextline == NULL)
4322 line = get_one_sourceline(sp);
4323 else
4324 {
4325 line = sp->nextline;
4326 sp->nextline = NULL;
4327 ++sourcing_lnum;
4328 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004329#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004330 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004331 script_line_start();
4332#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004333
4334 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4335 * contain the 'C' flag. */
4336 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4337 {
4338 /* compensate for the one line read-ahead */
4339 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004340
4341 /* Get the next line and concatenate it when it starts with a
4342 * backslash. We always need to read the next line, keep it in
4343 * sp->nextline. */
4344 sp->nextline = get_one_sourceline(sp);
4345 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004347 garray_T ga;
4348
Bram Moolenaarb549a732012-02-22 18:29:33 +01004349 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004350 ga_concat(&ga, line);
4351 ga_concat(&ga, p + 1);
4352 for (;;)
4353 {
4354 vim_free(sp->nextline);
4355 sp->nextline = get_one_sourceline(sp);
4356 if (sp->nextline == NULL)
4357 break;
4358 p = skipwhite(sp->nextline);
4359 if (*p != '\\')
4360 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004361 /* Adjust the growsize to the current length to speed up
4362 * concatenating many lines. */
4363 if (ga.ga_len > 400)
4364 {
4365 if (ga.ga_len > 8000)
4366 ga.ga_growsize = 8000;
4367 else
4368 ga.ga_growsize = ga.ga_len;
4369 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004370 ga_concat(&ga, p + 1);
4371 }
4372 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004373 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004374 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004375 }
4376 }
4377
4378#ifdef FEAT_MBYTE
4379 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4380 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004381 char_u *s;
4382
Bram Moolenaar071d4272004-06-13 20:20:40 +00004383 /* Convert the encoding of the script line. */
4384 s = string_convert(&sp->conv, line, NULL);
4385 if (s != NULL)
4386 {
4387 vim_free(line);
4388 line = s;
4389 }
4390 }
4391#endif
4392
4393#ifdef FEAT_EVAL
4394 /* Did we encounter a breakpoint? */
4395 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4396 {
4397 dbg_breakpoint(sp->fname, sourcing_lnum);
4398 /* Find next breakpoint. */
4399 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4400 sp->dbg_tick = debug_tick;
4401 }
4402#endif
4403
4404 return line;
4405}
4406
4407 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004408get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004409{
4410 garray_T ga;
4411 int len;
4412 int c;
4413 char_u *buf;
4414#ifdef USE_CRNL
4415 int has_cr; /* CR-LF found */
4416#endif
4417#ifdef USE_CR
4418 char_u *scan;
4419#endif
4420 int have_read = FALSE;
4421
4422 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004423 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424
4425 /*
4426 * Loop until there is a finished line (or end-of-file).
4427 */
4428 sourcing_lnum++;
4429 for (;;)
4430 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004431 /* make room to read at least 120 (more) characters */
4432 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 break;
4434 buf = (char_u *)ga.ga_data;
4435
4436#ifdef USE_CR
4437 if (sp->fileformat == EOL_MAC)
4438 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004439 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4440 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004441 break;
4442 }
4443 else
4444#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004445 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4446 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004448 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449#ifdef USE_CRNL
4450 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4451 * CTRL-Z by its own, or after a NL. */
4452 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4453 && sp->fileformat == EOL_DOS
4454 && buf[len - 1] == Ctrl_Z)
4455 {
4456 buf[len - 1] = NUL;
4457 break;
4458 }
4459#endif
4460
4461#ifdef USE_CR
4462 /* If the read doesn't stop on a new line, and there's
4463 * some CR then we assume a Mac format */
4464 if (sp->fileformat == EOL_UNKNOWN)
4465 {
4466 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4467 sp->fileformat = EOL_MAC;
4468 else
4469 sp->fileformat = EOL_UNIX;
4470 }
4471
4472 if (sp->fileformat == EOL_MAC)
4473 {
4474 scan = vim_strchr(buf, '\r');
4475
4476 if (scan != NULL)
4477 {
4478 *scan = '\n';
4479 if (*(scan + 1) != 0)
4480 {
4481 *(scan + 1) = 0;
4482 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4483 }
4484 }
4485 len = STRLEN(buf);
4486 }
4487#endif
4488
4489 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004490 ga.ga_len = len;
4491
4492 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004493 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494 continue;
4495
4496 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4497 {
4498#ifdef USE_CRNL
4499 has_cr = (len >= 2 && buf[len - 2] == '\r');
4500 if (sp->fileformat == EOL_UNKNOWN)
4501 {
4502 if (has_cr)
4503 sp->fileformat = EOL_DOS;
4504 else
4505 sp->fileformat = EOL_UNIX;
4506 }
4507
4508 if (sp->fileformat == EOL_DOS)
4509 {
4510 if (has_cr) /* replace trailing CR */
4511 {
4512 buf[len - 2] = '\n';
4513 --len;
4514 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004515 }
4516 else /* lines like ":map xx yy^M" will have failed */
4517 {
4518 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004519 {
4520 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004521 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004522 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004523 sp->error = TRUE;
4524 sp->fileformat = EOL_UNIX;
4525 }
4526 }
4527#endif
4528 /* The '\n' is escaped if there is an odd number of ^V's just
4529 * before it, first set "c" just before the 'V's and then check
4530 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4531 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4532 ;
4533 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4534 {
4535 sourcing_lnum++;
4536 continue;
4537 }
4538
4539 buf[len - 1] = NUL; /* remove the NL */
4540 }
4541
4542 /*
4543 * Check for ^C here now and then, so recursive :so can be broken.
4544 */
4545 line_breakcheck();
4546 break;
4547 }
4548
4549 if (have_read)
4550 return (char_u *)ga.ga_data;
4551
4552 vim_free(ga.ga_data);
4553 return NULL;
4554}
4555
Bram Moolenaar05159a02005-02-26 23:04:13 +00004556#if defined(FEAT_PROFILE) || defined(PROTO)
4557/*
4558 * Called when starting to read a script line.
4559 * "sourcing_lnum" must be correct!
4560 * When skipping lines it may not actually be executed, but we won't find out
4561 * until later and we need to store the time now.
4562 */
4563 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004564script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004565{
4566 scriptitem_T *si;
4567 sn_prl_T *pp;
4568
4569 if (current_SID <= 0 || current_SID > script_items.ga_len)
4570 return;
4571 si = &SCRIPT_ITEM(current_SID);
4572 if (si->sn_prof_on && sourcing_lnum >= 1)
4573 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004574 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004575 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004576 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004577 si->sn_prl_idx = sourcing_lnum - 1;
4578 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4579 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4580 {
4581 /* Zero counters for a line that was not used before. */
4582 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4583 pp->snp_count = 0;
4584 profile_zero(&pp->sn_prl_total);
4585 profile_zero(&pp->sn_prl_self);
4586 ++si->sn_prl_ga.ga_len;
4587 }
4588 si->sn_prl_execed = FALSE;
4589 profile_start(&si->sn_prl_start);
4590 profile_zero(&si->sn_prl_children);
4591 profile_get_wait(&si->sn_prl_wait);
4592 }
4593}
4594
4595/*
4596 * Called when actually executing a function line.
4597 */
4598 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004599script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004600{
4601 scriptitem_T *si;
4602
4603 if (current_SID <= 0 || current_SID > script_items.ga_len)
4604 return;
4605 si = &SCRIPT_ITEM(current_SID);
4606 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4607 si->sn_prl_execed = TRUE;
4608}
4609
4610/*
4611 * Called when done with a function line.
4612 */
4613 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004614script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004615{
4616 scriptitem_T *si;
4617 sn_prl_T *pp;
4618
4619 if (current_SID <= 0 || current_SID > script_items.ga_len)
4620 return;
4621 si = &SCRIPT_ITEM(current_SID);
4622 if (si->sn_prof_on && si->sn_prl_idx >= 0
4623 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4624 {
4625 if (si->sn_prl_execed)
4626 {
4627 pp = &PRL_ITEM(si, si->sn_prl_idx);
4628 ++pp->snp_count;
4629 profile_end(&si->sn_prl_start);
4630 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004631 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004632 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4633 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004634 }
4635 si->sn_prl_idx = -1;
4636 }
4637}
4638#endif
4639
Bram Moolenaar071d4272004-06-13 20:20:40 +00004640/*
4641 * ":scriptencoding": Set encoding conversion for a sourced script.
4642 * Without the multi-byte feature it's simply ignored.
4643 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004645ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004646{
4647#ifdef FEAT_MBYTE
4648 struct source_cookie *sp;
4649 char_u *name;
4650
4651 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4652 {
4653 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4654 return;
4655 }
4656
4657 if (*eap->arg != NUL)
4658 {
4659 name = enc_canonize(eap->arg);
4660 if (name == NULL) /* out of memory */
4661 return;
4662 }
4663 else
4664 name = eap->arg;
4665
4666 /* Setup for conversion from the specified encoding to 'encoding'. */
4667 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4668 convert_setup(&sp->conv, name, p_enc);
4669
4670 if (name != eap->arg)
4671 vim_free(name);
4672#endif
4673}
4674
4675#if defined(FEAT_EVAL) || defined(PROTO)
4676/*
4677 * ":finish": Mark a sourced file as finished.
4678 */
4679 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004680ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681{
4682 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4683 do_finish(eap, FALSE);
4684 else
4685 EMSG(_("E168: :finish used outside of a sourced file"));
4686}
4687
4688/*
4689 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4690 * Also called for a pending finish at the ":endtry" or after returning from
4691 * an extra do_cmdline(). "reanimate" is used in the latter case.
4692 */
4693 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004694do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004695{
4696 int idx;
4697
4698 if (reanimate)
4699 ((struct source_cookie *)getline_cookie(eap->getline,
4700 eap->cookie))->finished = FALSE;
4701
4702 /*
4703 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4704 * not in its finally clause (which then is to be executed next) is found.
4705 * In this case, make the ":finish" pending for execution at the ":endtry".
4706 * Otherwise, finish normally.
4707 */
4708 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4709 if (idx >= 0)
4710 {
4711 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4712 report_make_pending(CSTP_FINISH, NULL);
4713 }
4714 else
4715 ((struct source_cookie *)getline_cookie(eap->getline,
4716 eap->cookie))->finished = TRUE;
4717}
4718
4719
4720/*
4721 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4722 * message for missing ":endif".
4723 * Return FALSE when not sourcing a file.
4724 */
4725 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004726source_finished(
4727 char_u *(*fgetline)(int, void *, int),
4728 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004730 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004731 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004732 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004733}
4734#endif
4735
4736#if defined(FEAT_LISTCMDS) || defined(PROTO)
4737/*
4738 * ":checktime [buffer]"
4739 */
4740 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004741ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742{
4743 buf_T *buf;
4744 int save_no_check_timestamps = no_check_timestamps;
4745
4746 no_check_timestamps = 0;
4747 if (eap->addr_count == 0) /* default is all buffers */
4748 check_timestamps(FALSE);
4749 else
4750 {
4751 buf = buflist_findnr((int)eap->line2);
4752 if (buf != NULL) /* cannot happen? */
4753 (void)buf_check_timestamp(buf, FALSE);
4754 }
4755 no_check_timestamps = save_no_check_timestamps;
4756}
4757#endif
4758
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4760 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004761# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004762static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004763
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004764 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004765get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004766{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004767 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004768
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004769 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004770 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004771
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004772# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004773 if (loc != NULL)
4774 {
4775 char_u *p;
4776
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004777 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4778 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779 p = vim_strchr(loc, '=');
4780 if (p != NULL)
4781 {
4782 loc = ++p;
4783 while (*p != NUL) /* remove trailing newline */
4784 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004785 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 {
4787 *p = NUL;
4788 break;
4789 }
4790 ++p;
4791 }
4792 }
4793 }
4794# endif
4795
4796 return loc;
4797}
4798#endif
4799
4800
4801#ifdef WIN32
4802/*
4803 * On MS-Windows locale names are strings like "German_Germany.1252", but
4804 * gettext expects "de". Try to translate one into another here for a few
4805 * supported languages.
4806 */
4807 static char_u *
4808gettext_lang(char_u *name)
4809{
4810 int i;
4811 static char *(mtable[]) = {
4812 "afrikaans", "af",
4813 "czech", "cs",
4814 "dutch", "nl",
4815 "german", "de",
4816 "english_united kingdom", "en_GB",
4817 "spanish", "es",
4818 "french", "fr",
4819 "italian", "it",
4820 "japanese", "ja",
4821 "korean", "ko",
4822 "norwegian", "no",
4823 "polish", "pl",
4824 "russian", "ru",
4825 "slovak", "sk",
4826 "swedish", "sv",
4827 "ukrainian", "uk",
4828 "chinese_china", "zh_CN",
4829 "chinese_taiwan", "zh_TW",
4830 NULL};
4831
4832 for (i = 0; mtable[i] != NULL; i += 2)
4833 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004834 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004835 return name;
4836}
4837#endif
4838
4839#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4840/*
4841 * Obtain the current messages language. Used to set the default for
4842 * 'helplang'. May return NULL or an empty string.
4843 */
4844 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004845get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004846{
4847 char_u *p;
4848
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004849# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004850# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004851 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004852# else
4853 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004854 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4855 * and LC_MONETARY may be set differently for a Japanese working in the
4856 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004857 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004858# endif
4859# else
4860 p = mch_getenv((char_u *)"LC_ALL");
4861 if (p == NULL || *p == NUL)
4862 {
4863 p = mch_getenv((char_u *)"LC_MESSAGES");
4864 if (p == NULL || *p == NUL)
4865 p = mch_getenv((char_u *)"LANG");
4866 }
4867# endif
4868# ifdef WIN32
4869 p = gettext_lang(p);
4870# endif
4871 return p;
4872}
4873#endif
4874
Bram Moolenaardef9e822004-12-31 20:58:58 +00004875/* Complicated #if; matches with where get_mess_env() is used below. */
4876#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4877 && defined(LC_MESSAGES))) \
4878 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4879 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4880 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004881static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004882
4883/*
4884 * Get the language used for messages from the environment.
4885 */
4886 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004887get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004888{
4889 char_u *p;
4890
4891 p = mch_getenv((char_u *)"LC_ALL");
4892 if (p == NULL || *p == NUL)
4893 {
4894 p = mch_getenv((char_u *)"LC_MESSAGES");
4895 if (p == NULL || *p == NUL)
4896 {
4897 p = mch_getenv((char_u *)"LANG");
4898 if (p != NULL && VIM_ISDIGIT(*p))
4899 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004900# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004902 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004903# endif
4904 }
4905 }
4906 return p;
4907}
4908#endif
4909
4910#if defined(FEAT_EVAL) || defined(PROTO)
4911
4912/*
4913 * Set the "v:lang" variable according to the current locale setting.
4914 * Also do "v:lc_time"and "v:ctype".
4915 */
4916 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004917set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918{
4919 char_u *loc;
4920
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004921# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004922 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004923# else
4924 /* setlocale() not supported: use the default value */
4925 loc = (char_u *)"C";
4926# endif
4927 set_vim_var_string(VV_CTYPE, loc, -1);
4928
4929 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4930 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004931# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004932 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933# else
4934 loc = get_mess_env();
4935# endif
4936 set_vim_var_string(VV_LANG, loc, -1);
4937
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004938# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004939 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004940# endif
4941 set_vim_var_string(VV_LC_TIME, loc, -1);
4942}
4943#endif
4944
4945#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4946 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4947/*
4948 * ":language": Set the language (locale).
4949 */
4950 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004951ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952{
4953 char *loc;
4954 char_u *p;
4955 char_u *name;
4956 int what = LC_ALL;
4957 char *whatstr = "";
4958#ifdef LC_MESSAGES
4959# define VIM_LC_MESSAGES LC_MESSAGES
4960#else
4961# define VIM_LC_MESSAGES 6789
4962#endif
4963
4964 name = eap->arg;
4965
4966 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4967 * Allow abbreviation, but require at least 3 characters to avoid
4968 * confusion with a two letter language name "me" or "ct". */
4969 p = skiptowhite(eap->arg);
4970 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4971 {
4972 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4973 {
4974 what = VIM_LC_MESSAGES;
4975 name = skipwhite(p);
4976 whatstr = "messages ";
4977 }
4978 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4979 {
4980 what = LC_CTYPE;
4981 name = skipwhite(p);
4982 whatstr = "ctype ";
4983 }
4984 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4985 {
4986 what = LC_TIME;
4987 name = skipwhite(p);
4988 whatstr = "time ";
4989 }
4990 }
4991
4992 if (*name == NUL)
4993 {
4994#ifndef LC_MESSAGES
4995 if (what == VIM_LC_MESSAGES)
4996 p = get_mess_env();
4997 else
4998#endif
4999 p = (char_u *)setlocale(what, NULL);
5000 if (p == NULL || *p == NUL)
5001 p = (char_u *)"Unknown";
5002 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
5003 }
5004 else
5005 {
5006#ifndef LC_MESSAGES
5007 if (what == VIM_LC_MESSAGES)
5008 loc = "";
5009 else
5010#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005011 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005012 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005013#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
5014 /* Make sure strtod() uses a decimal point, not a comma. */
5015 setlocale(LC_NUMERIC, "C");
5016#endif
5017 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005018 if (loc == NULL)
5019 EMSG2(_("E197: Cannot set language to \"%s\""), name);
5020 else
5021 {
5022#ifdef HAVE_NL_MSG_CAT_CNTR
5023 /* Need to do this for GNU gettext, otherwise cached translations
5024 * will be used again. */
5025 extern int _nl_msg_cat_cntr;
5026
5027 ++_nl_msg_cat_cntr;
5028#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00005029 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005030 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
5031
5032 if (what != LC_TIME)
5033 {
5034 /* Tell gettext() what to translate to. It apparently doesn't
5035 * use the currently effective locale. Also do this when
5036 * FEAT_GETTEXT isn't defined, so that shell commands use this
5037 * value. */
5038 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005039 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005040 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02005041
5042 /* Clear $LANGUAGE because GNU gettext uses it. */
5043 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005044# ifdef WIN32
5045 /* Apparently MS-Windows printf() may cause a crash when
5046 * we give it 8-bit text while it's expecting text in the
5047 * current locale. This call avoids that. */
5048 setlocale(LC_CTYPE, "C");
5049# endif
5050 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051 if (what != LC_CTYPE)
5052 {
5053 char_u *mname;
5054#ifdef WIN32
5055 mname = gettext_lang(name);
5056#else
5057 mname = name;
5058#endif
5059 vim_setenv((char_u *)"LC_MESSAGES", mname);
5060#ifdef FEAT_MULTI_LANG
5061 set_helplang_default(mname);
5062#endif
5063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005064 }
5065
5066# ifdef FEAT_EVAL
5067 /* Set v:lang, v:lc_time and v:ctype to the final result. */
5068 set_lang_var();
5069# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02005070# ifdef FEAT_TITLE
5071 maketitle();
5072# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005073 }
5074 }
5075}
5076
5077# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005078
5079static char_u **locales = NULL; /* Array of all available locales */
5080static int did_init_locales = FALSE;
5081
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01005082static void init_locales(void);
5083static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005084
5085/*
5086 * Lazy initialization of all available locales.
5087 */
5088 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005089init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005090{
5091 if (!did_init_locales)
5092 {
5093 did_init_locales = TRUE;
5094 locales = find_locales();
5095 }
5096}
5097
5098/* Return an array of strings for all available locales + NULL for the
5099 * last element. Return NULL in case of error. */
5100 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005101find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005102{
5103 garray_T locales_ga;
5104 char_u *loc;
5105
5106 /* Find all available locales by running command "locale -a". If this
5107 * doesn't work we won't have completion. */
5108 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02005109 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005110 if (locale_a == NULL)
5111 return NULL;
5112 ga_init2(&locales_ga, sizeof(char_u *), 20);
5113
5114 /* Transform locale_a string where each locale is separated by "\n"
5115 * into an array of locale strings. */
5116 loc = (char_u *)strtok((char *)locale_a, "\n");
5117
5118 while (loc != NULL)
5119 {
5120 if (ga_grow(&locales_ga, 1) == FAIL)
5121 break;
5122 loc = vim_strsave(loc);
5123 if (loc == NULL)
5124 break;
5125
5126 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
5127 loc = (char_u *)strtok(NULL, "\n");
5128 }
5129 vim_free(locale_a);
5130 if (ga_grow(&locales_ga, 1) == FAIL)
5131 {
5132 ga_clear(&locales_ga);
5133 return NULL;
5134 }
5135 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
5136 return (char_u **)locales_ga.ga_data;
5137}
5138
5139# if defined(EXITFREE) || defined(PROTO)
5140 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005141free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005142{
5143 int i;
5144 if (locales != NULL)
5145 {
5146 for (i = 0; locales[i] != NULL; i++)
5147 vim_free(locales[i]);
5148 vim_free(locales);
5149 locales = NULL;
5150 }
5151}
5152# endif
5153
Bram Moolenaar071d4272004-06-13 20:20:40 +00005154/*
5155 * Function given to ExpandGeneric() to obtain the possible arguments of the
5156 * ":language" command.
5157 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005158 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005159get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005160{
5161 if (idx == 0)
5162 return (char_u *)"messages";
5163 if (idx == 1)
5164 return (char_u *)"ctype";
5165 if (idx == 2)
5166 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005167
5168 init_locales();
5169 if (locales == NULL)
5170 return NULL;
5171 return locales[idx - 3];
5172}
5173
5174/*
5175 * Function given to ExpandGeneric() to obtain the available locales.
5176 */
5177 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005178get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005179{
5180 init_locales();
5181 if (locales == NULL)
5182 return NULL;
5183 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005184}
5185# endif
5186
5187#endif