blob: 4ddfbe421d862790e3556b4e15bfb7d10a5094c6 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
Bram Moolenaarf1f60f82016-01-16 15:40:53 +010071static int get_maxbacktrace_level(void);
72static void do_setdebugtracelevel(char_u *arg);
73static void do_checkbacktracelevel(void);
74static void do_showbacktrace(char_u *cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +000075
76/*
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
79 */
80 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010081do_debug(char_u *cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +000082{
83 int save_msg_scroll = msg_scroll;
84 int save_State = State;
85 int save_did_emsg = did_emsg;
86 int save_cmd_silent = cmd_silent;
87 int save_msg_silent = msg_silent;
88 int save_emsg_silent = emsg_silent;
89 int save_redir_off = redir_off;
90 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000091 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000092 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 int save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 int n;
95 char_u *cmdline = NULL;
96 char_u *p;
97 char *tail = NULL;
98 static int last_cmd = 0;
99#define CMD_CONT 1
100#define CMD_NEXT 2
101#define CMD_STEP 3
102#define CMD_FINISH 4
103#define CMD_QUIT 5
104#define CMD_INTERRUPT 6
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100105#define CMD_BACKTRACE 7
106#define CMD_FRAME 8
107#define CMD_UP 9
108#define CMD_DOWN 10
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109
110#ifdef ALWAYS_USE_GUI
111 /* Can't do this when there is no terminal for input/output. */
112 if (!gui.in_use)
113 {
114 /* Break as soon as possible. */
115 debug_break_level = 9999;
116 return;
117 }
118#endif
119
120 /* Make sure we are in raw mode and start termcap mode. Might have side
121 * effects... */
122 settmode(TMODE_RAW);
123 starttermcap();
124
125 ++RedrawingDisabled; /* don't redisplay the window */
126 ++no_wait_return; /* don't wait for return */
127 did_emsg = FALSE; /* don't use error from debugged stuff */
128 cmd_silent = FALSE; /* display commands */
129 msg_silent = FALSE; /* display messages */
130 emsg_silent = FALSE; /* display error messages */
131 redir_off = TRUE; /* don't redirect debug commands */
132
133 State = NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134
135 if (!debug_did_msg)
136 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
137 if (sourcing_name != NULL)
138 msg(sourcing_name);
139 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000142 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143
144 /*
145 * Repeat getting a command and executing it.
146 */
147 for (;;)
148 {
149 msg_scroll = TRUE;
150 need_wait_return = FALSE;
Bram Moolenaar85b11762016-02-27 18:13:23 +0100151
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 save_ex_normal_busy = ex_normal_busy;
158 ex_normal_busy = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000160 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 typeahead_saved = TRUE;
163 save_ignore_script = ignore_script;
164 ignore_script = TRUE;
165 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000167 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000169 if (typeahead_saved)
170 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000172 ignore_script = save_ignore_script;
173 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175
176 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100177 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000178 if (cmdline != NULL)
179 {
180 /* If this is a debug command, set "last_cmd".
181 * If not, reset "last_cmd".
182 * For a blank line use previous command. */
183 p = skipwhite(cmdline);
184 if (*p != NUL)
185 {
186 switch (*p)
187 {
188 case 'c': last_cmd = CMD_CONT;
189 tail = "ont";
190 break;
191 case 'n': last_cmd = CMD_NEXT;
192 tail = "ext";
193 break;
194 case 's': last_cmd = CMD_STEP;
195 tail = "tep";
196 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100197 case 'f':
198 last_cmd = 0;
199 if (p[1] == 'r')
200 {
201 last_cmd = CMD_FRAME;
202 tail = "rame";
203 }
204 else
205 {
206 last_cmd = CMD_FINISH;
207 tail = "inish";
208 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209 break;
210 case 'q': last_cmd = CMD_QUIT;
211 tail = "uit";
212 break;
213 case 'i': last_cmd = CMD_INTERRUPT;
214 tail = "nterrupt";
215 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100216 case 'b': last_cmd = CMD_BACKTRACE;
217 if (p[1] == 't')
218 tail = "t";
219 else
220 tail = "acktrace";
221 break;
222 case 'w': last_cmd = CMD_BACKTRACE;
223 tail = "here";
224 break;
225 case 'u': last_cmd = CMD_UP;
226 tail = "p";
227 break;
228 case 'd': last_cmd = CMD_DOWN;
229 tail = "own";
230 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231 default: last_cmd = 0;
232 }
233 if (last_cmd != 0)
234 {
235 /* Check that the tail matches. */
236 ++p;
237 while (*p != NUL && *p == *tail)
238 {
239 ++p;
240 ++tail;
241 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100242 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000243 last_cmd = 0;
244 }
245 }
246
247 if (last_cmd != 0)
248 {
249 /* Execute debug command: decided where to break next and
250 * return. */
251 switch (last_cmd)
252 {
253 case CMD_CONT:
254 debug_break_level = -1;
255 break;
256 case CMD_NEXT:
257 debug_break_level = ex_nesting_level;
258 break;
259 case CMD_STEP:
260 debug_break_level = 9999;
261 break;
262 case CMD_FINISH:
263 debug_break_level = ex_nesting_level - 1;
264 break;
265 case CMD_QUIT:
266 got_int = TRUE;
267 debug_break_level = -1;
268 break;
269 case CMD_INTERRUPT:
270 got_int = TRUE;
271 debug_break_level = 9999;
272 /* Do not repeat ">interrupt" cmd, continue stepping. */
273 last_cmd = CMD_STEP;
274 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100275 case CMD_BACKTRACE:
276 do_showbacktrace(cmd);
277 continue;
278 case CMD_FRAME:
279 if (*p == NUL)
280 {
281 do_showbacktrace(cmd);
282 }
283 else
284 {
285 p = skipwhite(p);
286 do_setdebugtracelevel(p);
287 }
288 continue;
289 case CMD_UP:
290 debug_backtrace_level++;
291 do_checkbacktracelevel();
292 continue;
293 case CMD_DOWN:
294 debug_backtrace_level--;
295 do_checkbacktracelevel();
296 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000297 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100298 /* Going out reset backtrace_level */
299 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000300 break;
301 }
302
303 /* don't debug this command */
304 n = debug_break_level;
305 debug_break_level = -1;
306 (void)do_cmdline(cmdline, getexline, NULL,
307 DOCMD_VERBOSE|DOCMD_EXCRESET);
308 debug_break_level = n;
309
310 vim_free(cmdline);
311 }
312 lines_left = Rows - 1;
313 }
314 vim_free(cmdline);
315
316 --RedrawingDisabled;
317 --no_wait_return;
318 redraw_all_later(NOT_VALID);
319 need_wait_return = FALSE;
320 msg_scroll = save_msg_scroll;
321 lines_left = Rows - 1;
322 State = save_State;
323 did_emsg = save_did_emsg;
324 cmd_silent = save_cmd_silent;
325 msg_silent = save_msg_silent;
326 emsg_silent = save_emsg_silent;
327 redir_off = save_redir_off;
328
329 /* Only print the message again when typing a command before coming back
330 * here. */
331 debug_did_msg = TRUE;
332}
333
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100334 static int
335get_maxbacktrace_level(void)
336{
337 char *p, *q;
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200338 int maxbacktrace = 0;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100339
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100340 if (sourcing_name != NULL)
341 {
342 p = (char *)sourcing_name;
343 while ((q = strstr(p, "..")) != NULL)
344 {
345 p = q + 2;
346 maxbacktrace++;
347 }
348 }
349 return maxbacktrace;
350}
351
352 static void
353do_setdebugtracelevel(char_u *arg)
354{
355 int level;
356
357 level = atoi((char *)arg);
358 if (*arg == '+' || level < 0)
359 debug_backtrace_level += level;
360 else
361 debug_backtrace_level = level;
362
363 do_checkbacktracelevel();
364}
365
366 static void
367do_checkbacktracelevel(void)
368{
369 if (debug_backtrace_level < 0)
370 {
371 debug_backtrace_level = 0;
372 MSG(_("frame is zero"));
373 }
374 else
375 {
376 int max = get_maxbacktrace_level();
377
378 if (debug_backtrace_level > max)
379 {
380 debug_backtrace_level = max;
381 smsg((char_u *)_("frame at highest level: %d"), max);
382 }
383 }
384}
385
386 static void
387do_showbacktrace(char_u *cmd)
388{
389 char *cur;
390 char *next;
391 int i = 0;
392 int max = get_maxbacktrace_level();
393
394 if (sourcing_name != NULL)
395 {
396 cur = (char *)sourcing_name;
397 while (!got_int)
398 {
399 next = strstr(cur, "..");
400 if (next != NULL)
401 *next = NUL;
402 if (i == max - debug_backtrace_level)
403 smsg((char_u *)"->%d %s", max - i, cur);
404 else
405 smsg((char_u *)" %d %s", max - i, cur);
406 ++i;
407 if (next == NULL)
408 break;
409 *next = '.';
410 cur = next + 2;
411 }
412 }
413 if (sourcing_lnum != 0)
414 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
415 else
416 smsg((char_u *)_("cmd: %s"), cmd);
417}
418
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419/*
420 * ":debug".
421 */
422 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100423ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424{
425 int debug_break_level_save = debug_break_level;
426
427 debug_break_level = 9999;
428 do_cmdline_cmd(eap->arg);
429 debug_break_level = debug_break_level_save;
430}
431
432static char_u *debug_breakpoint_name = NULL;
433static linenr_T debug_breakpoint_lnum;
434
435/*
436 * When debugging or a breakpoint is set on a skipped command, no debug prompt
437 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
438 * debug_skipped_name is then set to the source name in the breakpoint case. If
439 * a skipped command decides itself that a debug prompt should be displayed, it
440 * can do so by calling dbg_check_skipped().
441 */
442static int debug_skipped;
443static char_u *debug_skipped_name;
444
445/*
446 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
447 * at or below the break level. But only when the line is actually
448 * executed. Return TRUE and set breakpoint_name for skipped commands that
449 * decide to execute something themselves.
450 * Called from do_one_cmd() before executing a command.
451 */
452 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100453dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454{
455 char_u *p;
456
457 debug_skipped = FALSE;
458 if (debug_breakpoint_name != NULL)
459 {
460 if (!eap->skip)
461 {
462 /* replace K_SNR with "<SNR>" */
463 if (debug_breakpoint_name[0] == K_SPECIAL
464 && debug_breakpoint_name[1] == KS_EXTRA
465 && debug_breakpoint_name[2] == (int)KE_SNR)
466 p = (char_u *)"<SNR>";
467 else
468 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000469 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
470 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000471 debug_breakpoint_name + (*p == NUL ? 0 : 3),
472 (long)debug_breakpoint_lnum);
473 debug_breakpoint_name = NULL;
474 do_debug(eap->cmd);
475 }
476 else
477 {
478 debug_skipped = TRUE;
479 debug_skipped_name = debug_breakpoint_name;
480 debug_breakpoint_name = NULL;
481 }
482 }
483 else if (ex_nesting_level <= debug_break_level)
484 {
485 if (!eap->skip)
486 do_debug(eap->cmd);
487 else
488 {
489 debug_skipped = TRUE;
490 debug_skipped_name = NULL;
491 }
492 }
493}
494
495/*
496 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
497 * set. Return TRUE when the debug mode is entered this time.
498 */
499 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100500dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000501{
502 int prev_got_int;
503
504 if (debug_skipped)
505 {
506 /*
507 * Save the value of got_int and reset it. We don't want a previous
508 * interruption cause flushing the input buffer.
509 */
510 prev_got_int = got_int;
511 got_int = FALSE;
512 debug_breakpoint_name = debug_skipped_name;
513 /* eap->skip is TRUE */
514 eap->skip = FALSE;
515 (void)dbg_check_breakpoint(eap);
516 eap->skip = TRUE;
517 got_int |= prev_got_int;
518 return TRUE;
519 }
520 return FALSE;
521}
522
523/*
524 * The list of breakpoints: dbg_breakp.
525 * This is a grow-array of structs.
526 */
527struct debuggy
528{
529 int dbg_nr; /* breakpoint number */
530 int dbg_type; /* DBG_FUNC or DBG_FILE */
531 char_u *dbg_name; /* function or file name */
532 regprog_T *dbg_prog; /* regexp program */
533 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000534 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000535};
536
537static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000538#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
539#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540static int last_breakp = 0; /* nr of last defined breakpoint */
541
Bram Moolenaar05159a02005-02-26 23:04:13 +0000542#ifdef FEAT_PROFILE
543/* Profiling uses file and func names similar to breakpoints. */
544static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
545#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546#define DBG_FUNC 1
547#define DBG_FILE 2
548
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100549static int dbg_parsearg(char_u *arg, garray_T *gap);
550static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551
552/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000553 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
554 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
555 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556 * Returns FAIL for failure.
557 */
558 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100559dbg_parsearg(
560 char_u *arg,
561 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000562{
563 char_u *p = arg;
564 char_u *q;
565 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000566 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567
Bram Moolenaar05159a02005-02-26 23:04:13 +0000568 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000569 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000570 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571
572 /* Find "func" or "file". */
573 if (STRNCMP(p, "func", 4) == 0)
574 bp->dbg_type = DBG_FUNC;
575 else if (STRNCMP(p, "file", 4) == 0)
576 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000577 else if (
578#ifdef FEAT_PROFILE
579 gap != &prof_ga &&
580#endif
581 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000582 {
583 if (curbuf->b_ffname == NULL)
584 {
585 EMSG(_(e_noname));
586 return FAIL;
587 }
588 bp->dbg_type = DBG_FILE;
589 here = TRUE;
590 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591 else
592 {
593 EMSG2(_(e_invarg2), p);
594 return FAIL;
595 }
596 p = skipwhite(p + 4);
597
598 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000599 if (here)
600 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000601 else if (
602#ifdef FEAT_PROFILE
603 gap != &prof_ga &&
604#endif
605 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606 {
607 bp->dbg_lnum = getdigits(&p);
608 p = skipwhite(p);
609 }
610 else
611 bp->dbg_lnum = 0;
612
613 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000614 if ((!here && *p == NUL)
615 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000616 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
617 {
618 EMSG2(_(e_invarg2), arg);
619 return FAIL;
620 }
621
622 if (bp->dbg_type == DBG_FUNC)
623 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000624 else if (here)
625 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626 else
627 {
628 /* Expand the file name in the same way as do_source(). This means
629 * doing it twice, so that $DIR/file gets expanded when $DIR is
630 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 if (q == NULL)
633 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635 vim_free(q);
636 if (p == NULL)
637 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000638 if (*p != '*')
639 {
640 bp->dbg_name = fix_fname(p);
641 vim_free(p);
642 }
643 else
644 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645 }
646
647 if (bp->dbg_name == NULL)
648 return FAIL;
649 return OK;
650}
651
652/*
653 * ":breakadd".
654 */
655 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100656ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000657{
658 struct debuggy *bp;
659 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000660 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661
Bram Moolenaar05159a02005-02-26 23:04:13 +0000662 gap = &dbg_breakp;
663#ifdef FEAT_PROFILE
664 if (eap->cmdidx == CMD_profile)
665 gap = &prof_ga;
666#endif
667
668 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000669 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000670 bp = &DEBUGGY(gap, gap->ga_len);
671 bp->dbg_forceit = eap->forceit;
672
Bram Moolenaar071d4272004-06-13 20:20:40 +0000673 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
674 if (pat != NULL)
675 {
676 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
677 vim_free(pat);
678 }
679 if (pat == NULL || bp->dbg_prog == NULL)
680 vim_free(bp->dbg_name);
681 else
682 {
683 if (bp->dbg_lnum == 0) /* default line number is 1 */
684 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000685#ifdef FEAT_PROFILE
686 if (eap->cmdidx != CMD_profile)
687#endif
688 {
689 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
690 ++debug_tick;
691 }
692 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000693 }
694 }
695}
696
697/*
698 * ":debuggreedy".
699 */
700 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100701ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000702{
703 if (eap->addr_count == 0 || eap->line2 != 0)
704 debug_greedy = TRUE;
705 else
706 debug_greedy = FALSE;
707}
708
709/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000710 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711 */
712 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100713ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000714{
715 struct debuggy *bp, *bpi;
716 int nr;
717 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000718 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 int i;
720 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000721 garray_T *gap;
722
723 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000724 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200725 {
726#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000727 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200728#else
729 ex_ni(eap);
730 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000731#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200732 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000733
734 if (vim_isdigit(*eap->arg))
735 {
736 /* ":breakdel {nr}" */
737 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000738 for (i = 0; i < gap->ga_len; ++i)
739 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740 {
741 todel = i;
742 break;
743 }
744 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000745 else if (*eap->arg == '*')
746 {
747 todel = 0;
748 del_all = TRUE;
749 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000750 else
751 {
752 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000753 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000755 bp = &DEBUGGY(gap, gap->ga_len);
756 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000758 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 if (bp->dbg_type == bpi->dbg_type
760 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
761 && (bp->dbg_lnum == bpi->dbg_lnum
762 || (bp->dbg_lnum == 0
763 && (best_lnum == 0
764 || bpi->dbg_lnum < best_lnum))))
765 {
766 todel = i;
767 best_lnum = bpi->dbg_lnum;
768 }
769 }
770 vim_free(bp->dbg_name);
771 }
772
773 if (todel < 0)
774 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
775 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000776 {
777 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000778 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000779 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200780 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000781 --gap->ga_len;
782 if (todel < gap->ga_len)
783 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
784 (gap->ga_len - todel) * sizeof(struct debuggy));
785#ifdef FEAT_PROFILE
786 if (eap->cmdidx == CMD_breakdel)
787#endif
788 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000789 if (!del_all)
790 break;
791 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000792
793 /* If all breakpoints were removed clear the array. */
794 if (gap->ga_len == 0)
795 ga_clear(gap);
796 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000797}
798
799/*
800 * ":breaklist".
801 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100803ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804{
805 struct debuggy *bp;
806 int i;
807
808 if (dbg_breakp.ga_len == 0)
809 MSG(_("No breakpoints defined"));
810 else
811 for (i = 0; i < dbg_breakp.ga_len; ++i)
812 {
813 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200814 if (bp->dbg_type == DBG_FILE)
815 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816 smsg((char_u *)_("%3d %s %s line %ld"),
817 bp->dbg_nr,
818 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200819 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820 (long)bp->dbg_lnum);
821 }
822}
823
824/*
825 * Find a breakpoint for a function or sourced file.
826 * Returns line number at which to break; zero when no matching breakpoint.
827 */
828 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100829dbg_find_breakpoint(
830 int file, /* TRUE for a file, FALSE for a function */
831 char_u *fname, /* file or function name */
832 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000833{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000834 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
835}
836
837#if defined(FEAT_PROFILE) || defined(PROTO)
838/*
839 * Return TRUE if profiling is on for a function or sourced file.
840 */
841 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100842has_profiling(
843 int file, /* TRUE for a file, FALSE for a function */
844 char_u *fname, /* file or function name */
845 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000846{
847 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
848 != (linenr_T)0);
849}
850#endif
851
852/*
853 * Common code for dbg_find_breakpoint() and has_profiling().
854 */
855 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100856debuggy_find(
857 int file, /* TRUE for a file, FALSE for a function */
858 char_u *fname, /* file or function name */
859 linenr_T after, /* after this line number */
860 garray_T *gap, /* either &dbg_breakp or &prof_ga */
861 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000862{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863 struct debuggy *bp;
864 int i;
865 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000866 char_u *name = fname;
867 int prev_got_int;
868
Bram Moolenaar05159a02005-02-26 23:04:13 +0000869 /* Return quickly when there are no breakpoints. */
870 if (gap->ga_len == 0)
871 return (linenr_T)0;
872
Bram Moolenaar071d4272004-06-13 20:20:40 +0000873 /* Replace K_SNR in function name with "<SNR>". */
874 if (!file && fname[0] == K_SPECIAL)
875 {
876 name = alloc((unsigned)STRLEN(fname) + 3);
877 if (name == NULL)
878 name = fname;
879 else
880 {
881 STRCPY(name, "<SNR>");
882 STRCPY(name + 5, fname + 3);
883 }
884 }
885
Bram Moolenaar05159a02005-02-26 23:04:13 +0000886 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000888 /* Skip entries that are not useful or are for a line that is beyond
889 * an already found breakpoint. */
890 bp = &DEBUGGY(gap, i);
891 if (((bp->dbg_type == DBG_FILE) == file && (
892#ifdef FEAT_PROFILE
893 gap == &prof_ga ||
894#endif
895 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000898 * Save the value of got_int and reset it. We don't want a
899 * previous interruption cancel matching, only hitting CTRL-C
900 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000901 */
902 prev_got_int = got_int;
903 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100904 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000905 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000906 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000907 if (fp != NULL)
908 *fp = bp->dbg_forceit;
909 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000910 got_int |= prev_got_int;
911 }
912 }
913 if (name != fname)
914 vim_free(name);
915
916 return lnum;
917}
918
919/*
920 * Called when a breakpoint was encountered.
921 */
922 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100923dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000924{
925 /* We need to check if this line is actually executed in do_one_cmd() */
926 debug_breakpoint_name = name;
927 debug_breakpoint_lnum = lnum;
928}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000929
930
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000931# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000932/*
933 * Store the current time in "tm".
934 */
935 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100936profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000937{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000938# ifdef WIN3264
939 QueryPerformanceCounter(tm);
940# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000941 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000942# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000943}
944
945/*
946 * Compute the elapsed time from "tm" till now and store in "tm".
947 */
948 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100949profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000950{
951 proftime_T now;
952
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000953# ifdef WIN3264
954 QueryPerformanceCounter(&now);
955 tm->QuadPart = now.QuadPart - tm->QuadPart;
956# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000957 gettimeofday(&now, NULL);
958 tm->tv_usec = now.tv_usec - tm->tv_usec;
959 tm->tv_sec = now.tv_sec - tm->tv_sec;
960 if (tm->tv_usec < 0)
961 {
962 tm->tv_usec += 1000000;
963 --tm->tv_sec;
964 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000965# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000966}
967
968/*
969 * Subtract the time "tm2" from "tm".
970 */
971 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100972profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000973{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000974# ifdef WIN3264
975 tm->QuadPart -= tm2->QuadPart;
976# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000977 tm->tv_usec -= tm2->tv_usec;
978 tm->tv_sec -= tm2->tv_sec;
979 if (tm->tv_usec < 0)
980 {
981 tm->tv_usec += 1000000;
982 --tm->tv_sec;
983 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000984# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000985}
986
987/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000988 * Return a string that represents the time in "tm".
989 * Uses a static buffer!
990 */
991 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100992profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000993{
994 static char buf[50];
995
996# ifdef WIN3264
997 LARGE_INTEGER fr;
998
999 QueryPerformanceFrequency(&fr);
1000 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1001# else
1002 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001003# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001004 return buf;
1005}
1006
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001007# if defined(FEAT_FLOAT) || defined(PROTO)
1008/*
1009 * Return a float that represents the time in "tm".
1010 */
1011 float_T
1012profile_float(proftime_T *tm)
1013{
1014# ifdef WIN3264
1015 LARGE_INTEGER fr;
1016
1017 QueryPerformanceFrequency(&fr);
1018 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
1019# else
1020 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
1021# endif
1022}
1023# endif
1024
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001025/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001026 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001027 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001028 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001029profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001030{
1031 if (msec <= 0) /* no limit */
1032 profile_zero(tm);
1033 else
1034 {
1035# ifdef WIN3264
1036 LARGE_INTEGER fr;
1037
1038 QueryPerformanceCounter(tm);
1039 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001040 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001041# else
1042 long usec;
1043
1044 gettimeofday(tm, NULL);
1045 usec = (long)tm->tv_usec + (long)msec * 1000;
1046 tm->tv_usec = usec % 1000000L;
1047 tm->tv_sec += usec / 1000000L;
1048# endif
1049 }
1050}
1051
1052/*
1053 * Return TRUE if the current time is past "tm".
1054 */
1055 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001056profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001057{
1058 proftime_T now;
1059
1060# ifdef WIN3264
1061 if (tm->QuadPart == 0) /* timer was not set */
1062 return FALSE;
1063 QueryPerformanceCounter(&now);
1064 return (now.QuadPart > tm->QuadPart);
1065# else
1066 if (tm->tv_sec == 0) /* timer was not set */
1067 return FALSE;
1068 gettimeofday(&now, NULL);
1069 return (now.tv_sec > tm->tv_sec
1070 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1071# endif
1072}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001073
1074/*
1075 * Set the time in "tm" to zero.
1076 */
1077 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001078profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001079{
1080# ifdef WIN3264
1081 tm->QuadPart = 0;
1082# else
1083 tm->tv_usec = 0;
1084 tm->tv_sec = 0;
1085# endif
1086}
1087
Bram Moolenaar76929292008-01-06 19:07:36 +00001088# endif /* FEAT_PROFILE || FEAT_RELTIME */
1089
Bram Moolenaar975b5272016-03-15 23:10:59 +01001090# if defined(FEAT_TIMERS) || defined(PROTO)
1091static timer_T *first_timer = NULL;
1092static int last_timer_id = 0;
1093
1094/*
1095 * Insert a timer in the list of timers.
1096 */
1097 static void
1098insert_timer(timer_T *timer)
1099{
1100 timer->tr_next = first_timer;
1101 timer->tr_prev = NULL;
1102 if (first_timer != NULL)
1103 first_timer->tr_prev = timer;
1104 first_timer = timer;
1105}
1106
1107/*
1108 * Take a timer out of the list of timers.
1109 */
1110 static void
1111remove_timer(timer_T *timer)
1112{
1113 if (timer->tr_prev == NULL)
1114 first_timer = timer->tr_next;
1115 else
1116 timer->tr_prev->tr_next = timer->tr_next;
1117 if (timer->tr_next != NULL)
1118 timer->tr_next->tr_prev = timer->tr_prev;
1119}
1120
1121 static void
1122free_timer(timer_T *timer)
1123{
1124 vim_free(timer->tr_callback);
1125 partial_unref(timer->tr_partial);
1126 vim_free(timer);
1127}
1128
1129/*
1130 * Create a timer and return it. NULL if out of memory.
1131 * Caller should set the callback.
1132 */
1133 timer_T *
1134create_timer(long msec, int repeat)
1135{
1136 timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
1137
1138 if (timer == NULL)
1139 return NULL;
1140 timer->tr_id = ++last_timer_id;
1141 insert_timer(timer);
1142 if (repeat != 0)
1143 {
1144 timer->tr_repeat = repeat - 1;
1145 timer->tr_interval = msec;
1146 }
1147
1148 profile_setlimit(msec, &timer->tr_due);
1149 return timer;
1150}
1151
1152/*
1153 * Invoke the callback of "timer".
1154 */
1155 static void
1156timer_callback(timer_T *timer)
1157{
1158 typval_T rettv;
1159 int dummy;
1160 typval_T argv[2];
1161
1162 argv[0].v_type = VAR_NUMBER;
1163 argv[0].vval.v_number = timer->tr_id;
1164 argv[1].v_type = VAR_UNKNOWN;
1165
1166 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
1167 &rettv, 1, argv, 0L, 0L, &dummy, TRUE,
1168 timer->tr_partial, NULL);
1169 clear_tv(&rettv);
1170}
1171
1172/*
1173 * Call timers that are due.
1174 * Return the time in msec until the next timer is due.
1175 */
1176 long
1177check_due_timer()
1178{
1179 timer_T *timer;
1180 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001181 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001182 proftime_T now;
1183 int did_one = FALSE;
1184# ifdef WIN3264
1185 LARGE_INTEGER fr;
1186
1187 QueryPerformanceFrequency(&fr);
1188# endif
1189 while (!got_int)
1190 {
1191 profile_start(&now);
1192 next_due = -1;
1193 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1194 {
1195# ifdef WIN3264
1196 this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
1197 / (double)fr.QuadPart) * 1000);
1198# else
1199 this_due = (timer->tr_due.tv_sec - now.tv_sec) * 1000
1200 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1201# endif
1202 if (this_due <= 1)
1203 {
1204 remove_timer(timer);
1205 timer_callback(timer);
1206 did_one = TRUE;
1207 if (timer->tr_repeat != 0)
1208 {
1209 profile_setlimit(timer->tr_interval, &timer->tr_due);
1210 if (timer->tr_repeat > 0)
1211 --timer->tr_repeat;
1212 insert_timer(timer);
1213 }
1214 else
1215 free_timer(timer);
1216 /* the callback may do anything, start all over */
1217 break;
1218 }
1219 if (next_due == -1 || next_due > this_due)
1220 next_due = this_due;
1221 }
1222 if (timer == NULL)
1223 break;
1224 }
1225
1226 if (did_one)
1227 redraw_after_callback();
1228
1229 return next_due;
1230}
1231
1232/*
1233 * Find a timer by ID. Returns NULL if not found;
1234 */
1235 timer_T *
1236find_timer(int id)
1237{
1238 timer_T *timer;
1239
1240 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1241 if (timer->tr_id == id)
1242 break;
1243 return timer;
1244}
1245
1246
1247/*
1248 * Stop a timer and delete it.
1249 */
1250 void
1251stop_timer(timer_T *timer)
1252{
1253 remove_timer(timer);
1254 free_timer(timer);
1255}
1256# endif
1257
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001258#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1259# if defined(HAVE_MATH_H)
1260# include <math.h>
1261# endif
1262
1263/*
1264 * Divide the time "tm" by "count" and store in "tm2".
1265 */
1266 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001267profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001268{
1269 if (count == 0)
1270 profile_zero(tm2);
1271 else
1272 {
1273# ifdef WIN3264
1274 tm2->QuadPart = tm->QuadPart / count;
1275# else
1276 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1277
1278 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001279 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001280# endif
1281 }
1282}
1283#endif
1284
Bram Moolenaar76929292008-01-06 19:07:36 +00001285# if defined(FEAT_PROFILE) || defined(PROTO)
1286/*
1287 * Functions for profiling.
1288 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001289static void script_do_profile(scriptitem_T *si);
1290static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001291static proftime_T prof_wait_time;
1292
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001293/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001294 * Add the time "tm2" to "tm".
1295 */
1296 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001297profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001298{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001299# ifdef WIN3264
1300 tm->QuadPart += tm2->QuadPart;
1301# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001302 tm->tv_usec += tm2->tv_usec;
1303 tm->tv_sec += tm2->tv_sec;
1304 if (tm->tv_usec >= 1000000)
1305 {
1306 tm->tv_usec -= 1000000;
1307 ++tm->tv_sec;
1308 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001309# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001310}
1311
1312/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001313 * Add the "self" time from the total time and the children's time.
1314 */
1315 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001316profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001317{
1318 /* Check that the result won't be negative. Can happen with recursive
1319 * calls. */
1320#ifdef WIN3264
1321 if (total->QuadPart <= children->QuadPart)
1322 return;
1323#else
1324 if (total->tv_sec < children->tv_sec
1325 || (total->tv_sec == children->tv_sec
1326 && total->tv_usec <= children->tv_usec))
1327 return;
1328#endif
1329 profile_add(self, total);
1330 profile_sub(self, children);
1331}
1332
1333/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001334 * Get the current waittime.
1335 */
1336 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001337profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001338{
1339 *tm = prof_wait_time;
1340}
1341
1342/*
1343 * Subtract the passed waittime since "tm" from "tma".
1344 */
1345 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001346profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001347{
1348 proftime_T tm3 = prof_wait_time;
1349
1350 profile_sub(&tm3, tm);
1351 profile_sub(tma, &tm3);
1352}
1353
1354/*
1355 * Return TRUE if "tm1" and "tm2" are equal.
1356 */
1357 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001358profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001359{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001360# ifdef WIN3264
1361 return (tm1->QuadPart == tm2->QuadPart);
1362# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001363 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001364# endif
1365}
1366
1367/*
1368 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1369 */
1370 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001371profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001372{
1373# ifdef WIN3264
1374 return (int)(tm2->QuadPart - tm1->QuadPart);
1375# else
1376 if (tm1->tv_sec == tm2->tv_sec)
1377 return tm2->tv_usec - tm1->tv_usec;
1378 return tm2->tv_sec - tm1->tv_sec;
1379# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001380}
1381
Bram Moolenaar05159a02005-02-26 23:04:13 +00001382static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001383static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001384
1385/*
1386 * ":profile cmd args"
1387 */
1388 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001389ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001390{
1391 char_u *e;
1392 int len;
1393
1394 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001395 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001396 e = skipwhite(e);
1397
1398 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1399 {
1400 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001401 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001402 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001403 profile_zero(&prof_wait_time);
1404 set_vim_var_nr(VV_PROFILING, 1L);
1405 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001406 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001407 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001408 else if (STRCMP(eap->arg, "pause") == 0)
1409 {
1410 if (do_profiling == PROF_YES)
1411 profile_start(&pause_time);
1412 do_profiling = PROF_PAUSED;
1413 }
1414 else if (STRCMP(eap->arg, "continue") == 0)
1415 {
1416 if (do_profiling == PROF_PAUSED)
1417 {
1418 profile_end(&pause_time);
1419 profile_add(&prof_wait_time, &pause_time);
1420 }
1421 do_profiling = PROF_YES;
1422 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001423 else
1424 {
1425 /* The rest is similar to ":breakadd". */
1426 ex_breakadd(eap);
1427 }
1428}
1429
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001430/* Command line expansion for :profile. */
1431static enum
1432{
1433 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001434 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001435} pexpand_what;
1436
1437static char *pexpand_cmds[] = {
1438 "start",
1439#define PROFCMD_START 0
1440 "pause",
1441#define PROFCMD_PAUSE 1
1442 "continue",
1443#define PROFCMD_CONTINUE 2
1444 "func",
1445#define PROFCMD_FUNC 3
1446 "file",
1447#define PROFCMD_FILE 4
1448 NULL
1449#define PROFCMD_LAST 5
1450};
1451
1452/*
1453 * Function given to ExpandGeneric() to obtain the profile command
1454 * specific expansion.
1455 */
1456 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001457get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001458{
1459 switch (pexpand_what)
1460 {
1461 case PEXP_SUBCMD:
1462 return (char_u *)pexpand_cmds[idx];
1463 /* case PEXP_FUNC: TODO */
1464 default:
1465 return NULL;
1466 }
1467}
1468
1469/*
1470 * Handle command line completion for :profile command.
1471 */
1472 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001473set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001474{
1475 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001476
1477 /* Default: expand subcommands. */
1478 xp->xp_context = EXPAND_PROFILE;
1479 pexpand_what = PEXP_SUBCMD;
1480 xp->xp_pattern = arg;
1481
1482 end_subcmd = skiptowhite(arg);
1483 if (*end_subcmd == NUL)
1484 return;
1485
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001486 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001487 {
1488 xp->xp_context = EXPAND_FILES;
1489 xp->xp_pattern = skipwhite(end_subcmd);
1490 return;
1491 }
1492
1493 /* TODO: expand function names after "func" */
1494 xp->xp_context = EXPAND_NOTHING;
1495}
1496
Bram Moolenaar05159a02005-02-26 23:04:13 +00001497/*
1498 * Dump the profiling info.
1499 */
1500 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001501profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001502{
1503 FILE *fd;
1504
1505 if (profile_fname != NULL)
1506 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001507 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001508 if (fd == NULL)
1509 EMSG2(_(e_notopen), profile_fname);
1510 else
1511 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001512 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001513 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001514 fclose(fd);
1515 }
1516 }
1517}
1518
1519/*
1520 * Start profiling script "fp".
1521 */
1522 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001523script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001524{
1525 si->sn_pr_count = 0;
1526 profile_zero(&si->sn_pr_total);
1527 profile_zero(&si->sn_pr_self);
1528
1529 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1530 si->sn_prl_idx = -1;
1531 si->sn_prof_on = TRUE;
1532 si->sn_pr_nest = 0;
1533}
1534
1535/*
1536 * save time when starting to invoke another script or function.
1537 */
1538 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001539script_prof_save(
1540 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001541{
1542 scriptitem_T *si;
1543
1544 if (current_SID > 0 && current_SID <= script_items.ga_len)
1545 {
1546 si = &SCRIPT_ITEM(current_SID);
1547 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1548 profile_start(&si->sn_pr_child);
1549 }
1550 profile_get_wait(tm);
1551}
1552
1553/*
1554 * Count time spent in children after invoking another script or function.
1555 */
1556 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001557script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001558{
1559 scriptitem_T *si;
1560
1561 if (current_SID > 0 && current_SID <= script_items.ga_len)
1562 {
1563 si = &SCRIPT_ITEM(current_SID);
1564 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1565 {
1566 profile_end(&si->sn_pr_child);
1567 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1568 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1569 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1570 }
1571 }
1572}
1573
1574static proftime_T inchar_time;
1575
1576/*
1577 * Called when starting to wait for the user to type a character.
1578 */
1579 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001580prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001581{
1582 profile_start(&inchar_time);
1583}
1584
1585/*
1586 * Called when finished waiting for the user to type a character.
1587 */
1588 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001589prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001590{
1591 profile_end(&inchar_time);
1592 profile_add(&prof_wait_time, &inchar_time);
1593}
1594
1595/*
1596 * Dump the profiling results for all scripts in file "fd".
1597 */
1598 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001599script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001600{
1601 int id;
1602 scriptitem_T *si;
1603 int i;
1604 FILE *sfd;
1605 sn_prl_T *pp;
1606
1607 for (id = 1; id <= script_items.ga_len; ++id)
1608 {
1609 si = &SCRIPT_ITEM(id);
1610 if (si->sn_prof_on)
1611 {
1612 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1613 if (si->sn_pr_count == 1)
1614 fprintf(fd, "Sourced 1 time\n");
1615 else
1616 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1617 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1618 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1619 fprintf(fd, "\n");
1620 fprintf(fd, "count total (s) self (s)\n");
1621
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001622 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001623 if (sfd == NULL)
1624 fprintf(fd, "Cannot open file!\n");
1625 else
1626 {
1627 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1628 {
1629 if (vim_fgets(IObuff, IOSIZE, sfd))
1630 break;
1631 pp = &PRL_ITEM(si, i);
1632 if (pp->snp_count > 0)
1633 {
1634 fprintf(fd, "%5d ", pp->snp_count);
1635 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1636 fprintf(fd, " ");
1637 else
1638 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1639 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1640 }
1641 else
1642 fprintf(fd, " ");
1643 fprintf(fd, "%s", IObuff);
1644 }
1645 fclose(sfd);
1646 }
1647 fprintf(fd, "\n");
1648 }
1649 }
1650}
1651
1652/*
1653 * Return TRUE when a function defined in the current script should be
1654 * profiled.
1655 */
1656 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001657prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001658{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001659 if (current_SID > 0)
1660 return SCRIPT_ITEM(current_SID).sn_pr_force;
1661 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001662}
1663
1664# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001665#endif
1666
1667/*
1668 * If 'autowrite' option set, try to write the file.
1669 * Careful: autocommands may make "buf" invalid!
1670 *
1671 * return FAIL for failure, OK otherwise
1672 */
1673 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001674autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001676 int r;
1677
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678 if (!(p_aw || p_awa) || !p_write
1679#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001680 /* never autowrite a "nofile" or "nowrite" buffer */
1681 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001682#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001683 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001685 r = buf_write_all(buf, forceit);
1686
1687 /* Writing may succeed but the buffer still changed, e.g., when there is a
1688 * conversion error. We do want to return FAIL then. */
1689 if (buf_valid(buf) && bufIsChanged(buf))
1690 r = FAIL;
1691 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692}
1693
1694/*
1695 * flush all buffers, except the ones that are readonly
1696 */
1697 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001698autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001699{
1700 buf_T *buf;
1701
1702 if (!(p_aw || p_awa) || !p_write)
1703 return;
1704 for (buf = firstbuf; buf; buf = buf->b_next)
1705 if (bufIsChanged(buf) && !buf->b_p_ro)
1706 {
1707 (void)buf_write_all(buf, FALSE);
1708#ifdef FEAT_AUTOCMD
1709 /* an autocommand may have deleted the buffer */
1710 if (!buf_valid(buf))
1711 buf = firstbuf;
1712#endif
1713 }
1714}
1715
1716/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001717 * Return TRUE if buffer was changed and cannot be abandoned.
1718 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001721check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001723 int forceit = (flags & CCGD_FORCEIT);
1724
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 if ( !forceit
1726 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001727 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1728 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729 {
1730#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1731 if ((p_confirm || cmdmod.confirm) && p_write)
1732 {
1733 buf_T *buf2;
1734 int count = 0;
1735
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001736 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1738 if (bufIsChanged(buf2)
1739 && (buf2->b_ffname != NULL
1740# ifdef FEAT_BROWSE
1741 || cmdmod.browse
1742# endif
1743 ))
1744 ++count;
1745# ifdef FEAT_AUTOCMD
1746 if (!buf_valid(buf))
1747 /* Autocommand deleted buffer, oops! It's not changed now. */
1748 return FALSE;
1749# endif
1750 dialog_changed(buf, count > 1);
1751# ifdef FEAT_AUTOCMD
1752 if (!buf_valid(buf))
1753 /* Autocommand deleted buffer, oops! It's not changed now. */
1754 return FALSE;
1755# endif
1756 return bufIsChanged(buf);
1757 }
1758#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001759 if (flags & CCGD_EXCMD)
1760 EMSG(_(e_nowrtmsg));
1761 else
1762 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763 return TRUE;
1764 }
1765 return FALSE;
1766}
1767
1768#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1769
1770#if defined(FEAT_BROWSE) || defined(PROTO)
1771/*
1772 * When wanting to write a file without a file name, ask the user for a name.
1773 */
1774 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001775browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001776{
1777 if (buf->b_fname == NULL)
1778 {
1779 char_u *fname;
1780
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001781 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1782 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783 if (fname != NULL)
1784 {
1785 if (setfname(buf, fname, NULL, TRUE) == OK)
1786 buf->b_flags |= BF_NOTEDITED;
1787 vim_free(fname);
1788 }
1789 }
1790}
1791#endif
1792
1793/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001794 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795 * Must check 'write' option first!
1796 */
1797 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001798dialog_changed(
1799 buf_T *buf,
1800 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001802 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803 int ret;
1804 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001805 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001807 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808 (buf->b_fname != NULL) ?
1809 buf->b_fname : (char_u *)_("Untitled"));
1810 if (checkall)
1811 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1812 else
1813 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1814
Bram Moolenaar8218f602012-04-25 17:32:18 +02001815 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1816 * function. */
1817 ea.append = ea.forceit = FALSE;
1818
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819 if (ret == VIM_YES)
1820 {
1821#ifdef FEAT_BROWSE
1822 /* May get file name, when there is none */
1823 browse_save_fname(buf);
1824#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001825 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1826 buf->b_fname, buf->b_ffname, FALSE) == OK)
1827 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828 (void)buf_write_all(buf, FALSE);
1829 }
1830 else if (ret == VIM_NO)
1831 {
1832 unchanged(buf, TRUE);
1833 }
1834 else if (ret == VIM_ALL)
1835 {
1836 /*
1837 * Write all modified files that can be written.
1838 * Skip readonly buffers, these need to be confirmed
1839 * individually.
1840 */
1841 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1842 {
1843 if (bufIsChanged(buf2)
1844 && (buf2->b_ffname != NULL
1845#ifdef FEAT_BROWSE
1846 || cmdmod.browse
1847#endif
1848 )
1849 && !buf2->b_p_ro)
1850 {
1851#ifdef FEAT_BROWSE
1852 /* May get file name, when there is none */
1853 browse_save_fname(buf2);
1854#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001855 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1856 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1857 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001858 (void)buf_write_all(buf2, FALSE);
1859#ifdef FEAT_AUTOCMD
1860 /* an autocommand may have deleted the buffer */
1861 if (!buf_valid(buf2))
1862 buf2 = firstbuf;
1863#endif
1864 }
1865 }
1866 }
1867 else if (ret == VIM_DISCARDALL)
1868 {
1869 /*
1870 * mark all buffers as unchanged
1871 */
1872 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1873 unchanged(buf2, TRUE);
1874 }
1875}
1876#endif
1877
1878/*
1879 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1880 * hidden, autowriting it or unloading it.
1881 */
1882 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001883can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001884{
1885 return ( P_HID(buf)
1886 || !bufIsChanged(buf)
1887 || buf->b_nwindows > 1
1888 || autowrite(buf, forceit) == OK
1889 || forceit);
1890}
1891
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001892static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001893
1894/*
1895 * Add a buffer number to "bufnrs", unless it's already there.
1896 */
1897 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001898add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001899{
1900 int i;
1901
1902 for (i = 0; i < *bufnump; ++i)
1903 if (bufnrs[i] == nr)
1904 return;
1905 bufnrs[*bufnump] = nr;
1906 *bufnump = *bufnump + 1;
1907}
1908
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909/*
1910 * Return TRUE if any buffer was changed and cannot be abandoned.
1911 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001912 * When "unload" is true the current buffer is unloaded instead of making it
1913 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914 */
1915 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001916check_changed_any(
1917 int hidden, /* Only check hidden buffers */
1918 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001920 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 buf_T *buf;
1922 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001923 int i;
1924 int bufnum = 0;
1925 int bufcount = 0;
1926 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001927#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001928 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929 win_T *wp;
1930#endif
1931
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001932 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1933 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001935 if (bufcount == 0)
1936 return FALSE;
1937
1938 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1939 if (bufnrs == NULL)
1940 return FALSE;
1941
1942 /* curbuf */
1943 bufnrs[bufnum++] = curbuf->b_fnum;
1944#ifdef FEAT_WINDOWS
1945 /* buf in curtab */
1946 FOR_ALL_WINDOWS(wp)
1947 if (wp->w_buffer != curbuf)
1948 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1949
1950 /* buf in other tab */
1951 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1952 if (tp != curtab)
1953 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1954 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1955#endif
1956 /* any other buf */
1957 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1958 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1959
1960 for (i = 0; i < bufnum; ++i)
1961 {
1962 buf = buflist_findnr(bufnrs[i]);
1963 if (buf == NULL)
1964 continue;
1965 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1966 {
1967 /* Try auto-writing the buffer. If this fails but the buffer no
1968 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001969 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1970 | CCGD_MULTWIN
1971 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001972 break; /* didn't save - still changes */
1973 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001974 }
1975
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001976 if (i >= bufnum)
1977 goto theend;
1978
1979 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980 exiting = FALSE;
1981#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1982 /*
1983 * When ":confirm" used, don't give an error message.
1984 */
1985 if (!(p_confirm || cmdmod.confirm))
1986#endif
1987 {
1988 /* There must be a wait_return for this message, do_buffer()
1989 * may cause a redraw. But wait_return() is a no-op when vgetc()
1990 * is busy (Quit used from window menu), then make sure we don't
1991 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001992 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001993 {
1994 msg_row = cmdline_row;
1995 msg_col = 0;
1996 msg_didout = FALSE;
1997 }
1998 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001999 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002000 {
2001 save = no_wait_return;
2002 no_wait_return = FALSE;
2003 wait_return(FALSE);
2004 no_wait_return = save;
2005 }
2006 }
2007
2008#ifdef FEAT_WINDOWS
2009 /* Try to find a window that contains the buffer. */
2010 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002011 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002012 if (wp->w_buffer == buf)
2013 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002014 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002015# ifdef FEAT_AUTOCMD
2016 /* Paranoia: did autocms wipe out the buffer with changes? */
2017 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002018 {
2019 goto theend;
2020 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002021# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002022 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002024buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025#endif
2026
2027 /* Open the changed buffer in the current window. */
2028 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002029 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002030
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002031theend:
2032 vim_free(bufnrs);
2033 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002034}
2035
2036/*
2037 * return FAIL if there is no file name, OK if there is one
2038 * give error message for FAIL
2039 */
2040 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002041check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002042{
2043 if (curbuf->b_ffname == NULL)
2044 {
2045 EMSG(_(e_noname));
2046 return FAIL;
2047 }
2048 return OK;
2049}
2050
2051/*
2052 * flush the contents of a buffer, unless it has no file name
2053 *
2054 * return FAIL for failure, OK otherwise
2055 */
2056 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002057buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002058{
2059 int retval;
2060#ifdef FEAT_AUTOCMD
2061 buf_T *old_curbuf = curbuf;
2062#endif
2063
2064 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2065 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2066 FALSE, forceit, TRUE, FALSE));
2067#ifdef FEAT_AUTOCMD
2068 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002069 {
2070 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002072 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073#endif
2074 return retval;
2075}
2076
2077/*
2078 * Code to handle the argument list.
2079 */
2080
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002081static char_u *do_one_arg(char_u *str);
2082static int do_arglist(char_u *str, int what, int after);
2083static void alist_check_arg_idx(void);
2084static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002085#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002086static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002087#endif
2088#define AL_SET 1
2089#define AL_ADD 2
2090#define AL_DEL 3
2091
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002093 * Isolate one argument, taking backticks.
2094 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002095 * Return a pointer to the start of the next argument.
2096 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002097 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002098do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002099{
2100 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002101 int inbacktick;
2102
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 inbacktick = FALSE;
2104 for (p = str; *str; ++str)
2105 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002106 /* When the backslash is used for escaping the special meaning of a
2107 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002108 if (rem_backslash(str))
2109 {
2110 *p++ = *str++;
2111 *p++ = *str;
2112 }
2113 else
2114 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002115 /* An item ends at a space not in backticks */
2116 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002117 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002118 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002119 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002120 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002121 }
2122 }
2123 str = skipwhite(str);
2124 *p = NUL;
2125
2126 return str;
2127}
2128
Bram Moolenaar86b68352004-12-27 21:59:20 +00002129/*
2130 * Separate the arguments in "str" and return a list of pointers in the
2131 * growarray "gap".
2132 */
2133 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002134get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002135{
2136 ga_init2(gap, (int)sizeof(char_u *), 20);
2137 while (*str != NUL)
2138 {
2139 if (ga_grow(gap, 1) == FAIL)
2140 {
2141 ga_clear(gap);
2142 return FAIL;
2143 }
2144 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2145
2146 /* Isolate one argument, change it in-place, put a NUL after it. */
2147 str = do_one_arg(str);
2148 }
2149 return OK;
2150}
2151
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002152#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002153/*
2154 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002155 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002156 * Return FAIL or OK.
2157 */
2158 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002159get_arglist_exp(
2160 char_u *str,
2161 int *fcountp,
2162 char_u ***fnamesp,
2163 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002164{
2165 garray_T ga;
2166 int i;
2167
2168 if (get_arglist(&ga, str) == FAIL)
2169 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002170 if (wig == TRUE)
2171 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2172 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2173 else
2174 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2175 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2176
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002177 ga_clear(&ga);
2178 return i;
2179}
2180#endif
2181
Bram Moolenaar071d4272004-06-13 20:20:40 +00002182#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2183/*
2184 * Redefine the argument list.
2185 */
2186 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002187set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002188{
2189 do_arglist(str, AL_SET, 0);
2190}
2191#endif
2192
2193/*
2194 * "what" == AL_SET: Redefine the argument list to 'str'.
2195 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2196 * "what" == AL_DEL: remove files in 'str' from the argument list.
2197 *
2198 * Return FAIL for failure, OK otherwise.
2199 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002201do_arglist(
2202 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002203 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002204 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002205{
2206 garray_T new_ga;
2207 int exp_count;
2208 char_u **exp_files;
2209 int i;
2210#ifdef FEAT_LISTCMDS
2211 char_u *p;
2212 int match;
2213#endif
2214
2215 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002216 * Set default argument for ":argadd" command.
2217 */
2218 if (what == AL_ADD && *str == NUL)
2219 {
2220 if (curbuf->b_ffname == NULL)
2221 return FAIL;
2222 str = curbuf->b_fname;
2223 }
2224
2225 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226 * Collect all file name arguments in "new_ga".
2227 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002228 if (get_arglist(&new_ga, str) == FAIL)
2229 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002230
2231#ifdef FEAT_LISTCMDS
2232 if (what == AL_DEL)
2233 {
2234 regmatch_T regmatch;
2235 int didone;
2236
2237 /*
2238 * Delete the items: use each item as a regexp and find a match in the
2239 * argument list.
2240 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002241 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002242 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2243 {
2244 p = ((char_u **)new_ga.ga_data)[i];
2245 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2246 if (p == NULL)
2247 break;
2248 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2249 if (regmatch.regprog == NULL)
2250 {
2251 vim_free(p);
2252 break;
2253 }
2254
2255 didone = FALSE;
2256 for (match = 0; match < ARGCOUNT; ++match)
2257 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2258 (colnr_T)0))
2259 {
2260 didone = TRUE;
2261 vim_free(ARGLIST[match].ae_fname);
2262 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2263 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2264 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 if (curwin->w_arg_idx > match)
2266 --curwin->w_arg_idx;
2267 --match;
2268 }
2269
Bram Moolenaar473de612013-06-08 18:19:48 +02002270 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 vim_free(p);
2272 if (!didone)
2273 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2274 }
2275 ga_clear(&new_ga);
2276 }
2277 else
2278#endif
2279 {
2280 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2281 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2282 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002283 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284 {
2285 EMSG(_(e_nomatch));
2286 return FAIL;
2287 }
2288
2289#ifdef FEAT_LISTCMDS
2290 if (what == AL_ADD)
2291 {
2292 (void)alist_add_list(exp_count, exp_files, after);
2293 vim_free(exp_files);
2294 }
2295 else /* what == AL_SET */
2296#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002297 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002298 }
2299
2300 alist_check_arg_idx();
2301
2302 return OK;
2303}
2304
2305/*
2306 * Check the validity of the arg_idx for each other window.
2307 */
2308 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002309alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310{
2311#ifdef FEAT_WINDOWS
2312 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002313 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002314
Bram Moolenaarf740b292006-02-16 22:11:02 +00002315 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002316 if (win->w_alist == curwin->w_alist)
2317 check_arg_idx(win);
2318#else
2319 check_arg_idx(curwin);
2320#endif
2321}
2322
2323/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002324 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002325 * index.
2326 */
2327 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002328editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002329{
2330 return !(win->w_arg_idx >= WARGCOUNT(win)
2331 || (win->w_buffer->b_fnum
2332 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2333 && (win->w_buffer->b_ffname == NULL
2334 || !(fullpathcmp(
2335 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2336 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2337}
2338
2339/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340 * Check if window "win" is editing the w_arg_idx file in its argument list.
2341 */
2342 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002343check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002345 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346 {
2347 /* We are not editing the current entry in the argument list.
2348 * Set "arg_had_last" if we are editing the last one. */
2349 win->w_arg_idx_invalid = TRUE;
2350 if (win->w_arg_idx != WARGCOUNT(win) - 1
2351 && arg_had_last == FALSE
2352#ifdef FEAT_WINDOWS
2353 && ALIST(win) == &global_alist
2354#endif
2355 && GARGCOUNT > 0
2356 && win->w_arg_idx < GARGCOUNT
2357 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2358 || (win->w_buffer->b_ffname != NULL
2359 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2360 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2361 arg_had_last = TRUE;
2362 }
2363 else
2364 {
2365 /* We are editing the current entry in the argument list.
2366 * Set "arg_had_last" if it's also the last one */
2367 win->w_arg_idx_invalid = FALSE;
2368 if (win->w_arg_idx == WARGCOUNT(win) - 1
2369#ifdef FEAT_WINDOWS
2370 && win->w_alist == &global_alist
2371#endif
2372 )
2373 arg_had_last = TRUE;
2374 }
2375}
2376
2377/*
2378 * ":args", ":argslocal" and ":argsglobal".
2379 */
2380 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002381ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002382{
2383 int i;
2384
2385 if (eap->cmdidx != CMD_args)
2386 {
2387#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2388 alist_unlink(ALIST(curwin));
2389 if (eap->cmdidx == CMD_argglobal)
2390 ALIST(curwin) = &global_alist;
2391 else /* eap->cmdidx == CMD_arglocal */
2392 alist_new();
2393#else
2394 ex_ni(eap);
2395 return;
2396#endif
2397 }
2398
2399 if (!ends_excmd(*eap->arg))
2400 {
2401 /*
2402 * ":args file ..": define new argument list, handle like ":next"
2403 * Also for ":argslocal file .." and ":argsglobal file ..".
2404 */
2405 ex_next(eap);
2406 }
2407 else
2408#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2409 if (eap->cmdidx == CMD_args)
2410#endif
2411 {
2412 /*
2413 * ":args": list arguments.
2414 */
2415 if (ARGCOUNT > 0)
2416 {
2417 /* Overwrite the command, for a short list there is no scrolling
2418 * required and no wait_return(). */
2419 gotocmdline(TRUE);
2420 for (i = 0; i < ARGCOUNT; ++i)
2421 {
2422 if (i == curwin->w_arg_idx)
2423 msg_putchar('[');
2424 msg_outtrans(alist_name(&ARGLIST[i]));
2425 if (i == curwin->w_arg_idx)
2426 msg_putchar(']');
2427 msg_putchar(' ');
2428 }
2429 }
2430 }
2431#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2432 else if (eap->cmdidx == CMD_arglocal)
2433 {
2434 garray_T *gap = &curwin->w_alist->al_ga;
2435
2436 /*
2437 * ":argslocal": make a local copy of the global argument list.
2438 */
2439 if (ga_grow(gap, GARGCOUNT) == OK)
2440 for (i = 0; i < GARGCOUNT; ++i)
2441 if (GARGLIST[i].ae_fname != NULL)
2442 {
2443 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2444 vim_strsave(GARGLIST[i].ae_fname);
2445 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2446 GARGLIST[i].ae_fnum;
2447 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002448 }
2449 }
2450#endif
2451}
2452
2453/*
2454 * ":previous", ":sprevious", ":Next" and ":sNext".
2455 */
2456 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002457ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002458{
2459 /* If past the last one already, go to the last one. */
2460 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2461 do_argfile(eap, ARGCOUNT - 1);
2462 else
2463 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2464}
2465
2466/*
2467 * ":rewind", ":first", ":sfirst" and ":srewind".
2468 */
2469 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002470ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471{
2472 do_argfile(eap, 0);
2473}
2474
2475/*
2476 * ":last" and ":slast".
2477 */
2478 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002479ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480{
2481 do_argfile(eap, ARGCOUNT - 1);
2482}
2483
2484/*
2485 * ":argument" and ":sargument".
2486 */
2487 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002488ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002489{
2490 int i;
2491
2492 if (eap->addr_count > 0)
2493 i = eap->line2 - 1;
2494 else
2495 i = curwin->w_arg_idx;
2496 do_argfile(eap, i);
2497}
2498
2499/*
2500 * Edit file "argn" of the argument lists.
2501 */
2502 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002503do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504{
2505 int other;
2506 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002507 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002508
2509 if (argn < 0 || argn >= ARGCOUNT)
2510 {
2511 if (ARGCOUNT <= 1)
2512 EMSG(_("E163: There is only one file to edit"));
2513 else if (argn < 0)
2514 EMSG(_("E164: Cannot go before first file"));
2515 else
2516 EMSG(_("E165: Cannot go beyond last file"));
2517 }
2518 else
2519 {
2520 setpcmark();
2521#ifdef FEAT_GUI
2522 need_mouse_correct = TRUE;
2523#endif
2524
2525#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002526 /* split window or create new tab page first */
2527 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002528 {
2529 if (win_split(0, 0) == FAIL)
2530 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002531 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 }
2533 else
2534#endif
2535 {
2536 /*
2537 * if 'hidden' set, only check for changed file when re-editing
2538 * the same buffer
2539 */
2540 other = TRUE;
2541 if (P_HID(curbuf))
2542 {
2543 p = fix_fname(alist_name(&ARGLIST[argn]));
2544 other = otherfile(p);
2545 vim_free(p);
2546 }
2547 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002548 && check_changed(curbuf, CCGD_AW
2549 | (other ? 0 : CCGD_MULTWIN)
2550 | (eap->forceit ? CCGD_FORCEIT : 0)
2551 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552 return;
2553 }
2554
2555 curwin->w_arg_idx = argn;
2556 if (argn == ARGCOUNT - 1
2557#ifdef FEAT_WINDOWS
2558 && curwin->w_alist == &global_alist
2559#endif
2560 )
2561 arg_had_last = TRUE;
2562
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002563 /* Edit the file; always use the last known line number.
2564 * When it fails (e.g. Abort for already edited file) restore the
2565 * argument index. */
2566 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002567 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002568 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2569 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002570 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002572 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573 setmark('\'');
2574 }
2575}
2576
2577/*
2578 * ":next", and commands that behave like it.
2579 */
2580 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002581ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582{
2583 int i;
2584
2585 /*
2586 * check for changed buffer now, if this fails the argument list is not
2587 * redefined.
2588 */
2589 if ( P_HID(curbuf)
2590 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002591 || !check_changed(curbuf, CCGD_AW
2592 | (eap->forceit ? CCGD_FORCEIT : 0)
2593 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594 {
2595 if (*eap->arg != NUL) /* redefine file list */
2596 {
2597 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2598 return;
2599 i = 0;
2600 }
2601 else
2602 i = curwin->w_arg_idx + (int)eap->line2;
2603 do_argfile(eap, i);
2604 }
2605}
2606
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002607#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002608/*
2609 * ":argedit"
2610 */
2611 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002612ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002613{
2614 int fnum;
2615 int i;
2616 char_u *s;
2617
2618 /* Add the argument to the buffer list and get the buffer number. */
2619 fnum = buflist_add(eap->arg, BLN_LISTED);
2620
2621 /* Check if this argument is already in the argument list. */
2622 for (i = 0; i < ARGCOUNT; ++i)
2623 if (ARGLIST[i].ae_fnum == fnum)
2624 break;
2625 if (i == ARGCOUNT)
2626 {
2627 /* Can't find it, add it to the argument list. */
2628 s = vim_strsave(eap->arg);
2629 if (s == NULL)
2630 return;
2631 i = alist_add_list(1, &s,
2632 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2633 if (i < 0)
2634 return;
2635 curwin->w_arg_idx = i;
2636 }
2637
2638 alist_check_arg_idx();
2639
2640 /* Edit the argument. */
2641 do_argfile(eap, i);
2642}
2643
2644/*
2645 * ":argadd"
2646 */
2647 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002648ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649{
2650 do_arglist(eap->arg, AL_ADD,
2651 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2652#ifdef FEAT_TITLE
2653 maketitle();
2654#endif
2655}
2656
2657/*
2658 * ":argdelete"
2659 */
2660 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002661ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002662{
2663 int i;
2664 int n;
2665
2666 if (eap->addr_count > 0)
2667 {
2668 /* ":1,4argdel": Delete all arguments in the range. */
2669 if (eap->line2 > ARGCOUNT)
2670 eap->line2 = ARGCOUNT;
2671 n = eap->line2 - eap->line1 + 1;
2672 if (*eap->arg != NUL || n <= 0)
2673 EMSG(_(e_invarg));
2674 else
2675 {
2676 for (i = eap->line1; i <= eap->line2; ++i)
2677 vim_free(ARGLIST[i - 1].ae_fname);
2678 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2679 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2680 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 if (curwin->w_arg_idx >= eap->line2)
2682 curwin->w_arg_idx -= n;
2683 else if (curwin->w_arg_idx > eap->line1)
2684 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002685 if (ARGCOUNT == 0)
2686 curwin->w_arg_idx = 0;
2687 else if (curwin->w_arg_idx >= ARGCOUNT)
2688 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 }
2690 }
2691 else if (*eap->arg == NUL)
2692 EMSG(_(e_argreq));
2693 else
2694 do_arglist(eap->arg, AL_DEL, 0);
2695#ifdef FEAT_TITLE
2696 maketitle();
2697#endif
2698}
2699
2700/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002701 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702 */
2703 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002704ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002705{
2706 int i;
2707#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002708 win_T *wp;
2709 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002711 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 int next_fnum = 0;
2713#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2714 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002716 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002717#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002718 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002719 int qf_idx;
2720#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002721
2722#ifndef FEAT_WINDOWS
2723 if (eap->cmdidx == CMD_windo)
2724 {
2725 ex_ni(eap);
2726 return;
2727 }
2728#endif
2729
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002730#ifndef FEAT_QUICKFIX
2731 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2732 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2733 {
2734 ex_ni(eap);
2735 return;
2736 }
2737#endif
2738
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002740 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002741 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2742 * great speed improvement. */
2743 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002745#ifdef FEAT_CLIPBOARD
2746 start_global_changes();
2747#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748
2749 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002750 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002751 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002752 || !check_changed(curbuf, CCGD_AW
2753 | (eap->forceit ? CCGD_FORCEIT : 0)
2754 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002757 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002758#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002759 wp = firstwin;
2760 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002762 switch (eap->cmdidx)
2763 {
2764#ifdef FEAT_WINDOWS
2765 case CMD_windo:
2766 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2767 i++;
2768 break;
2769 case CMD_tabdo:
2770 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2771 i++;
2772 break;
2773#endif
2774 case CMD_argdo:
2775 i = eap->line1 - 1;
2776 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002777 default:
2778 break;
2779 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002780 /* set pcmark now */
2781 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002782 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002783 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002784 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002785 || !buf->b_p_bl); buf = buf->b_next)
2786 if (buf->b_fnum > eap->line2)
2787 {
2788 buf = NULL;
2789 break;
2790 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002791 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002792 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002793 }
2794#ifdef FEAT_QUICKFIX
2795 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2796 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2797 {
2798 qf_size = qf_get_size(eap);
2799 if (qf_size <= 0 || eap->line1 > qf_size)
2800 buf = NULL;
2801 else
2802 {
2803 ex_cc(eap);
2804
2805 buf = curbuf;
2806 i = eap->line1 - 1;
2807 if (eap->addr_count <= 0)
2808 /* default is all the quickfix/location list entries */
2809 eap->line2 = qf_size;
2810 }
2811 }
2812#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813 else
2814 setpcmark();
2815 listcmd_busy = TRUE; /* avoids setting pcmark below */
2816
Bram Moolenaare25bb902015-02-27 20:33:37 +01002817 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002818 {
2819 if (eap->cmdidx == CMD_argdo)
2820 {
2821 /* go to argument "i" */
2822 if (i == ARGCOUNT)
2823 break;
2824 /* Don't call do_argfile() when already there, it will try
2825 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002826 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002827 {
2828 /* Clear 'shm' to avoid that the file message overwrites
2829 * any output from the command. */
2830 p_shm_save = vim_strsave(p_shm);
2831 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002833 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2834 vim_free(p_shm_save);
2835 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002836 if (curwin->w_arg_idx != i)
2837 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002838 }
2839#ifdef FEAT_WINDOWS
2840 else if (eap->cmdidx == CMD_windo)
2841 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002842 /* go to window "wp" */
2843 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002845 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002846 if (curwin != wp)
2847 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002848 wp = curwin->w_next;
2849 }
2850 else if (eap->cmdidx == CMD_tabdo)
2851 {
2852 /* go to window "tp" */
2853 if (!valid_tabpage(tp))
2854 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002855 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002856 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857 }
2858#endif
2859 else if (eap->cmdidx == CMD_bufdo)
2860 {
2861 /* Remember the number of the next listed buffer, in case
2862 * ":bwipe" is used or autocommands do something strange. */
2863 next_fnum = -1;
2864 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2865 if (buf->b_p_bl)
2866 {
2867 next_fnum = buf->b_fnum;
2868 break;
2869 }
2870 }
2871
Bram Moolenaara162bc52015-01-07 16:54:21 +01002872 ++i;
2873
Bram Moolenaar071d4272004-06-13 20:20:40 +00002874 /* execute the command */
2875 do_cmdline(eap->arg, eap->getline, eap->cookie,
2876 DOCMD_VERBOSE + DOCMD_NOWAIT);
2877
2878 if (eap->cmdidx == CMD_bufdo)
2879 {
2880 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002881 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002882 break;
2883 /* Check if the buffer still exists. */
2884 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2885 if (buf->b_fnum == next_fnum)
2886 break;
2887 if (buf == NULL)
2888 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002889
2890 /* Go to the next buffer. Clear 'shm' to avoid that the file
2891 * message overwrites any output from the command. */
2892 p_shm_save = vim_strsave(p_shm);
2893 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002895 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2896 vim_free(p_shm_save);
2897
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002898 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002899 if (curbuf->b_fnum != next_fnum)
2900 break;
2901 }
2902
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002903#ifdef FEAT_QUICKFIX
2904 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2905 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2906 {
2907 if (i >= qf_size || i >= eap->line2)
2908 break;
2909
2910 qf_idx = qf_get_cur_idx(eap);
2911
2912 ex_cnext(eap);
2913
2914 /* If jumping to the next quickfix entry fails, quit here */
2915 if (qf_get_cur_idx(eap) == qf_idx)
2916 break;
2917 }
2918#endif
2919
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920 if (eap->cmdidx == CMD_windo)
2921 {
2922 validate_cursor(); /* cursor may have moved */
2923#ifdef FEAT_SCROLLBIND
2924 /* required when 'scrollbind' has been set */
2925 if (curwin->w_p_scb)
2926 do_check_scrollbind(TRUE);
2927#endif
2928 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002929
2930#ifdef FEAT_WINDOWS
2931 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2932 if (i+1 > eap->line2)
2933 break;
2934#endif
2935 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2936 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 }
2938 listcmd_busy = FALSE;
2939 }
2940
2941#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002942 if (save_ei != NULL)
2943 {
2944 au_event_restore(save_ei);
2945 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2946 curbuf->b_fname, TRUE, curbuf);
2947 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002949#ifdef FEAT_CLIPBOARD
2950 end_global_changes();
2951#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952}
2953
2954/*
2955 * Add files[count] to the arglist of the current window after arg "after".
2956 * The file names in files[count] must have been allocated and are taken over.
2957 * Files[] itself is not taken over.
2958 * Returns index of first added argument. Returns -1 when failed (out of mem).
2959 */
2960 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002961alist_add_list(
2962 int count,
2963 char_u **files,
2964 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965{
2966 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002967 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002968
2969 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2970 {
2971 if (after < 0)
2972 after = 0;
2973 if (after > ARGCOUNT)
2974 after = ARGCOUNT;
2975 if (after < ARGCOUNT)
2976 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2977 (ARGCOUNT - after) * sizeof(aentry_T));
2978 for (i = 0; i < count; ++i)
2979 {
2980 ARGLIST[after + i].ae_fname = files[i];
2981 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2982 }
2983 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002984 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2985 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002986 return after;
2987 }
2988
2989 for (i = 0; i < count; ++i)
2990 vim_free(files[i]);
2991 return -1;
2992}
2993
2994#endif /* FEAT_LISTCMDS */
2995
2996#ifdef FEAT_EVAL
2997/*
2998 * ":compiler[!] {name}"
2999 */
3000 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003001ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003002{
3003 char_u *buf;
3004 char_u *old_cur_comp = NULL;
3005 char_u *p;
3006
3007 if (*eap->arg == NUL)
3008 {
3009 /* List all compiler scripts. */
3010 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3011 /* ) keep the indenter happy... */
3012 }
3013 else
3014 {
3015 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3016 if (buf != NULL)
3017 {
3018 if (eap->forceit)
3019 {
3020 /* ":compiler! {name}" sets global options */
3021 do_cmdline_cmd((char_u *)
3022 "command -nargs=* CompilerSet set <args>");
3023 }
3024 else
3025 {
3026 /* ":compiler! {name}" sets local options.
3027 * To remain backwards compatible "current_compiler" is always
3028 * used. A user's compiler plugin may set it, the distributed
3029 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003030 * "b:current_compiler" and restore "current_compiler".
3031 * Explicitly prepend "g:" to make it work in a function. */
3032 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033 if (old_cur_comp != NULL)
3034 old_cur_comp = vim_strsave(old_cur_comp);
3035 do_cmdline_cmd((char_u *)
3036 "command -nargs=* CompilerSet setlocal <args>");
3037 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003038 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003039 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040
3041 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003042 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003043 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3044 vim_free(buf);
3045
3046 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3047
3048 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003049 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003050 if (p != NULL)
3051 set_internal_string_var((char_u *)"b:current_compiler", p);
3052
3053 /* Restore "current_compiler" for ":compiler {name}". */
3054 if (!eap->forceit)
3055 {
3056 if (old_cur_comp != NULL)
3057 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003058 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059 old_cur_comp);
3060 vim_free(old_cur_comp);
3061 }
3062 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003063 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064 }
3065 }
3066 }
3067}
3068#endif
3069
3070/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003071 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 */
3073 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003074ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003076 char_u *arg = eap->arg;
3077 char_u *p = skiptowhite(arg);
3078 int len = (int)(p - arg);
3079 int flags = eap->forceit ? DIP_ALL : 0;
3080
3081 if (STRNCMP(arg, "START", len) == 0)
3082 {
3083 flags += DIP_START + DIP_NORTP;
3084 arg = skipwhite(arg + len);
3085 }
3086 else if (STRNCMP(arg, "OPT", len) == 0)
3087 {
3088 flags += DIP_OPT + DIP_NORTP;
3089 arg = skipwhite(arg + len);
3090 }
3091 else if (STRNCMP(arg, "PACK", len) == 0)
3092 {
3093 flags += DIP_START + DIP_OPT + DIP_NORTP;
3094 arg = skipwhite(arg + len);
3095 }
3096 else if (STRNCMP(arg, "ALL", len) == 0)
3097 {
3098 flags += DIP_START + DIP_OPT;
3099 arg = skipwhite(arg + len);
3100 }
3101
3102 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103}
3104
Bram Moolenaar071d4272004-06-13 20:20:40 +00003105 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003106source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003108 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003109}
3110
3111/*
3112 * Source the file "name" from all directories in 'runtimepath'.
3113 * "name" can contain wildcards.
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003114 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
Bram Moolenaar91715872016-03-03 17:13:03 +01003115 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 * return FAIL when no file could be sourced, OK otherwise.
3117 */
3118 int
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003119source_runtime(char_u *name, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003120{
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003121 return do_in_runtimepath(name, flags, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003122}
3123
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003124/*
3125 * Find the file "name" in all directories in "path" and invoke
3126 * "callback(fname, cookie)".
3127 * "name" can contain wildcards.
3128 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3129 * When "flags" has DIP_DIR: find directories instead of files.
3130 * When "flags" has DIP_ERR: give an error message if there is no match.
3131 *
3132 * return FAIL when no file could be sourced, OK otherwise.
3133 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003134 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003135do_in_path(
3136 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003137 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003138 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003139 void (*callback)(char_u *fname, void *ck),
3140 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141{
3142 char_u *rtp;
3143 char_u *np;
3144 char_u *buf;
3145 char_u *rtp_copy;
3146 char_u *tail;
3147 int num_files;
3148 char_u **files;
3149 int i;
3150 int did_one = FALSE;
3151#ifdef AMIGA
3152 struct Process *proc = (struct Process *)FindTask(0L);
3153 APTR save_winptr = proc->pr_WindowPtr;
3154
3155 /* Avoid a requester here for a volume that doesn't exist. */
3156 proc->pr_WindowPtr = (APTR)-1L;
3157#endif
3158
3159 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3160 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003161 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162 buf = alloc(MAXPATHL);
3163 if (buf != NULL && rtp_copy != NULL)
3164 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003165 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003166 {
3167 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003168 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003169 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003170 verbose_leave();
3171 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003172
Bram Moolenaar071d4272004-06-13 20:20:40 +00003173 /* Loop over all entries in 'runtimepath'. */
3174 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003175 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176 {
3177 /* Copy the path from 'runtimepath' to buf[]. */
3178 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003179 if (name == NULL)
3180 {
3181 (*callback)(buf, (void *) &cookie);
3182 if (!did_one)
3183 did_one = (cookie == NULL);
3184 }
3185 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 {
3187 add_pathsep(buf);
3188 tail = buf + STRLEN(buf);
3189
3190 /* Loop over all patterns in "name" */
3191 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003192 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003193 {
3194 /* Append the pattern from "name" to buf[]. */
3195 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3196 "\t ");
3197
3198 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003199 {
3200 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003201 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003202 verbose_leave();
3203 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204
3205 /* Expand wildcards, invoke the callback for each match. */
3206 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003207 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208 {
3209 for (i = 0; i < num_files; ++i)
3210 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003211 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003213 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214 break;
3215 }
3216 FreeWild(num_files, files);
3217 }
3218 }
3219 }
3220 }
3221 }
3222 vim_free(buf);
3223 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003224 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003225 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003226 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3227
3228 if (flags & DIP_ERR)
3229 EMSG3(_(e_dirnotf), basepath, name);
3230 else if (p_verbose > 0)
3231 {
3232 verbose_enter();
3233 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3234 verbose_leave();
3235 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003236 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237
3238#ifdef AMIGA
3239 proc->pr_WindowPtr = save_winptr;
3240#endif
3241
3242 return did_one ? OK : FAIL;
3243}
3244
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003245/*
3246 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3247 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003248 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3249 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003250 * Returns OK when at least one match found, FAIL otherwise.
3251 *
3252 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3253 * passed by reference in this case, setting it to NULL indicates that callback
3254 * has done its job.
3255 */
3256 int
3257do_in_runtimepath(
3258 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003259 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003260 void (*callback)(char_u *fname, void *ck),
3261 void *cookie)
3262{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003263 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003264 char_u *s;
3265 int len;
3266 char *start_dir = "pack/*/start/*/%s";
3267 char *opt_dir = "pack/*/opt/*/%s";
3268
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003269 if ((flags & DIP_NORTP) == 0)
3270 done = do_in_path(p_rtp, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003271
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003272 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003273 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003274 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003275 s = alloc(len);
3276 if (s == NULL)
3277 return FAIL;
3278 vim_snprintf((char *)s, len, start_dir, name);
3279 done = do_in_path(p_pp, s, flags, callback, cookie);
3280 vim_free(s);
3281 }
3282
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003283 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003284 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003285 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003286 s = alloc(len);
3287 if (s == NULL)
3288 return FAIL;
3289 vim_snprintf((char *)s, len, opt_dir, name);
3290 done = do_in_path(p_pp, s, flags, callback, cookie);
3291 vim_free(s);
3292 }
3293
3294 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003295}
3296
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003297/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003298 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003299 */
3300 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003301source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003302{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003303 int num_files;
3304 char_u **files;
3305 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003306
Bram Moolenaarf3654822016-03-04 22:12:23 +01003307 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003308 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003309 for (i = 0; i < num_files; ++i)
3310 (void)do_source(files[i], FALSE, DOSO_NONE);
3311 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003312 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003313}
3314
Bram Moolenaar49b27322016-04-05 21:13:00 +02003315/* used for "cookie" of add_pack_plugin() */
3316static int APP_ADD_DIR;
3317static int APP_LOAD;
3318static int APP_BOTH;
3319
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003320 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003321add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003322{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003323 char_u *p4, *p3, *p2, *p1, *p;
3324 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003325 int c;
3326 char_u *new_rtp;
3327 int keep;
3328 int oldlen;
3329 int addlen;
3330 char_u *ffname = fix_fname(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003331
Bram Moolenaar91715872016-03-03 17:13:03 +01003332 if (ffname == NULL)
3333 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003334 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003335 {
3336 /* directory not in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003337 p4 = p3 = p2 = p1 = get_past_head(ffname);
3338 for (p = p1; *p; mb_ptr_adv(p))
3339 if (vim_ispathsep_nocolon(*p))
3340 {
3341 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3342 }
3343
3344 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003345 * rtp/pack/name/start/name
3346 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003347 *
3348 * find the part up to "pack" in 'runtimepath' */
3349 c = *p4;
3350 *p4 = NUL;
3351 insp = (char_u *)strstr((char *)p_rtp, (char *)ffname);
3352 if (insp == NULL)
3353 /* not found, append at the end */
3354 insp = p_rtp + STRLEN(p_rtp);
3355 else
3356 {
3357 /* append after the matching directory. */
3358 insp += STRLEN(ffname);
3359 while (*insp != NUL && *insp != ',')
3360 ++insp;
3361 }
3362 *p4 = c;
3363
Bram Moolenaar1daae442016-02-22 23:25:25 +01003364 oldlen = (int)STRLEN(p_rtp);
Bram Moolenaar91715872016-03-03 17:13:03 +01003365 addlen = (int)STRLEN(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003366 new_rtp = alloc(oldlen + addlen + 2);
3367 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003368 goto theend;
3369 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003370 mch_memmove(new_rtp, p_rtp, keep);
3371 new_rtp[keep] = ',';
Bram Moolenaar91715872016-03-03 17:13:03 +01003372 mch_memmove(new_rtp + keep + 1, ffname, addlen + 1);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003373 if (p_rtp[keep] != NUL)
3374 mch_memmove(new_rtp + keep + 1 + addlen, p_rtp + keep,
3375 oldlen - keep + 1);
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003376 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3377 vim_free(new_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003378 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003379
Bram Moolenaar49b27322016-04-05 21:13:00 +02003380 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003381 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003382 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003383 static char *ftpat = "%s/ftdetect/*.vim";
3384 int len;
3385 char_u *pat;
3386
3387 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3388 pat = alloc(len);
3389 if (pat == NULL)
3390 goto theend;
3391 vim_snprintf((char *)pat, len, plugpat, ffname);
3392 source_all_matches(pat);
3393
3394#ifdef FEAT_AUTOCMD
3395 {
3396 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3397
3398 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3399 * found when it loads. */
3400 if (cmd != NULL && eval_to_number(cmd) > 0)
3401 {
3402 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3403 vim_snprintf((char *)pat, len, ftpat, ffname);
3404 source_all_matches(pat);
3405 do_cmdline_cmd((char_u *)"augroup END");
3406 }
3407 vim_free(cmd);
3408 }
3409#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003410 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003411 }
3412
3413theend:
3414 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003415}
3416
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003417static int did_source_packages = FALSE;
3418
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003419/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003420 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003421 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003422 */
3423 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003424ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003425{
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003426 if (!did_source_packages || (eap != NULL && eap->forceit))
3427 {
3428 did_source_packages = TRUE;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003429
3430 /* First do a round to add all directories to 'runtimepath', then load
3431 * the plugins. This allows for plugins to use an autoload directory
3432 * of another plugin. */
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003433 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003434 add_pack_plugin, &APP_ADD_DIR);
3435 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3436 add_pack_plugin, &APP_LOAD);
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003437 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003438}
3439
3440/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003441 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003442 */
3443 void
3444ex_packadd(exarg_T *eap)
3445{
3446 static char *plugpat = "pack/*/opt/%s";
3447 int len;
3448 char *pat;
3449
3450 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3451 pat = (char *)alloc(len);
3452 if (pat == NULL)
3453 return;
3454 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003455 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003456 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003457 vim_free(pat);
3458}
3459
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3461/*
3462 * ":options"
3463 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003465ex_options(
3466 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003467{
3468 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3469}
3470#endif
3471
3472/*
3473 * ":source {fname}"
3474 */
3475 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003476ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003477{
3478#ifdef FEAT_BROWSE
3479 if (cmdmod.browse)
3480 {
3481 char_u *fname = NULL;
3482
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003483 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3485 if (fname != NULL)
3486 {
3487 cmd_source(fname, eap);
3488 vim_free(fname);
3489 }
3490 }
3491 else
3492#endif
3493 cmd_source(eap->arg, eap);
3494}
3495
3496 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003497cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498{
3499 if (*fname == NUL)
3500 EMSG(_(e_argreq));
3501
Bram Moolenaar071d4272004-06-13 20:20:40 +00003502 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003503 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003504 * Need to execute the commands directly. This is required at least
3505 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003506 * - ":g" command busy
3507 * - after ":argdo", ":windo" or ":bufdo"
3508 * - another command follows
3509 * - inside a loop
3510 */
3511 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3512#ifdef FEAT_EVAL
3513 || eap->cstack->cs_idx >= 0
3514#endif
3515 );
3516
3517 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003518 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 EMSG2(_(e_notopen), fname);
3520}
3521
3522/*
3523 * ":source" and associated commands.
3524 */
3525/*
3526 * Structure used to store info for each sourced file.
3527 * It is shared between do_source() and getsourceline().
3528 * This is required, because it needs to be handed to do_cmdline() and
3529 * sourcing can be done recursively.
3530 */
3531struct source_cookie
3532{
3533 FILE *fp; /* opened file for sourcing */
3534 char_u *nextline; /* if not NULL: line that was read ahead */
3535 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003536#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3538 int error; /* TRUE if LF found after CR-LF */
3539#endif
3540#ifdef FEAT_EVAL
3541 linenr_T breakpoint; /* next line with breakpoint or zero */
3542 char_u *fname; /* name of sourced file */
3543 int dbg_tick; /* debug_tick when breakpoint was set */
3544 int level; /* top nesting level of sourced file */
3545#endif
3546#ifdef FEAT_MBYTE
3547 vimconv_T conv; /* type of conversion */
3548#endif
3549};
3550
3551#ifdef FEAT_EVAL
3552/*
3553 * Return the address holding the next breakpoint line for a source cookie.
3554 */
3555 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003556source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003557{
3558 return &((struct source_cookie *)cookie)->breakpoint;
3559}
3560
3561/*
3562 * Return the address holding the debug tick for a source cookie.
3563 */
3564 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003565source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003566{
3567 return &((struct source_cookie *)cookie)->dbg_tick;
3568}
3569
3570/*
3571 * Return the nesting level for a source cookie.
3572 */
3573 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003574source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575{
3576 return ((struct source_cookie *)cookie)->level;
3577}
3578#endif
3579
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003580static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003581
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003582#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3583# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003584static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003585
3586/*
3587 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003588 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003589 */
3590 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003591fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003593# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003594 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3595# else
3596 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003597# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598
3599 if (fd_tmp == -1)
3600 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003601
3602# ifdef HAVE_FD_CLOEXEC
3603 {
3604 int fdflags = fcntl(fd_tmp, F_GETFD);
3605 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003606 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003607 }
3608# endif
3609
Bram Moolenaar071d4272004-06-13 20:20:40 +00003610 return fdopen(fd_tmp, READBIN);
3611}
3612#endif
3613
3614
3615/*
3616 * do_source: Read the file "fname" and execute its lines as EX commands.
3617 *
3618 * This function may be called recursively!
3619 *
3620 * return FAIL if file could not be opened, OK otherwise
3621 */
3622 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003623do_source(
3624 char_u *fname,
3625 int check_other, /* check for .vimrc and _vimrc */
3626 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627{
3628 struct source_cookie cookie;
3629 char_u *save_sourcing_name;
3630 linenr_T save_sourcing_lnum;
3631 char_u *p;
3632 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003633 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003634 int retval = FAIL;
3635#ifdef FEAT_EVAL
3636 scid_T save_current_SID;
3637 static scid_T last_current_SID = 0;
3638 void *save_funccalp;
3639 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003640 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003641# ifdef UNIX
3642 struct stat st;
3643 int stat_ok;
3644# endif
3645#endif
3646#ifdef STARTUPTIME
3647 struct timeval tv_rel;
3648 struct timeval tv_start;
3649#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003650#ifdef FEAT_PROFILE
3651 proftime_T wait_start;
3652#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003653
Bram Moolenaar071d4272004-06-13 20:20:40 +00003654 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655 if (p == NULL)
3656 return retval;
3657 fname_exp = fix_fname(p);
3658 vim_free(p);
3659 if (fname_exp == NULL)
3660 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 if (mch_isdir(fname_exp))
3662 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003663 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003664 goto theend;
3665 }
3666
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003667#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003668 /* Apply SourceCmd autocommands, they should get the file and source it. */
3669 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3670 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3671 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003672 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003673# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003674 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003675# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003676 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003677# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003678 goto theend;
3679 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003680
3681 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003682 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3683#endif
3684
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003685#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003686 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3687#else
3688 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3689#endif
3690 if (cookie.fp == NULL && check_other)
3691 {
3692 /*
3693 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3694 * and ".exrc" by "_exrc" or vice versa.
3695 */
3696 p = gettail(fname_exp);
3697 if ((*p == '.' || *p == '_')
3698 && (STRICMP(p + 1, "vimrc") == 0
3699 || STRICMP(p + 1, "gvimrc") == 0
3700 || STRICMP(p + 1, "exrc") == 0))
3701 {
3702 if (*p == '_')
3703 *p = '.';
3704 else
3705 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003706#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3708#else
3709 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3710#endif
3711 }
3712 }
3713
3714 if (cookie.fp == NULL)
3715 {
3716 if (p_verbose > 0)
3717 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003718 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003719 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003720 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721 else
3722 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003723 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003724 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725 }
3726 goto theend;
3727 }
3728
3729 /*
3730 * The file exists.
3731 * - In verbose mode, give a message.
3732 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3733 */
3734 if (p_verbose > 1)
3735 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003736 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003738 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739 else
3740 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003741 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003742 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003744 if (is_vimrc == DOSO_VIMRC)
3745 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3746 else if (is_vimrc == DOSO_GVIMRC)
3747 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003748
3749#ifdef USE_CRNL
3750 /* If no automatic file format: Set default to CR-NL. */
3751 if (*p_ffs == NUL)
3752 cookie.fileformat = EOL_DOS;
3753 else
3754 cookie.fileformat = EOL_UNKNOWN;
3755 cookie.error = FALSE;
3756#endif
3757
3758#ifdef USE_CR
3759 /* If no automatic file format: Set default to CR. */
3760 if (*p_ffs == NUL)
3761 cookie.fileformat = EOL_MAC;
3762 else
3763 cookie.fileformat = EOL_UNKNOWN;
3764 cookie.error = FALSE;
3765#endif
3766
3767 cookie.nextline = NULL;
3768 cookie.finished = FALSE;
3769
3770#ifdef FEAT_EVAL
3771 /*
3772 * Check if this script has a breakpoint.
3773 */
3774 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3775 cookie.fname = fname_exp;
3776 cookie.dbg_tick = debug_tick;
3777
3778 cookie.level = ex_nesting_level;
3779#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003780
3781 /*
3782 * Keep the sourcing name/lnum, for recursive calls.
3783 */
3784 save_sourcing_name = sourcing_name;
3785 sourcing_name = fname_exp;
3786 save_sourcing_lnum = sourcing_lnum;
3787 sourcing_lnum = 0;
3788
Bram Moolenaar73881402009-02-04 16:50:47 +00003789#ifdef FEAT_MBYTE
3790 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3791
3792 /* Read the first line so we can check for a UTF-8 BOM. */
3793 firstline = getsourceline(0, (void *)&cookie, 0);
3794 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3795 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3796 {
3797 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3798 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3799 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003800 if (p == NULL)
3801 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003802 if (p != NULL)
3803 {
3804 vim_free(firstline);
3805 firstline = p;
3806 }
3807 }
3808#endif
3809
Bram Moolenaar071d4272004-06-13 20:20:40 +00003810#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003811 if (time_fd != NULL)
3812 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813#endif
3814
3815#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003816# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003817 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003818 prof_child_enter(&wait_start); /* entering a child now */
3819# endif
3820
3821 /* Don't use local function variables, if called from a function.
3822 * Also starts profiling timer for nested script. */
3823 save_funccalp = save_funccal();
3824
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825 /*
3826 * Check if this script was sourced before to finds its SID.
3827 * If it's new, generate a new SID.
3828 */
3829 save_current_SID = current_SID;
3830# ifdef UNIX
3831 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3832# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003833 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3834 {
3835 si = &SCRIPT_ITEM(current_SID);
3836 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 && (
3838# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003839 /* Compare dev/ino when possible, it catches symbolic
3840 * links. Also compare file names, the inode may change
3841 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003842 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003843 && (si->sn_dev == st.st_dev
3844 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003845# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003846 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003847 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003848 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849 if (current_SID == 0)
3850 {
3851 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003852 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3853 == FAIL)
3854 goto almosttheend;
3855 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003857 ++script_items.ga_len;
3858 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3859# ifdef FEAT_PROFILE
3860 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003861# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003862 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003863 si = &SCRIPT_ITEM(current_SID);
3864 si->sn_name = fname_exp;
3865 fname_exp = NULL;
3866# ifdef UNIX
3867 if (stat_ok)
3868 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003869 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003870 si->sn_dev = st.st_dev;
3871 si->sn_ino = st.st_ino;
3872 }
3873 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003874 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003875# endif
3876
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877 /* Allocate the local script variables to use for this script. */
3878 new_script_vars(current_SID);
3879 }
3880
Bram Moolenaar05159a02005-02-26 23:04:13 +00003881# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003882 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003883 {
3884 int forceit;
3885
3886 /* Check if we do profiling for this script. */
3887 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3888 {
3889 script_do_profile(si);
3890 si->sn_pr_force = forceit;
3891 }
3892 if (si->sn_prof_on)
3893 {
3894 ++si->sn_pr_count;
3895 profile_start(&si->sn_pr_start);
3896 profile_zero(&si->sn_pr_children);
3897 }
3898 }
3899# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900#endif
3901
3902 /*
3903 * Call do_cmdline, which will call getsourceline() to get the lines.
3904 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003905 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003907 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003908
3909#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003910 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003911 {
3912 /* Get "si" again, "script_items" may have been reallocated. */
3913 si = &SCRIPT_ITEM(current_SID);
3914 if (si->sn_prof_on)
3915 {
3916 profile_end(&si->sn_pr_start);
3917 profile_sub_wait(&wait_start, &si->sn_pr_start);
3918 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003919 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3920 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003921 }
3922 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003923#endif
3924
3925 if (got_int)
3926 EMSG(_(e_interr));
3927 sourcing_name = save_sourcing_name;
3928 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003929 if (p_verbose > 1)
3930 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003931 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003932 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003934 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003935 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003936 }
3937#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003938 if (time_fd != NULL)
3939 {
3940 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3941 time_msg((char *)IObuff, &tv_start);
3942 time_pop(&tv_rel);
3943 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003944#endif
3945
3946#ifdef FEAT_EVAL
3947 /*
3948 * After a "finish" in debug mode, need to break at first command of next
3949 * sourced file.
3950 */
3951 if (save_debug_break_level > ex_nesting_level
3952 && debug_break_level == ex_nesting_level)
3953 ++debug_break_level;
3954#endif
3955
Bram Moolenaar05159a02005-02-26 23:04:13 +00003956#ifdef FEAT_EVAL
3957almosttheend:
3958 current_SID = save_current_SID;
3959 restore_funccal(save_funccalp);
3960# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003961 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003962 prof_child_exit(&wait_start); /* leaving a child now */
3963# endif
3964#endif
3965 fclose(cookie.fp);
3966 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003967 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003968#ifdef FEAT_MBYTE
3969 convert_setup(&cookie.conv, NULL, NULL);
3970#endif
3971
Bram Moolenaar071d4272004-06-13 20:20:40 +00003972theend:
3973 vim_free(fname_exp);
3974 return retval;
3975}
3976
3977#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003978
Bram Moolenaar071d4272004-06-13 20:20:40 +00003979/*
3980 * ":scriptnames"
3981 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003982 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003983ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003984{
3985 int i;
3986
Bram Moolenaar05159a02005-02-26 23:04:13 +00003987 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3988 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003989 {
3990 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3991 NameBuff, MAXPATHL, TRUE);
3992 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003993 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994}
3995
3996# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3997/*
3998 * Fix slashes in the list of script names for 'shellslash'.
3999 */
4000 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004001scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002{
4003 int i;
4004
Bram Moolenaar05159a02005-02-26 23:04:13 +00004005 for (i = 1; i <= script_items.ga_len; ++i)
4006 if (SCRIPT_ITEM(i).sn_name != NULL)
4007 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004008}
4009# endif
4010
4011/*
4012 * Get a pointer to a script name. Used for ":verbose set".
4013 */
4014 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004015get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016{
4017 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004018 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004019 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004020 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004021 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004022 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004024 return (char_u *)_("environment variable");
4025 if (id == SID_ERROR)
4026 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004027 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004029
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004030# if defined(EXITFREE) || defined(PROTO)
4031 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004032free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004033{
4034 int i;
4035
4036 for (i = script_items.ga_len; i > 0; --i)
4037 vim_free(SCRIPT_ITEM(i).sn_name);
4038 ga_clear(&script_items);
4039}
4040# endif
4041
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042#endif
4043
4044#if defined(USE_CR) || defined(PROTO)
4045
4046# if defined(__MSL__) && (__MSL__ >= 22)
4047/*
4048 * Newer version of the Metrowerks library handle DOS and UNIX files
4049 * without help.
4050 * Test with earlier versions, MSL 2.2 is the library supplied with
4051 * Codewarrior Pro 2.
4052 */
4053 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004054fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004055{
4056 return fgets(s, n, stream);
4057}
4058# else
4059/*
4060 * Version of fgets() which also works for lines ending in a <CR> only
4061 * (Macintosh format).
4062 * For older versions of the Metrowerks library.
4063 * At least CodeWarrior 9 needed this code.
4064 */
4065 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004066fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004067{
4068 int c = 0;
4069 int char_read = 0;
4070
4071 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4072 {
4073 c = fgetc(stream);
4074 s[char_read++] = c;
4075 /* If the file is in DOS format, we need to skip a NL after a CR. I
4076 * thought it was the other way around, but this appears to work... */
4077 if (c == '\n')
4078 {
4079 c = fgetc(stream);
4080 if (c != '\r')
4081 ungetc(c, stream);
4082 }
4083 }
4084
4085 s[char_read] = 0;
4086 if (char_read == 0)
4087 return NULL;
4088
4089 if (feof(stream) && char_read == 1)
4090 return NULL;
4091
4092 return s;
4093}
4094# endif
4095#endif
4096
4097/*
4098 * Get one full line from a sourced file.
4099 * Called by do_cmdline() when it's called from do_source().
4100 *
4101 * Return a pointer to the line in allocated memory.
4102 * Return NULL for end-of-file or some error.
4103 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004105getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106{
4107 struct source_cookie *sp = (struct source_cookie *)cookie;
4108 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004109 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110
4111#ifdef FEAT_EVAL
4112 /* If breakpoints have been added/deleted need to check for it. */
4113 if (sp->dbg_tick < debug_tick)
4114 {
4115 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4116 sp->dbg_tick = debug_tick;
4117 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004118# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004119 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004120 script_line_end();
4121# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122#endif
4123 /*
4124 * Get current line. If there is a read-ahead line, use it, otherwise get
4125 * one now.
4126 */
4127 if (sp->finished)
4128 line = NULL;
4129 else if (sp->nextline == NULL)
4130 line = get_one_sourceline(sp);
4131 else
4132 {
4133 line = sp->nextline;
4134 sp->nextline = NULL;
4135 ++sourcing_lnum;
4136 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004137#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004138 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004139 script_line_start();
4140#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004141
4142 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4143 * contain the 'C' flag. */
4144 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4145 {
4146 /* compensate for the one line read-ahead */
4147 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004148
4149 /* Get the next line and concatenate it when it starts with a
4150 * backslash. We always need to read the next line, keep it in
4151 * sp->nextline. */
4152 sp->nextline = get_one_sourceline(sp);
4153 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004155 garray_T ga;
4156
Bram Moolenaarb549a732012-02-22 18:29:33 +01004157 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004158 ga_concat(&ga, line);
4159 ga_concat(&ga, p + 1);
4160 for (;;)
4161 {
4162 vim_free(sp->nextline);
4163 sp->nextline = get_one_sourceline(sp);
4164 if (sp->nextline == NULL)
4165 break;
4166 p = skipwhite(sp->nextline);
4167 if (*p != '\\')
4168 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004169 /* Adjust the growsize to the current length to speed up
4170 * concatenating many lines. */
4171 if (ga.ga_len > 400)
4172 {
4173 if (ga.ga_len > 8000)
4174 ga.ga_growsize = 8000;
4175 else
4176 ga.ga_growsize = ga.ga_len;
4177 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004178 ga_concat(&ga, p + 1);
4179 }
4180 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004182 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004183 }
4184 }
4185
4186#ifdef FEAT_MBYTE
4187 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4188 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004189 char_u *s;
4190
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191 /* Convert the encoding of the script line. */
4192 s = string_convert(&sp->conv, line, NULL);
4193 if (s != NULL)
4194 {
4195 vim_free(line);
4196 line = s;
4197 }
4198 }
4199#endif
4200
4201#ifdef FEAT_EVAL
4202 /* Did we encounter a breakpoint? */
4203 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4204 {
4205 dbg_breakpoint(sp->fname, sourcing_lnum);
4206 /* Find next breakpoint. */
4207 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4208 sp->dbg_tick = debug_tick;
4209 }
4210#endif
4211
4212 return line;
4213}
4214
4215 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004216get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004217{
4218 garray_T ga;
4219 int len;
4220 int c;
4221 char_u *buf;
4222#ifdef USE_CRNL
4223 int has_cr; /* CR-LF found */
4224#endif
4225#ifdef USE_CR
4226 char_u *scan;
4227#endif
4228 int have_read = FALSE;
4229
4230 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004231 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004232
4233 /*
4234 * Loop until there is a finished line (or end-of-file).
4235 */
4236 sourcing_lnum++;
4237 for (;;)
4238 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004239 /* make room to read at least 120 (more) characters */
4240 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241 break;
4242 buf = (char_u *)ga.ga_data;
4243
4244#ifdef USE_CR
4245 if (sp->fileformat == EOL_MAC)
4246 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004247 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4248 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004249 break;
4250 }
4251 else
4252#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004253 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4254 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004256 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257#ifdef USE_CRNL
4258 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4259 * CTRL-Z by its own, or after a NL. */
4260 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4261 && sp->fileformat == EOL_DOS
4262 && buf[len - 1] == Ctrl_Z)
4263 {
4264 buf[len - 1] = NUL;
4265 break;
4266 }
4267#endif
4268
4269#ifdef USE_CR
4270 /* If the read doesn't stop on a new line, and there's
4271 * some CR then we assume a Mac format */
4272 if (sp->fileformat == EOL_UNKNOWN)
4273 {
4274 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4275 sp->fileformat = EOL_MAC;
4276 else
4277 sp->fileformat = EOL_UNIX;
4278 }
4279
4280 if (sp->fileformat == EOL_MAC)
4281 {
4282 scan = vim_strchr(buf, '\r');
4283
4284 if (scan != NULL)
4285 {
4286 *scan = '\n';
4287 if (*(scan + 1) != 0)
4288 {
4289 *(scan + 1) = 0;
4290 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4291 }
4292 }
4293 len = STRLEN(buf);
4294 }
4295#endif
4296
4297 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298 ga.ga_len = len;
4299
4300 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004301 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004302 continue;
4303
4304 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4305 {
4306#ifdef USE_CRNL
4307 has_cr = (len >= 2 && buf[len - 2] == '\r');
4308 if (sp->fileformat == EOL_UNKNOWN)
4309 {
4310 if (has_cr)
4311 sp->fileformat = EOL_DOS;
4312 else
4313 sp->fileformat = EOL_UNIX;
4314 }
4315
4316 if (sp->fileformat == EOL_DOS)
4317 {
4318 if (has_cr) /* replace trailing CR */
4319 {
4320 buf[len - 2] = '\n';
4321 --len;
4322 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323 }
4324 else /* lines like ":map xx yy^M" will have failed */
4325 {
4326 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004327 {
4328 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004329 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004330 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004331 sp->error = TRUE;
4332 sp->fileformat = EOL_UNIX;
4333 }
4334 }
4335#endif
4336 /* The '\n' is escaped if there is an odd number of ^V's just
4337 * before it, first set "c" just before the 'V's and then check
4338 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4339 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4340 ;
4341 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4342 {
4343 sourcing_lnum++;
4344 continue;
4345 }
4346
4347 buf[len - 1] = NUL; /* remove the NL */
4348 }
4349
4350 /*
4351 * Check for ^C here now and then, so recursive :so can be broken.
4352 */
4353 line_breakcheck();
4354 break;
4355 }
4356
4357 if (have_read)
4358 return (char_u *)ga.ga_data;
4359
4360 vim_free(ga.ga_data);
4361 return NULL;
4362}
4363
Bram Moolenaar05159a02005-02-26 23:04:13 +00004364#if defined(FEAT_PROFILE) || defined(PROTO)
4365/*
4366 * Called when starting to read a script line.
4367 * "sourcing_lnum" must be correct!
4368 * When skipping lines it may not actually be executed, but we won't find out
4369 * until later and we need to store the time now.
4370 */
4371 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004372script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004373{
4374 scriptitem_T *si;
4375 sn_prl_T *pp;
4376
4377 if (current_SID <= 0 || current_SID > script_items.ga_len)
4378 return;
4379 si = &SCRIPT_ITEM(current_SID);
4380 if (si->sn_prof_on && sourcing_lnum >= 1)
4381 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004382 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004383 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004384 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004385 si->sn_prl_idx = sourcing_lnum - 1;
4386 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4387 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4388 {
4389 /* Zero counters for a line that was not used before. */
4390 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4391 pp->snp_count = 0;
4392 profile_zero(&pp->sn_prl_total);
4393 profile_zero(&pp->sn_prl_self);
4394 ++si->sn_prl_ga.ga_len;
4395 }
4396 si->sn_prl_execed = FALSE;
4397 profile_start(&si->sn_prl_start);
4398 profile_zero(&si->sn_prl_children);
4399 profile_get_wait(&si->sn_prl_wait);
4400 }
4401}
4402
4403/*
4404 * Called when actually executing a function line.
4405 */
4406 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004407script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004408{
4409 scriptitem_T *si;
4410
4411 if (current_SID <= 0 || current_SID > script_items.ga_len)
4412 return;
4413 si = &SCRIPT_ITEM(current_SID);
4414 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4415 si->sn_prl_execed = TRUE;
4416}
4417
4418/*
4419 * Called when done with a function line.
4420 */
4421 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004422script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004423{
4424 scriptitem_T *si;
4425 sn_prl_T *pp;
4426
4427 if (current_SID <= 0 || current_SID > script_items.ga_len)
4428 return;
4429 si = &SCRIPT_ITEM(current_SID);
4430 if (si->sn_prof_on && si->sn_prl_idx >= 0
4431 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4432 {
4433 if (si->sn_prl_execed)
4434 {
4435 pp = &PRL_ITEM(si, si->sn_prl_idx);
4436 ++pp->snp_count;
4437 profile_end(&si->sn_prl_start);
4438 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004439 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004440 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4441 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004442 }
4443 si->sn_prl_idx = -1;
4444 }
4445}
4446#endif
4447
Bram Moolenaar071d4272004-06-13 20:20:40 +00004448/*
4449 * ":scriptencoding": Set encoding conversion for a sourced script.
4450 * Without the multi-byte feature it's simply ignored.
4451 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004452 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004453ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004454{
4455#ifdef FEAT_MBYTE
4456 struct source_cookie *sp;
4457 char_u *name;
4458
4459 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4460 {
4461 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4462 return;
4463 }
4464
4465 if (*eap->arg != NUL)
4466 {
4467 name = enc_canonize(eap->arg);
4468 if (name == NULL) /* out of memory */
4469 return;
4470 }
4471 else
4472 name = eap->arg;
4473
4474 /* Setup for conversion from the specified encoding to 'encoding'. */
4475 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4476 convert_setup(&sp->conv, name, p_enc);
4477
4478 if (name != eap->arg)
4479 vim_free(name);
4480#endif
4481}
4482
4483#if defined(FEAT_EVAL) || defined(PROTO)
4484/*
4485 * ":finish": Mark a sourced file as finished.
4486 */
4487 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004488ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004489{
4490 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4491 do_finish(eap, FALSE);
4492 else
4493 EMSG(_("E168: :finish used outside of a sourced file"));
4494}
4495
4496/*
4497 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4498 * Also called for a pending finish at the ":endtry" or after returning from
4499 * an extra do_cmdline(). "reanimate" is used in the latter case.
4500 */
4501 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004502do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503{
4504 int idx;
4505
4506 if (reanimate)
4507 ((struct source_cookie *)getline_cookie(eap->getline,
4508 eap->cookie))->finished = FALSE;
4509
4510 /*
4511 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4512 * not in its finally clause (which then is to be executed next) is found.
4513 * In this case, make the ":finish" pending for execution at the ":endtry".
4514 * Otherwise, finish normally.
4515 */
4516 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4517 if (idx >= 0)
4518 {
4519 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4520 report_make_pending(CSTP_FINISH, NULL);
4521 }
4522 else
4523 ((struct source_cookie *)getline_cookie(eap->getline,
4524 eap->cookie))->finished = TRUE;
4525}
4526
4527
4528/*
4529 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4530 * message for missing ":endif".
4531 * Return FALSE when not sourcing a file.
4532 */
4533 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004534source_finished(
4535 char_u *(*fgetline)(int, void *, int),
4536 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004538 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004540 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004541}
4542#endif
4543
4544#if defined(FEAT_LISTCMDS) || defined(PROTO)
4545/*
4546 * ":checktime [buffer]"
4547 */
4548 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004549ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550{
4551 buf_T *buf;
4552 int save_no_check_timestamps = no_check_timestamps;
4553
4554 no_check_timestamps = 0;
4555 if (eap->addr_count == 0) /* default is all buffers */
4556 check_timestamps(FALSE);
4557 else
4558 {
4559 buf = buflist_findnr((int)eap->line2);
4560 if (buf != NULL) /* cannot happen? */
4561 (void)buf_check_timestamp(buf, FALSE);
4562 }
4563 no_check_timestamps = save_no_check_timestamps;
4564}
4565#endif
4566
Bram Moolenaar071d4272004-06-13 20:20:40 +00004567#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4568 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004569# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004570static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004572 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004573get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004575 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004576
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004577 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004578 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004579
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004580# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004581 if (loc != NULL)
4582 {
4583 char_u *p;
4584
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004585 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4586 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004587 p = vim_strchr(loc, '=');
4588 if (p != NULL)
4589 {
4590 loc = ++p;
4591 while (*p != NUL) /* remove trailing newline */
4592 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004593 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594 {
4595 *p = NUL;
4596 break;
4597 }
4598 ++p;
4599 }
4600 }
4601 }
4602# endif
4603
4604 return loc;
4605}
4606#endif
4607
4608
4609#ifdef WIN32
4610/*
4611 * On MS-Windows locale names are strings like "German_Germany.1252", but
4612 * gettext expects "de". Try to translate one into another here for a few
4613 * supported languages.
4614 */
4615 static char_u *
4616gettext_lang(char_u *name)
4617{
4618 int i;
4619 static char *(mtable[]) = {
4620 "afrikaans", "af",
4621 "czech", "cs",
4622 "dutch", "nl",
4623 "german", "de",
4624 "english_united kingdom", "en_GB",
4625 "spanish", "es",
4626 "french", "fr",
4627 "italian", "it",
4628 "japanese", "ja",
4629 "korean", "ko",
4630 "norwegian", "no",
4631 "polish", "pl",
4632 "russian", "ru",
4633 "slovak", "sk",
4634 "swedish", "sv",
4635 "ukrainian", "uk",
4636 "chinese_china", "zh_CN",
4637 "chinese_taiwan", "zh_TW",
4638 NULL};
4639
4640 for (i = 0; mtable[i] != NULL; i += 2)
4641 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004642 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004643 return name;
4644}
4645#endif
4646
4647#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4648/*
4649 * Obtain the current messages language. Used to set the default for
4650 * 'helplang'. May return NULL or an empty string.
4651 */
4652 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004653get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654{
4655 char_u *p;
4656
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004657# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004658# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004659 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004660# else
4661 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004662 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4663 * and LC_MONETARY may be set differently for a Japanese working in the
4664 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004665 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004666# endif
4667# else
4668 p = mch_getenv((char_u *)"LC_ALL");
4669 if (p == NULL || *p == NUL)
4670 {
4671 p = mch_getenv((char_u *)"LC_MESSAGES");
4672 if (p == NULL || *p == NUL)
4673 p = mch_getenv((char_u *)"LANG");
4674 }
4675# endif
4676# ifdef WIN32
4677 p = gettext_lang(p);
4678# endif
4679 return p;
4680}
4681#endif
4682
Bram Moolenaardef9e822004-12-31 20:58:58 +00004683/* Complicated #if; matches with where get_mess_env() is used below. */
4684#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4685 && defined(LC_MESSAGES))) \
4686 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4687 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4688 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004689static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690
4691/*
4692 * Get the language used for messages from the environment.
4693 */
4694 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004695get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004696{
4697 char_u *p;
4698
4699 p = mch_getenv((char_u *)"LC_ALL");
4700 if (p == NULL || *p == NUL)
4701 {
4702 p = mch_getenv((char_u *)"LC_MESSAGES");
4703 if (p == NULL || *p == NUL)
4704 {
4705 p = mch_getenv((char_u *)"LANG");
4706 if (p != NULL && VIM_ISDIGIT(*p))
4707 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004708# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004709 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004710 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004711# endif
4712 }
4713 }
4714 return p;
4715}
4716#endif
4717
4718#if defined(FEAT_EVAL) || defined(PROTO)
4719
4720/*
4721 * Set the "v:lang" variable according to the current locale setting.
4722 * Also do "v:lc_time"and "v:ctype".
4723 */
4724 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004725set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004726{
4727 char_u *loc;
4728
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004729# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004730 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004731# else
4732 /* setlocale() not supported: use the default value */
4733 loc = (char_u *)"C";
4734# endif
4735 set_vim_var_string(VV_CTYPE, loc, -1);
4736
4737 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4738 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004739# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004740 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004741# else
4742 loc = get_mess_env();
4743# endif
4744 set_vim_var_string(VV_LANG, loc, -1);
4745
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004746# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004747 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748# endif
4749 set_vim_var_string(VV_LC_TIME, loc, -1);
4750}
4751#endif
4752
4753#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4754 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4755/*
4756 * ":language": Set the language (locale).
4757 */
4758 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004759ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760{
4761 char *loc;
4762 char_u *p;
4763 char_u *name;
4764 int what = LC_ALL;
4765 char *whatstr = "";
4766#ifdef LC_MESSAGES
4767# define VIM_LC_MESSAGES LC_MESSAGES
4768#else
4769# define VIM_LC_MESSAGES 6789
4770#endif
4771
4772 name = eap->arg;
4773
4774 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4775 * Allow abbreviation, but require at least 3 characters to avoid
4776 * confusion with a two letter language name "me" or "ct". */
4777 p = skiptowhite(eap->arg);
4778 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4779 {
4780 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4781 {
4782 what = VIM_LC_MESSAGES;
4783 name = skipwhite(p);
4784 whatstr = "messages ";
4785 }
4786 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4787 {
4788 what = LC_CTYPE;
4789 name = skipwhite(p);
4790 whatstr = "ctype ";
4791 }
4792 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4793 {
4794 what = LC_TIME;
4795 name = skipwhite(p);
4796 whatstr = "time ";
4797 }
4798 }
4799
4800 if (*name == NUL)
4801 {
4802#ifndef LC_MESSAGES
4803 if (what == VIM_LC_MESSAGES)
4804 p = get_mess_env();
4805 else
4806#endif
4807 p = (char_u *)setlocale(what, NULL);
4808 if (p == NULL || *p == NUL)
4809 p = (char_u *)"Unknown";
4810 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4811 }
4812 else
4813 {
4814#ifndef LC_MESSAGES
4815 if (what == VIM_LC_MESSAGES)
4816 loc = "";
4817 else
4818#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004819 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004820 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004821#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4822 /* Make sure strtod() uses a decimal point, not a comma. */
4823 setlocale(LC_NUMERIC, "C");
4824#endif
4825 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004826 if (loc == NULL)
4827 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4828 else
4829 {
4830#ifdef HAVE_NL_MSG_CAT_CNTR
4831 /* Need to do this for GNU gettext, otherwise cached translations
4832 * will be used again. */
4833 extern int _nl_msg_cat_cntr;
4834
4835 ++_nl_msg_cat_cntr;
4836#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004837 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004838 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4839
4840 if (what != LC_TIME)
4841 {
4842 /* Tell gettext() what to translate to. It apparently doesn't
4843 * use the currently effective locale. Also do this when
4844 * FEAT_GETTEXT isn't defined, so that shell commands use this
4845 * value. */
4846 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004847 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004848 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004849
4850 /* Clear $LANGUAGE because GNU gettext uses it. */
4851 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004852# ifdef WIN32
4853 /* Apparently MS-Windows printf() may cause a crash when
4854 * we give it 8-bit text while it's expecting text in the
4855 * current locale. This call avoids that. */
4856 setlocale(LC_CTYPE, "C");
4857# endif
4858 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004859 if (what != LC_CTYPE)
4860 {
4861 char_u *mname;
4862#ifdef WIN32
4863 mname = gettext_lang(name);
4864#else
4865 mname = name;
4866#endif
4867 vim_setenv((char_u *)"LC_MESSAGES", mname);
4868#ifdef FEAT_MULTI_LANG
4869 set_helplang_default(mname);
4870#endif
4871 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004872 }
4873
4874# ifdef FEAT_EVAL
4875 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4876 set_lang_var();
4877# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004878# ifdef FEAT_TITLE
4879 maketitle();
4880# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004881 }
4882 }
4883}
4884
4885# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004886
4887static char_u **locales = NULL; /* Array of all available locales */
4888static int did_init_locales = FALSE;
4889
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004890static void init_locales(void);
4891static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004892
4893/*
4894 * Lazy initialization of all available locales.
4895 */
4896 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004897init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004898{
4899 if (!did_init_locales)
4900 {
4901 did_init_locales = TRUE;
4902 locales = find_locales();
4903 }
4904}
4905
4906/* Return an array of strings for all available locales + NULL for the
4907 * last element. Return NULL in case of error. */
4908 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004909find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004910{
4911 garray_T locales_ga;
4912 char_u *loc;
4913
4914 /* Find all available locales by running command "locale -a". If this
4915 * doesn't work we won't have completion. */
4916 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004917 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004918 if (locale_a == NULL)
4919 return NULL;
4920 ga_init2(&locales_ga, sizeof(char_u *), 20);
4921
4922 /* Transform locale_a string where each locale is separated by "\n"
4923 * into an array of locale strings. */
4924 loc = (char_u *)strtok((char *)locale_a, "\n");
4925
4926 while (loc != NULL)
4927 {
4928 if (ga_grow(&locales_ga, 1) == FAIL)
4929 break;
4930 loc = vim_strsave(loc);
4931 if (loc == NULL)
4932 break;
4933
4934 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4935 loc = (char_u *)strtok(NULL, "\n");
4936 }
4937 vim_free(locale_a);
4938 if (ga_grow(&locales_ga, 1) == FAIL)
4939 {
4940 ga_clear(&locales_ga);
4941 return NULL;
4942 }
4943 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4944 return (char_u **)locales_ga.ga_data;
4945}
4946
4947# if defined(EXITFREE) || defined(PROTO)
4948 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004949free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004950{
4951 int i;
4952 if (locales != NULL)
4953 {
4954 for (i = 0; locales[i] != NULL; i++)
4955 vim_free(locales[i]);
4956 vim_free(locales);
4957 locales = NULL;
4958 }
4959}
4960# endif
4961
Bram Moolenaar071d4272004-06-13 20:20:40 +00004962/*
4963 * Function given to ExpandGeneric() to obtain the possible arguments of the
4964 * ":language" command.
4965 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004966 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004967get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004968{
4969 if (idx == 0)
4970 return (char_u *)"messages";
4971 if (idx == 1)
4972 return (char_u *)"ctype";
4973 if (idx == 2)
4974 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004975
4976 init_locales();
4977 if (locales == NULL)
4978 return NULL;
4979 return locales[idx - 3];
4980}
4981
4982/*
4983 * Function given to ExpandGeneric() to obtain the available locales.
4984 */
4985 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004986get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004987{
4988 init_locales();
4989 if (locales == NULL)
4990 return NULL;
4991 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004992}
4993# endif
4994
4995#endif