blob: 07458edc0a2ad7ddb30568d145ea365e3665a5a3 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
Bram Moolenaarf1f60f82016-01-16 15:40:53 +010071static int get_maxbacktrace_level(void);
72static void do_setdebugtracelevel(char_u *arg);
73static void do_checkbacktracelevel(void);
74static void do_showbacktrace(char_u *cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +000075
76/*
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
79 */
80 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010081do_debug(char_u *cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +000082{
83 int save_msg_scroll = msg_scroll;
84 int save_State = State;
85 int save_did_emsg = did_emsg;
86 int save_cmd_silent = cmd_silent;
87 int save_msg_silent = msg_silent;
88 int save_emsg_silent = emsg_silent;
89 int save_redir_off = redir_off;
90 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000091 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000092 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 int save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 int n;
95 char_u *cmdline = NULL;
96 char_u *p;
97 char *tail = NULL;
98 static int last_cmd = 0;
99#define CMD_CONT 1
100#define CMD_NEXT 2
101#define CMD_STEP 3
102#define CMD_FINISH 4
103#define CMD_QUIT 5
104#define CMD_INTERRUPT 6
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100105#define CMD_BACKTRACE 7
106#define CMD_FRAME 8
107#define CMD_UP 9
108#define CMD_DOWN 10
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109
110#ifdef ALWAYS_USE_GUI
111 /* Can't do this when there is no terminal for input/output. */
112 if (!gui.in_use)
113 {
114 /* Break as soon as possible. */
115 debug_break_level = 9999;
116 return;
117 }
118#endif
119
120 /* Make sure we are in raw mode and start termcap mode. Might have side
121 * effects... */
122 settmode(TMODE_RAW);
123 starttermcap();
124
125 ++RedrawingDisabled; /* don't redisplay the window */
126 ++no_wait_return; /* don't wait for return */
127 did_emsg = FALSE; /* don't use error from debugged stuff */
128 cmd_silent = FALSE; /* display commands */
129 msg_silent = FALSE; /* display messages */
130 emsg_silent = FALSE; /* display error messages */
131 redir_off = TRUE; /* don't redirect debug commands */
132
133 State = NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134
135 if (!debug_did_msg)
136 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
137 if (sourcing_name != NULL)
138 msg(sourcing_name);
139 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000142 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143
144 /*
145 * Repeat getting a command and executing it.
146 */
147 for (;;)
148 {
149 msg_scroll = TRUE;
150 need_wait_return = FALSE;
Bram Moolenaar85b11762016-02-27 18:13:23 +0100151
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 save_ex_normal_busy = ex_normal_busy;
158 ex_normal_busy = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000160 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 typeahead_saved = TRUE;
163 save_ignore_script = ignore_script;
164 ignore_script = TRUE;
165 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166
Bram Moolenaardc303bc2016-05-17 17:45:38 +0200167 vim_free(cmdline);
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000168 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000170 if (typeahead_saved)
171 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000173 ignore_script = save_ignore_script;
174 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176
177 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100178 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 if (cmdline != NULL)
180 {
181 /* If this is a debug command, set "last_cmd".
182 * If not, reset "last_cmd".
183 * For a blank line use previous command. */
184 p = skipwhite(cmdline);
185 if (*p != NUL)
186 {
187 switch (*p)
188 {
189 case 'c': last_cmd = CMD_CONT;
190 tail = "ont";
191 break;
192 case 'n': last_cmd = CMD_NEXT;
193 tail = "ext";
194 break;
195 case 's': last_cmd = CMD_STEP;
196 tail = "tep";
197 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100198 case 'f':
199 last_cmd = 0;
200 if (p[1] == 'r')
201 {
202 last_cmd = CMD_FRAME;
203 tail = "rame";
204 }
205 else
206 {
207 last_cmd = CMD_FINISH;
208 tail = "inish";
209 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210 break;
211 case 'q': last_cmd = CMD_QUIT;
212 tail = "uit";
213 break;
214 case 'i': last_cmd = CMD_INTERRUPT;
215 tail = "nterrupt";
216 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100217 case 'b': last_cmd = CMD_BACKTRACE;
218 if (p[1] == 't')
219 tail = "t";
220 else
221 tail = "acktrace";
222 break;
223 case 'w': last_cmd = CMD_BACKTRACE;
224 tail = "here";
225 break;
226 case 'u': last_cmd = CMD_UP;
227 tail = "p";
228 break;
229 case 'd': last_cmd = CMD_DOWN;
230 tail = "own";
231 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 default: last_cmd = 0;
233 }
234 if (last_cmd != 0)
235 {
236 /* Check that the tail matches. */
237 ++p;
238 while (*p != NUL && *p == *tail)
239 {
240 ++p;
241 ++tail;
242 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100243 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 last_cmd = 0;
245 }
246 }
247
248 if (last_cmd != 0)
249 {
250 /* Execute debug command: decided where to break next and
251 * return. */
252 switch (last_cmd)
253 {
254 case CMD_CONT:
255 debug_break_level = -1;
256 break;
257 case CMD_NEXT:
258 debug_break_level = ex_nesting_level;
259 break;
260 case CMD_STEP:
261 debug_break_level = 9999;
262 break;
263 case CMD_FINISH:
264 debug_break_level = ex_nesting_level - 1;
265 break;
266 case CMD_QUIT:
267 got_int = TRUE;
268 debug_break_level = -1;
269 break;
270 case CMD_INTERRUPT:
271 got_int = TRUE;
272 debug_break_level = 9999;
273 /* Do not repeat ">interrupt" cmd, continue stepping. */
274 last_cmd = CMD_STEP;
275 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100276 case CMD_BACKTRACE:
277 do_showbacktrace(cmd);
278 continue;
279 case CMD_FRAME:
280 if (*p == NUL)
281 {
282 do_showbacktrace(cmd);
283 }
284 else
285 {
286 p = skipwhite(p);
287 do_setdebugtracelevel(p);
288 }
289 continue;
290 case CMD_UP:
291 debug_backtrace_level++;
292 do_checkbacktracelevel();
293 continue;
294 case CMD_DOWN:
295 debug_backtrace_level--;
296 do_checkbacktracelevel();
297 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100299 /* Going out reset backtrace_level */
300 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301 break;
302 }
303
304 /* don't debug this command */
305 n = debug_break_level;
306 debug_break_level = -1;
307 (void)do_cmdline(cmdline, getexline, NULL,
308 DOCMD_VERBOSE|DOCMD_EXCRESET);
309 debug_break_level = n;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 }
311 lines_left = Rows - 1;
312 }
313 vim_free(cmdline);
314
315 --RedrawingDisabled;
316 --no_wait_return;
317 redraw_all_later(NOT_VALID);
318 need_wait_return = FALSE;
319 msg_scroll = save_msg_scroll;
320 lines_left = Rows - 1;
321 State = save_State;
322 did_emsg = save_did_emsg;
323 cmd_silent = save_cmd_silent;
324 msg_silent = save_msg_silent;
325 emsg_silent = save_emsg_silent;
326 redir_off = save_redir_off;
327
328 /* Only print the message again when typing a command before coming back
329 * here. */
330 debug_did_msg = TRUE;
331}
332
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100333 static int
334get_maxbacktrace_level(void)
335{
336 char *p, *q;
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200337 int maxbacktrace = 0;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100338
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100339 if (sourcing_name != NULL)
340 {
341 p = (char *)sourcing_name;
342 while ((q = strstr(p, "..")) != NULL)
343 {
344 p = q + 2;
345 maxbacktrace++;
346 }
347 }
348 return maxbacktrace;
349}
350
351 static void
352do_setdebugtracelevel(char_u *arg)
353{
354 int level;
355
356 level = atoi((char *)arg);
357 if (*arg == '+' || level < 0)
358 debug_backtrace_level += level;
359 else
360 debug_backtrace_level = level;
361
362 do_checkbacktracelevel();
363}
364
365 static void
366do_checkbacktracelevel(void)
367{
368 if (debug_backtrace_level < 0)
369 {
370 debug_backtrace_level = 0;
371 MSG(_("frame is zero"));
372 }
373 else
374 {
375 int max = get_maxbacktrace_level();
376
377 if (debug_backtrace_level > max)
378 {
379 debug_backtrace_level = max;
380 smsg((char_u *)_("frame at highest level: %d"), max);
381 }
382 }
383}
384
385 static void
386do_showbacktrace(char_u *cmd)
387{
388 char *cur;
389 char *next;
390 int i = 0;
391 int max = get_maxbacktrace_level();
392
393 if (sourcing_name != NULL)
394 {
395 cur = (char *)sourcing_name;
396 while (!got_int)
397 {
398 next = strstr(cur, "..");
399 if (next != NULL)
400 *next = NUL;
401 if (i == max - debug_backtrace_level)
402 smsg((char_u *)"->%d %s", max - i, cur);
403 else
404 smsg((char_u *)" %d %s", max - i, cur);
405 ++i;
406 if (next == NULL)
407 break;
408 *next = '.';
409 cur = next + 2;
410 }
411 }
412 if (sourcing_lnum != 0)
413 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
414 else
415 smsg((char_u *)_("cmd: %s"), cmd);
416}
417
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418/*
419 * ":debug".
420 */
421 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100422ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423{
424 int debug_break_level_save = debug_break_level;
425
426 debug_break_level = 9999;
427 do_cmdline_cmd(eap->arg);
428 debug_break_level = debug_break_level_save;
429}
430
431static char_u *debug_breakpoint_name = NULL;
432static linenr_T debug_breakpoint_lnum;
433
434/*
435 * When debugging or a breakpoint is set on a skipped command, no debug prompt
436 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
437 * debug_skipped_name is then set to the source name in the breakpoint case. If
438 * a skipped command decides itself that a debug prompt should be displayed, it
439 * can do so by calling dbg_check_skipped().
440 */
441static int debug_skipped;
442static char_u *debug_skipped_name;
443
444/*
445 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
446 * at or below the break level. But only when the line is actually
447 * executed. Return TRUE and set breakpoint_name for skipped commands that
448 * decide to execute something themselves.
449 * Called from do_one_cmd() before executing a command.
450 */
451 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100452dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453{
454 char_u *p;
455
456 debug_skipped = FALSE;
457 if (debug_breakpoint_name != NULL)
458 {
459 if (!eap->skip)
460 {
461 /* replace K_SNR with "<SNR>" */
462 if (debug_breakpoint_name[0] == K_SPECIAL
463 && debug_breakpoint_name[1] == KS_EXTRA
464 && debug_breakpoint_name[2] == (int)KE_SNR)
465 p = (char_u *)"<SNR>";
466 else
467 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000468 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
469 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 debug_breakpoint_name + (*p == NUL ? 0 : 3),
471 (long)debug_breakpoint_lnum);
472 debug_breakpoint_name = NULL;
473 do_debug(eap->cmd);
474 }
475 else
476 {
477 debug_skipped = TRUE;
478 debug_skipped_name = debug_breakpoint_name;
479 debug_breakpoint_name = NULL;
480 }
481 }
482 else if (ex_nesting_level <= debug_break_level)
483 {
484 if (!eap->skip)
485 do_debug(eap->cmd);
486 else
487 {
488 debug_skipped = TRUE;
489 debug_skipped_name = NULL;
490 }
491 }
492}
493
494/*
495 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
496 * set. Return TRUE when the debug mode is entered this time.
497 */
498 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100499dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500{
501 int prev_got_int;
502
503 if (debug_skipped)
504 {
505 /*
506 * Save the value of got_int and reset it. We don't want a previous
507 * interruption cause flushing the input buffer.
508 */
509 prev_got_int = got_int;
510 got_int = FALSE;
511 debug_breakpoint_name = debug_skipped_name;
512 /* eap->skip is TRUE */
513 eap->skip = FALSE;
514 (void)dbg_check_breakpoint(eap);
515 eap->skip = TRUE;
516 got_int |= prev_got_int;
517 return TRUE;
518 }
519 return FALSE;
520}
521
522/*
523 * The list of breakpoints: dbg_breakp.
524 * This is a grow-array of structs.
525 */
526struct debuggy
527{
528 int dbg_nr; /* breakpoint number */
529 int dbg_type; /* DBG_FUNC or DBG_FILE */
530 char_u *dbg_name; /* function or file name */
531 regprog_T *dbg_prog; /* regexp program */
532 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534};
535
536static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000537#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
538#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539static int last_breakp = 0; /* nr of last defined breakpoint */
540
Bram Moolenaar05159a02005-02-26 23:04:13 +0000541#ifdef FEAT_PROFILE
542/* Profiling uses file and func names similar to breakpoints. */
543static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
544#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545#define DBG_FUNC 1
546#define DBG_FILE 2
547
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100548static int dbg_parsearg(char_u *arg, garray_T *gap);
549static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550
551/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000552 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
553 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
554 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 * Returns FAIL for failure.
556 */
557 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100558dbg_parsearg(
559 char_u *arg,
560 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561{
562 char_u *p = arg;
563 char_u *q;
564 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000565 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566
Bram Moolenaar05159a02005-02-26 23:04:13 +0000567 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000569 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570
571 /* Find "func" or "file". */
572 if (STRNCMP(p, "func", 4) == 0)
573 bp->dbg_type = DBG_FUNC;
574 else if (STRNCMP(p, "file", 4) == 0)
575 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000576 else if (
577#ifdef FEAT_PROFILE
578 gap != &prof_ga &&
579#endif
580 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000581 {
582 if (curbuf->b_ffname == NULL)
583 {
584 EMSG(_(e_noname));
585 return FAIL;
586 }
587 bp->dbg_type = DBG_FILE;
588 here = TRUE;
589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590 else
591 {
592 EMSG2(_(e_invarg2), p);
593 return FAIL;
594 }
595 p = skipwhite(p + 4);
596
597 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000598 if (here)
599 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000600 else if (
601#ifdef FEAT_PROFILE
602 gap != &prof_ga &&
603#endif
604 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 {
606 bp->dbg_lnum = getdigits(&p);
607 p = skipwhite(p);
608 }
609 else
610 bp->dbg_lnum = 0;
611
612 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000613 if ((!here && *p == NUL)
614 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
616 {
617 EMSG2(_(e_invarg2), arg);
618 return FAIL;
619 }
620
621 if (bp->dbg_type == DBG_FUNC)
622 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000623 else if (here)
624 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 else
626 {
627 /* Expand the file name in the same way as do_source(). This means
628 * doing it twice, so that $DIR/file gets expanded when $DIR is
629 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 if (q == NULL)
632 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 vim_free(q);
635 if (p == NULL)
636 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000637 if (*p != '*')
638 {
639 bp->dbg_name = fix_fname(p);
640 vim_free(p);
641 }
642 else
643 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 }
645
646 if (bp->dbg_name == NULL)
647 return FAIL;
648 return OK;
649}
650
651/*
652 * ":breakadd".
653 */
654 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100655ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656{
657 struct debuggy *bp;
658 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000659 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660
Bram Moolenaar05159a02005-02-26 23:04:13 +0000661 gap = &dbg_breakp;
662#ifdef FEAT_PROFILE
663 if (eap->cmdidx == CMD_profile)
664 gap = &prof_ga;
665#endif
666
667 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000669 bp = &DEBUGGY(gap, gap->ga_len);
670 bp->dbg_forceit = eap->forceit;
671
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
673 if (pat != NULL)
674 {
675 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
676 vim_free(pat);
677 }
678 if (pat == NULL || bp->dbg_prog == NULL)
679 vim_free(bp->dbg_name);
680 else
681 {
682 if (bp->dbg_lnum == 0) /* default line number is 1 */
683 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000684#ifdef FEAT_PROFILE
685 if (eap->cmdidx != CMD_profile)
686#endif
687 {
688 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
689 ++debug_tick;
690 }
691 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 }
693 }
694}
695
696/*
697 * ":debuggreedy".
698 */
699 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100700ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701{
702 if (eap->addr_count == 0 || eap->line2 != 0)
703 debug_greedy = TRUE;
704 else
705 debug_greedy = FALSE;
706}
707
708/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000709 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 */
711 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100712ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713{
714 struct debuggy *bp, *bpi;
715 int nr;
716 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000717 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 int i;
719 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000720 garray_T *gap;
721
722 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000723 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200724 {
725#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000726 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200727#else
728 ex_ni(eap);
729 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000730#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200731 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732
733 if (vim_isdigit(*eap->arg))
734 {
735 /* ":breakdel {nr}" */
736 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000737 for (i = 0; i < gap->ga_len; ++i)
738 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 {
740 todel = i;
741 break;
742 }
743 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000744 else if (*eap->arg == '*')
745 {
746 todel = 0;
747 del_all = TRUE;
748 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 else
750 {
751 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000752 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000754 bp = &DEBUGGY(gap, gap->ga_len);
755 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000757 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 if (bp->dbg_type == bpi->dbg_type
759 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
760 && (bp->dbg_lnum == bpi->dbg_lnum
761 || (bp->dbg_lnum == 0
762 && (best_lnum == 0
763 || bpi->dbg_lnum < best_lnum))))
764 {
765 todel = i;
766 best_lnum = bpi->dbg_lnum;
767 }
768 }
769 vim_free(bp->dbg_name);
770 }
771
772 if (todel < 0)
773 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
774 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000775 {
776 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000777 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000778 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200779 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000780 --gap->ga_len;
781 if (todel < gap->ga_len)
782 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
783 (gap->ga_len - todel) * sizeof(struct debuggy));
784#ifdef FEAT_PROFILE
785 if (eap->cmdidx == CMD_breakdel)
786#endif
787 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000788 if (!del_all)
789 break;
790 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000791
792 /* If all breakpoints were removed clear the array. */
793 if (gap->ga_len == 0)
794 ga_clear(gap);
795 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796}
797
798/*
799 * ":breaklist".
800 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100802ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803{
804 struct debuggy *bp;
805 int i;
806
807 if (dbg_breakp.ga_len == 0)
808 MSG(_("No breakpoints defined"));
809 else
810 for (i = 0; i < dbg_breakp.ga_len; ++i)
811 {
812 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200813 if (bp->dbg_type == DBG_FILE)
814 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 smsg((char_u *)_("%3d %s %s line %ld"),
816 bp->dbg_nr,
817 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200818 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 (long)bp->dbg_lnum);
820 }
821}
822
823/*
824 * Find a breakpoint for a function or sourced file.
825 * Returns line number at which to break; zero when no matching breakpoint.
826 */
827 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100828dbg_find_breakpoint(
829 int file, /* TRUE for a file, FALSE for a function */
830 char_u *fname, /* file or function name */
831 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000833 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
834}
835
836#if defined(FEAT_PROFILE) || defined(PROTO)
837/*
838 * Return TRUE if profiling is on for a function or sourced file.
839 */
840 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100841has_profiling(
842 int file, /* TRUE for a file, FALSE for a function */
843 char_u *fname, /* file or function name */
844 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845{
846 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
847 != (linenr_T)0);
848}
849#endif
850
851/*
852 * Common code for dbg_find_breakpoint() and has_profiling().
853 */
854 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100855debuggy_find(
856 int file, /* TRUE for a file, FALSE for a function */
857 char_u *fname, /* file or function name */
858 linenr_T after, /* after this line number */
859 garray_T *gap, /* either &dbg_breakp or &prof_ga */
860 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 struct debuggy *bp;
863 int i;
864 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 char_u *name = fname;
866 int prev_got_int;
867
Bram Moolenaar05159a02005-02-26 23:04:13 +0000868 /* Return quickly when there are no breakpoints. */
869 if (gap->ga_len == 0)
870 return (linenr_T)0;
871
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 /* Replace K_SNR in function name with "<SNR>". */
873 if (!file && fname[0] == K_SPECIAL)
874 {
875 name = alloc((unsigned)STRLEN(fname) + 3);
876 if (name == NULL)
877 name = fname;
878 else
879 {
880 STRCPY(name, "<SNR>");
881 STRCPY(name + 5, fname + 3);
882 }
883 }
884
Bram Moolenaar05159a02005-02-26 23:04:13 +0000885 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000887 /* Skip entries that are not useful or are for a line that is beyond
888 * an already found breakpoint. */
889 bp = &DEBUGGY(gap, i);
890 if (((bp->dbg_type == DBG_FILE) == file && (
891#ifdef FEAT_PROFILE
892 gap == &prof_ga ||
893#endif
894 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000897 * Save the value of got_int and reset it. We don't want a
898 * previous interruption cancel matching, only hitting CTRL-C
899 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900 */
901 prev_got_int = got_int;
902 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100903 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000904 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000906 if (fp != NULL)
907 *fp = bp->dbg_forceit;
908 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 got_int |= prev_got_int;
910 }
911 }
912 if (name != fname)
913 vim_free(name);
914
915 return lnum;
916}
917
918/*
919 * Called when a breakpoint was encountered.
920 */
921 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100922dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923{
924 /* We need to check if this line is actually executed in do_one_cmd() */
925 debug_breakpoint_name = name;
926 debug_breakpoint_lnum = lnum;
927}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000928
929
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000930# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000931/*
932 * Store the current time in "tm".
933 */
934 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100935profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000936{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000937# ifdef WIN3264
938 QueryPerformanceCounter(tm);
939# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000940 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000941# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000942}
943
944/*
945 * Compute the elapsed time from "tm" till now and store in "tm".
946 */
947 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100948profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000949{
950 proftime_T now;
951
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000952# ifdef WIN3264
953 QueryPerformanceCounter(&now);
954 tm->QuadPart = now.QuadPart - tm->QuadPart;
955# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000956 gettimeofday(&now, NULL);
957 tm->tv_usec = now.tv_usec - tm->tv_usec;
958 tm->tv_sec = now.tv_sec - tm->tv_sec;
959 if (tm->tv_usec < 0)
960 {
961 tm->tv_usec += 1000000;
962 --tm->tv_sec;
963 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000964# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000965}
966
967/*
968 * Subtract the time "tm2" from "tm".
969 */
970 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100971profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000972{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000973# ifdef WIN3264
974 tm->QuadPart -= tm2->QuadPart;
975# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000976 tm->tv_usec -= tm2->tv_usec;
977 tm->tv_sec -= tm2->tv_sec;
978 if (tm->tv_usec < 0)
979 {
980 tm->tv_usec += 1000000;
981 --tm->tv_sec;
982 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000983# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000984}
985
986/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000987 * Return a string that represents the time in "tm".
988 * Uses a static buffer!
989 */
990 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100991profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000992{
993 static char buf[50];
994
995# ifdef WIN3264
996 LARGE_INTEGER fr;
997
998 QueryPerformanceFrequency(&fr);
999 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1000# else
1001 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001002# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001003 return buf;
1004}
1005
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001006# if defined(FEAT_FLOAT) || defined(PROTO)
1007/*
1008 * Return a float that represents the time in "tm".
1009 */
1010 float_T
1011profile_float(proftime_T *tm)
1012{
1013# ifdef WIN3264
1014 LARGE_INTEGER fr;
1015
1016 QueryPerformanceFrequency(&fr);
1017 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
1018# else
1019 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
1020# endif
1021}
1022# endif
1023
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001024/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001025 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001026 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001027 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001028profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001029{
1030 if (msec <= 0) /* no limit */
1031 profile_zero(tm);
1032 else
1033 {
1034# ifdef WIN3264
1035 LARGE_INTEGER fr;
1036
1037 QueryPerformanceCounter(tm);
1038 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001039 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001040# else
1041 long usec;
1042
1043 gettimeofday(tm, NULL);
1044 usec = (long)tm->tv_usec + (long)msec * 1000;
1045 tm->tv_usec = usec % 1000000L;
1046 tm->tv_sec += usec / 1000000L;
1047# endif
1048 }
1049}
1050
1051/*
1052 * Return TRUE if the current time is past "tm".
1053 */
1054 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001055profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001056{
1057 proftime_T now;
1058
1059# ifdef WIN3264
1060 if (tm->QuadPart == 0) /* timer was not set */
1061 return FALSE;
1062 QueryPerformanceCounter(&now);
1063 return (now.QuadPart > tm->QuadPart);
1064# else
1065 if (tm->tv_sec == 0) /* timer was not set */
1066 return FALSE;
1067 gettimeofday(&now, NULL);
1068 return (now.tv_sec > tm->tv_sec
1069 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1070# endif
1071}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001072
1073/*
1074 * Set the time in "tm" to zero.
1075 */
1076 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001077profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001078{
1079# ifdef WIN3264
1080 tm->QuadPart = 0;
1081# else
1082 tm->tv_usec = 0;
1083 tm->tv_sec = 0;
1084# endif
1085}
1086
Bram Moolenaar76929292008-01-06 19:07:36 +00001087# endif /* FEAT_PROFILE || FEAT_RELTIME */
1088
Bram Moolenaar975b5272016-03-15 23:10:59 +01001089# if defined(FEAT_TIMERS) || defined(PROTO)
1090static timer_T *first_timer = NULL;
1091static int last_timer_id = 0;
1092
1093/*
1094 * Insert a timer in the list of timers.
1095 */
1096 static void
1097insert_timer(timer_T *timer)
1098{
1099 timer->tr_next = first_timer;
1100 timer->tr_prev = NULL;
1101 if (first_timer != NULL)
1102 first_timer->tr_prev = timer;
1103 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +02001104 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001105}
1106
1107/*
1108 * Take a timer out of the list of timers.
1109 */
1110 static void
1111remove_timer(timer_T *timer)
1112{
1113 if (timer->tr_prev == NULL)
1114 first_timer = timer->tr_next;
1115 else
1116 timer->tr_prev->tr_next = timer->tr_next;
1117 if (timer->tr_next != NULL)
1118 timer->tr_next->tr_prev = timer->tr_prev;
1119}
1120
1121 static void
1122free_timer(timer_T *timer)
1123{
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
Bram Moolenaarcf089462016-06-12 21:18:43 +02001177check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001178{
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}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001256
1257/*
1258 * Mark references in partials of timers.
1259 */
1260 int
1261set_ref_in_timer(int copyID)
1262{
1263 int abort = FALSE;
1264 timer_T *timer;
1265 typval_T tv;
1266
1267 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1268 {
1269 tv.v_type = VAR_PARTIAL;
1270 tv.vval.v_partial = timer->tr_partial;
1271 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1272 }
1273 return abort;
1274}
Bram Moolenaar975b5272016-03-15 23:10:59 +01001275# endif
1276
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001277#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1278# if defined(HAVE_MATH_H)
1279# include <math.h>
1280# endif
1281
1282/*
1283 * Divide the time "tm" by "count" and store in "tm2".
1284 */
1285 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001286profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001287{
1288 if (count == 0)
1289 profile_zero(tm2);
1290 else
1291 {
1292# ifdef WIN3264
1293 tm2->QuadPart = tm->QuadPart / count;
1294# else
1295 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1296
1297 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001298 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001299# endif
1300 }
1301}
1302#endif
1303
Bram Moolenaar76929292008-01-06 19:07:36 +00001304# if defined(FEAT_PROFILE) || defined(PROTO)
1305/*
1306 * Functions for profiling.
1307 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001308static void script_do_profile(scriptitem_T *si);
1309static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001310static proftime_T prof_wait_time;
1311
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001312/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001313 * Add the time "tm2" to "tm".
1314 */
1315 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001316profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001317{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001318# ifdef WIN3264
1319 tm->QuadPart += tm2->QuadPart;
1320# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001321 tm->tv_usec += tm2->tv_usec;
1322 tm->tv_sec += tm2->tv_sec;
1323 if (tm->tv_usec >= 1000000)
1324 {
1325 tm->tv_usec -= 1000000;
1326 ++tm->tv_sec;
1327 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001328# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001329}
1330
1331/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001332 * Add the "self" time from the total time and the children's time.
1333 */
1334 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001335profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001336{
1337 /* Check that the result won't be negative. Can happen with recursive
1338 * calls. */
1339#ifdef WIN3264
1340 if (total->QuadPart <= children->QuadPart)
1341 return;
1342#else
1343 if (total->tv_sec < children->tv_sec
1344 || (total->tv_sec == children->tv_sec
1345 && total->tv_usec <= children->tv_usec))
1346 return;
1347#endif
1348 profile_add(self, total);
1349 profile_sub(self, children);
1350}
1351
1352/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001353 * Get the current waittime.
1354 */
1355 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001356profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001357{
1358 *tm = prof_wait_time;
1359}
1360
1361/*
1362 * Subtract the passed waittime since "tm" from "tma".
1363 */
1364 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001365profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001366{
1367 proftime_T tm3 = prof_wait_time;
1368
1369 profile_sub(&tm3, tm);
1370 profile_sub(tma, &tm3);
1371}
1372
1373/*
1374 * Return TRUE if "tm1" and "tm2" are equal.
1375 */
1376 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001377profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001378{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001379# ifdef WIN3264
1380 return (tm1->QuadPart == tm2->QuadPart);
1381# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001382 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001383# endif
1384}
1385
1386/*
1387 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1388 */
1389 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001390profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001391{
1392# ifdef WIN3264
1393 return (int)(tm2->QuadPart - tm1->QuadPart);
1394# else
1395 if (tm1->tv_sec == tm2->tv_sec)
1396 return tm2->tv_usec - tm1->tv_usec;
1397 return tm2->tv_sec - tm1->tv_sec;
1398# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001399}
1400
Bram Moolenaar05159a02005-02-26 23:04:13 +00001401static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001402static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001403
1404/*
1405 * ":profile cmd args"
1406 */
1407 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001408ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001409{
1410 char_u *e;
1411 int len;
1412
1413 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001414 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001415 e = skipwhite(e);
1416
1417 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1418 {
1419 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001420 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001421 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001422 profile_zero(&prof_wait_time);
1423 set_vim_var_nr(VV_PROFILING, 1L);
1424 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001425 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001426 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001427 else if (STRCMP(eap->arg, "pause") == 0)
1428 {
1429 if (do_profiling == PROF_YES)
1430 profile_start(&pause_time);
1431 do_profiling = PROF_PAUSED;
1432 }
1433 else if (STRCMP(eap->arg, "continue") == 0)
1434 {
1435 if (do_profiling == PROF_PAUSED)
1436 {
1437 profile_end(&pause_time);
1438 profile_add(&prof_wait_time, &pause_time);
1439 }
1440 do_profiling = PROF_YES;
1441 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001442 else
1443 {
1444 /* The rest is similar to ":breakadd". */
1445 ex_breakadd(eap);
1446 }
1447}
1448
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001449/* Command line expansion for :profile. */
1450static enum
1451{
1452 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001453 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001454} pexpand_what;
1455
1456static char *pexpand_cmds[] = {
1457 "start",
1458#define PROFCMD_START 0
1459 "pause",
1460#define PROFCMD_PAUSE 1
1461 "continue",
1462#define PROFCMD_CONTINUE 2
1463 "func",
1464#define PROFCMD_FUNC 3
1465 "file",
1466#define PROFCMD_FILE 4
1467 NULL
1468#define PROFCMD_LAST 5
1469};
1470
1471/*
1472 * Function given to ExpandGeneric() to obtain the profile command
1473 * specific expansion.
1474 */
1475 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001476get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001477{
1478 switch (pexpand_what)
1479 {
1480 case PEXP_SUBCMD:
1481 return (char_u *)pexpand_cmds[idx];
1482 /* case PEXP_FUNC: TODO */
1483 default:
1484 return NULL;
1485 }
1486}
1487
1488/*
1489 * Handle command line completion for :profile command.
1490 */
1491 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001492set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001493{
1494 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001495
1496 /* Default: expand subcommands. */
1497 xp->xp_context = EXPAND_PROFILE;
1498 pexpand_what = PEXP_SUBCMD;
1499 xp->xp_pattern = arg;
1500
1501 end_subcmd = skiptowhite(arg);
1502 if (*end_subcmd == NUL)
1503 return;
1504
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001505 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001506 {
1507 xp->xp_context = EXPAND_FILES;
1508 xp->xp_pattern = skipwhite(end_subcmd);
1509 return;
1510 }
1511
1512 /* TODO: expand function names after "func" */
1513 xp->xp_context = EXPAND_NOTHING;
1514}
1515
Bram Moolenaar05159a02005-02-26 23:04:13 +00001516/*
1517 * Dump the profiling info.
1518 */
1519 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001520profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001521{
1522 FILE *fd;
1523
1524 if (profile_fname != NULL)
1525 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001526 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001527 if (fd == NULL)
1528 EMSG2(_(e_notopen), profile_fname);
1529 else
1530 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001531 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001532 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001533 fclose(fd);
1534 }
1535 }
1536}
1537
1538/*
1539 * Start profiling script "fp".
1540 */
1541 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001542script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001543{
1544 si->sn_pr_count = 0;
1545 profile_zero(&si->sn_pr_total);
1546 profile_zero(&si->sn_pr_self);
1547
1548 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1549 si->sn_prl_idx = -1;
1550 si->sn_prof_on = TRUE;
1551 si->sn_pr_nest = 0;
1552}
1553
1554/*
1555 * save time when starting to invoke another script or function.
1556 */
1557 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001558script_prof_save(
1559 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001560{
1561 scriptitem_T *si;
1562
1563 if (current_SID > 0 && current_SID <= script_items.ga_len)
1564 {
1565 si = &SCRIPT_ITEM(current_SID);
1566 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1567 profile_start(&si->sn_pr_child);
1568 }
1569 profile_get_wait(tm);
1570}
1571
1572/*
1573 * Count time spent in children after invoking another script or function.
1574 */
1575 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001576script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001577{
1578 scriptitem_T *si;
1579
1580 if (current_SID > 0 && current_SID <= script_items.ga_len)
1581 {
1582 si = &SCRIPT_ITEM(current_SID);
1583 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1584 {
1585 profile_end(&si->sn_pr_child);
1586 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1587 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1588 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1589 }
1590 }
1591}
1592
1593static proftime_T inchar_time;
1594
1595/*
1596 * Called when starting to wait for the user to type a character.
1597 */
1598 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001599prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001600{
1601 profile_start(&inchar_time);
1602}
1603
1604/*
1605 * Called when finished waiting for the user to type a character.
1606 */
1607 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001608prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001609{
1610 profile_end(&inchar_time);
1611 profile_add(&prof_wait_time, &inchar_time);
1612}
1613
1614/*
1615 * Dump the profiling results for all scripts in file "fd".
1616 */
1617 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001618script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001619{
1620 int id;
1621 scriptitem_T *si;
1622 int i;
1623 FILE *sfd;
1624 sn_prl_T *pp;
1625
1626 for (id = 1; id <= script_items.ga_len; ++id)
1627 {
1628 si = &SCRIPT_ITEM(id);
1629 if (si->sn_prof_on)
1630 {
1631 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1632 if (si->sn_pr_count == 1)
1633 fprintf(fd, "Sourced 1 time\n");
1634 else
1635 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1636 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1637 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1638 fprintf(fd, "\n");
1639 fprintf(fd, "count total (s) self (s)\n");
1640
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001641 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001642 if (sfd == NULL)
1643 fprintf(fd, "Cannot open file!\n");
1644 else
1645 {
1646 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1647 {
1648 if (vim_fgets(IObuff, IOSIZE, sfd))
1649 break;
1650 pp = &PRL_ITEM(si, i);
1651 if (pp->snp_count > 0)
1652 {
1653 fprintf(fd, "%5d ", pp->snp_count);
1654 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1655 fprintf(fd, " ");
1656 else
1657 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1658 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1659 }
1660 else
1661 fprintf(fd, " ");
1662 fprintf(fd, "%s", IObuff);
1663 }
1664 fclose(sfd);
1665 }
1666 fprintf(fd, "\n");
1667 }
1668 }
1669}
1670
1671/*
1672 * Return TRUE when a function defined in the current script should be
1673 * profiled.
1674 */
1675 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001676prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001677{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001678 if (current_SID > 0)
1679 return SCRIPT_ITEM(current_SID).sn_pr_force;
1680 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001681}
1682
1683# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684#endif
1685
1686/*
1687 * If 'autowrite' option set, try to write the file.
1688 * Careful: autocommands may make "buf" invalid!
1689 *
1690 * return FAIL for failure, OK otherwise
1691 */
1692 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001693autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001694{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001695 int r;
1696
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697 if (!(p_aw || p_awa) || !p_write
1698#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001699 /* never autowrite a "nofile" or "nowrite" buffer */
1700 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001701#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001702 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001704 r = buf_write_all(buf, forceit);
1705
1706 /* Writing may succeed but the buffer still changed, e.g., when there is a
1707 * conversion error. We do want to return FAIL then. */
1708 if (buf_valid(buf) && bufIsChanged(buf))
1709 r = FAIL;
1710 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711}
1712
1713/*
1714 * flush all buffers, except the ones that are readonly
1715 */
1716 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001717autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001718{
1719 buf_T *buf;
1720
1721 if (!(p_aw || p_awa) || !p_write)
1722 return;
1723 for (buf = firstbuf; buf; buf = buf->b_next)
1724 if (bufIsChanged(buf) && !buf->b_p_ro)
1725 {
1726 (void)buf_write_all(buf, FALSE);
1727#ifdef FEAT_AUTOCMD
1728 /* an autocommand may have deleted the buffer */
1729 if (!buf_valid(buf))
1730 buf = firstbuf;
1731#endif
1732 }
1733}
1734
1735/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001736 * Return TRUE if buffer was changed and cannot be abandoned.
1737 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001740check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001742 int forceit = (flags & CCGD_FORCEIT);
1743
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744 if ( !forceit
1745 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001746 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1747 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748 {
1749#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1750 if ((p_confirm || cmdmod.confirm) && p_write)
1751 {
1752 buf_T *buf2;
1753 int count = 0;
1754
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001755 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1757 if (bufIsChanged(buf2)
1758 && (buf2->b_ffname != NULL
1759# ifdef FEAT_BROWSE
1760 || cmdmod.browse
1761# endif
1762 ))
1763 ++count;
1764# ifdef FEAT_AUTOCMD
1765 if (!buf_valid(buf))
1766 /* Autocommand deleted buffer, oops! It's not changed now. */
1767 return FALSE;
1768# endif
1769 dialog_changed(buf, count > 1);
1770# ifdef FEAT_AUTOCMD
1771 if (!buf_valid(buf))
1772 /* Autocommand deleted buffer, oops! It's not changed now. */
1773 return FALSE;
1774# endif
1775 return bufIsChanged(buf);
1776 }
1777#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001778 if (flags & CCGD_EXCMD)
1779 EMSG(_(e_nowrtmsg));
1780 else
1781 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001782 return TRUE;
1783 }
1784 return FALSE;
1785}
1786
1787#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1788
1789#if defined(FEAT_BROWSE) || defined(PROTO)
1790/*
1791 * When wanting to write a file without a file name, ask the user for a name.
1792 */
1793 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001794browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795{
1796 if (buf->b_fname == NULL)
1797 {
1798 char_u *fname;
1799
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001800 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1801 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802 if (fname != NULL)
1803 {
1804 if (setfname(buf, fname, NULL, TRUE) == OK)
1805 buf->b_flags |= BF_NOTEDITED;
1806 vim_free(fname);
1807 }
1808 }
1809}
1810#endif
1811
1812/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001813 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814 * Must check 'write' option first!
1815 */
1816 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001817dialog_changed(
1818 buf_T *buf,
1819 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001821 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822 int ret;
1823 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001824 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001825
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001826 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827 (buf->b_fname != NULL) ?
1828 buf->b_fname : (char_u *)_("Untitled"));
1829 if (checkall)
1830 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1831 else
1832 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1833
Bram Moolenaar8218f602012-04-25 17:32:18 +02001834 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1835 * function. */
1836 ea.append = ea.forceit = FALSE;
1837
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 if (ret == VIM_YES)
1839 {
1840#ifdef FEAT_BROWSE
1841 /* May get file name, when there is none */
1842 browse_save_fname(buf);
1843#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001844 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1845 buf->b_fname, buf->b_ffname, FALSE) == OK)
1846 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847 (void)buf_write_all(buf, FALSE);
1848 }
1849 else if (ret == VIM_NO)
1850 {
1851 unchanged(buf, TRUE);
1852 }
1853 else if (ret == VIM_ALL)
1854 {
1855 /*
1856 * Write all modified files that can be written.
1857 * Skip readonly buffers, these need to be confirmed
1858 * individually.
1859 */
1860 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1861 {
1862 if (bufIsChanged(buf2)
1863 && (buf2->b_ffname != NULL
1864#ifdef FEAT_BROWSE
1865 || cmdmod.browse
1866#endif
1867 )
1868 && !buf2->b_p_ro)
1869 {
1870#ifdef FEAT_BROWSE
1871 /* May get file name, when there is none */
1872 browse_save_fname(buf2);
1873#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001874 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1875 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1876 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877 (void)buf_write_all(buf2, FALSE);
1878#ifdef FEAT_AUTOCMD
1879 /* an autocommand may have deleted the buffer */
1880 if (!buf_valid(buf2))
1881 buf2 = firstbuf;
1882#endif
1883 }
1884 }
1885 }
1886 else if (ret == VIM_DISCARDALL)
1887 {
1888 /*
1889 * mark all buffers as unchanged
1890 */
1891 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1892 unchanged(buf2, TRUE);
1893 }
1894}
1895#endif
1896
1897/*
1898 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1899 * hidden, autowriting it or unloading it.
1900 */
1901 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001902can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903{
1904 return ( P_HID(buf)
1905 || !bufIsChanged(buf)
1906 || buf->b_nwindows > 1
1907 || autowrite(buf, forceit) == OK
1908 || forceit);
1909}
1910
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001911static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001912
1913/*
1914 * Add a buffer number to "bufnrs", unless it's already there.
1915 */
1916 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001917add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001918{
1919 int i;
1920
1921 for (i = 0; i < *bufnump; ++i)
1922 if (bufnrs[i] == nr)
1923 return;
1924 bufnrs[*bufnump] = nr;
1925 *bufnump = *bufnump + 1;
1926}
1927
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928/*
1929 * Return TRUE if any buffer was changed and cannot be abandoned.
1930 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001931 * When "unload" is true the current buffer is unloaded instead of making it
1932 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 */
1934 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001935check_changed_any(
1936 int hidden, /* Only check hidden buffers */
1937 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001939 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 buf_T *buf;
1941 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001942 int i;
1943 int bufnum = 0;
1944 int bufcount = 0;
1945 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001946#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001947 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 win_T *wp;
1949#endif
1950
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001951 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1952 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001954 if (bufcount == 0)
1955 return FALSE;
1956
1957 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1958 if (bufnrs == NULL)
1959 return FALSE;
1960
1961 /* curbuf */
1962 bufnrs[bufnum++] = curbuf->b_fnum;
1963#ifdef FEAT_WINDOWS
1964 /* buf in curtab */
1965 FOR_ALL_WINDOWS(wp)
1966 if (wp->w_buffer != curbuf)
1967 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1968
1969 /* buf in other tab */
1970 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1971 if (tp != curtab)
1972 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1973 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1974#endif
1975 /* any other buf */
1976 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1977 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1978
1979 for (i = 0; i < bufnum; ++i)
1980 {
1981 buf = buflist_findnr(bufnrs[i]);
1982 if (buf == NULL)
1983 continue;
1984 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1985 {
1986 /* Try auto-writing the buffer. If this fails but the buffer no
1987 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001988 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1989 | CCGD_MULTWIN
1990 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001991 break; /* didn't save - still changes */
1992 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001993 }
1994
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001995 if (i >= bufnum)
1996 goto theend;
1997
1998 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999 exiting = FALSE;
2000#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2001 /*
2002 * When ":confirm" used, don't give an error message.
2003 */
2004 if (!(p_confirm || cmdmod.confirm))
2005#endif
2006 {
2007 /* There must be a wait_return for this message, do_buffer()
2008 * may cause a redraw. But wait_return() is a no-op when vgetc()
2009 * is busy (Quit used from window menu), then make sure we don't
2010 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002011 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002012 {
2013 msg_row = cmdline_row;
2014 msg_col = 0;
2015 msg_didout = FALSE;
2016 }
2017 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002018 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002019 {
2020 save = no_wait_return;
2021 no_wait_return = FALSE;
2022 wait_return(FALSE);
2023 no_wait_return = save;
2024 }
2025 }
2026
2027#ifdef FEAT_WINDOWS
2028 /* Try to find a window that contains the buffer. */
2029 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002030 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031 if (wp->w_buffer == buf)
2032 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002033 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002034# ifdef FEAT_AUTOCMD
2035 /* Paranoia: did autocms wipe out the buffer with changes? */
2036 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002037 {
2038 goto theend;
2039 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002040# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002041 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002042 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002043buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002044#endif
2045
2046 /* Open the changed buffer in the current window. */
2047 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002048 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002049
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002050theend:
2051 vim_free(bufnrs);
2052 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053}
2054
2055/*
2056 * return FAIL if there is no file name, OK if there is one
2057 * give error message for FAIL
2058 */
2059 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002060check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002061{
2062 if (curbuf->b_ffname == NULL)
2063 {
2064 EMSG(_(e_noname));
2065 return FAIL;
2066 }
2067 return OK;
2068}
2069
2070/*
2071 * flush the contents of a buffer, unless it has no file name
2072 *
2073 * return FAIL for failure, OK otherwise
2074 */
2075 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002076buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002077{
2078 int retval;
2079#ifdef FEAT_AUTOCMD
2080 buf_T *old_curbuf = curbuf;
2081#endif
2082
2083 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2084 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2085 FALSE, forceit, TRUE, FALSE));
2086#ifdef FEAT_AUTOCMD
2087 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002088 {
2089 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002090 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002091 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092#endif
2093 return retval;
2094}
2095
2096/*
2097 * Code to handle the argument list.
2098 */
2099
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002100static char_u *do_one_arg(char_u *str);
2101static int do_arglist(char_u *str, int what, int after);
2102static void alist_check_arg_idx(void);
2103static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002104#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002105static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002106#endif
2107#define AL_SET 1
2108#define AL_ADD 2
2109#define AL_DEL 3
2110
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002112 * Isolate one argument, taking backticks.
2113 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002114 * Return a pointer to the start of the next argument.
2115 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002116 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002117do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002118{
2119 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002120 int inbacktick;
2121
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122 inbacktick = FALSE;
2123 for (p = str; *str; ++str)
2124 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002125 /* When the backslash is used for escaping the special meaning of a
2126 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002127 if (rem_backslash(str))
2128 {
2129 *p++ = *str++;
2130 *p++ = *str;
2131 }
2132 else
2133 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002134 /* An item ends at a space not in backticks */
2135 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002137 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002138 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002139 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002140 }
2141 }
2142 str = skipwhite(str);
2143 *p = NUL;
2144
2145 return str;
2146}
2147
Bram Moolenaar86b68352004-12-27 21:59:20 +00002148/*
2149 * Separate the arguments in "str" and return a list of pointers in the
2150 * growarray "gap".
2151 */
2152 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002153get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002154{
2155 ga_init2(gap, (int)sizeof(char_u *), 20);
2156 while (*str != NUL)
2157 {
2158 if (ga_grow(gap, 1) == FAIL)
2159 {
2160 ga_clear(gap);
2161 return FAIL;
2162 }
2163 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2164
2165 /* Isolate one argument, change it in-place, put a NUL after it. */
2166 str = do_one_arg(str);
2167 }
2168 return OK;
2169}
2170
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002171#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002172/*
2173 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002174 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002175 * Return FAIL or OK.
2176 */
2177 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002178get_arglist_exp(
2179 char_u *str,
2180 int *fcountp,
2181 char_u ***fnamesp,
2182 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002183{
2184 garray_T ga;
2185 int i;
2186
2187 if (get_arglist(&ga, str) == FAIL)
2188 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002189 if (wig == TRUE)
2190 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2191 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2192 else
2193 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2194 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2195
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002196 ga_clear(&ga);
2197 return i;
2198}
2199#endif
2200
Bram Moolenaar071d4272004-06-13 20:20:40 +00002201#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2202/*
2203 * Redefine the argument list.
2204 */
2205 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002206set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002207{
2208 do_arglist(str, AL_SET, 0);
2209}
2210#endif
2211
2212/*
2213 * "what" == AL_SET: Redefine the argument list to 'str'.
2214 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2215 * "what" == AL_DEL: remove files in 'str' from the argument list.
2216 *
2217 * Return FAIL for failure, OK otherwise.
2218 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002219 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002220do_arglist(
2221 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002222 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002223 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002224{
2225 garray_T new_ga;
2226 int exp_count;
2227 char_u **exp_files;
2228 int i;
2229#ifdef FEAT_LISTCMDS
2230 char_u *p;
2231 int match;
2232#endif
2233
2234 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002235 * Set default argument for ":argadd" command.
2236 */
2237 if (what == AL_ADD && *str == NUL)
2238 {
2239 if (curbuf->b_ffname == NULL)
2240 return FAIL;
2241 str = curbuf->b_fname;
2242 }
2243
2244 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002245 * Collect all file name arguments in "new_ga".
2246 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002247 if (get_arglist(&new_ga, str) == FAIL)
2248 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249
2250#ifdef FEAT_LISTCMDS
2251 if (what == AL_DEL)
2252 {
2253 regmatch_T regmatch;
2254 int didone;
2255
2256 /*
2257 * Delete the items: use each item as a regexp and find a match in the
2258 * argument list.
2259 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002260 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2262 {
2263 p = ((char_u **)new_ga.ga_data)[i];
2264 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2265 if (p == NULL)
2266 break;
2267 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2268 if (regmatch.regprog == NULL)
2269 {
2270 vim_free(p);
2271 break;
2272 }
2273
2274 didone = FALSE;
2275 for (match = 0; match < ARGCOUNT; ++match)
2276 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2277 (colnr_T)0))
2278 {
2279 didone = TRUE;
2280 vim_free(ARGLIST[match].ae_fname);
2281 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2282 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2283 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284 if (curwin->w_arg_idx > match)
2285 --curwin->w_arg_idx;
2286 --match;
2287 }
2288
Bram Moolenaar473de612013-06-08 18:19:48 +02002289 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002290 vim_free(p);
2291 if (!didone)
2292 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2293 }
2294 ga_clear(&new_ga);
2295 }
2296 else
2297#endif
2298 {
2299 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2300 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2301 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002302 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303 {
2304 EMSG(_(e_nomatch));
2305 return FAIL;
2306 }
2307
2308#ifdef FEAT_LISTCMDS
2309 if (what == AL_ADD)
2310 {
2311 (void)alist_add_list(exp_count, exp_files, after);
2312 vim_free(exp_files);
2313 }
2314 else /* what == AL_SET */
2315#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002316 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 }
2318
2319 alist_check_arg_idx();
2320
2321 return OK;
2322}
2323
2324/*
2325 * Check the validity of the arg_idx for each other window.
2326 */
2327 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002328alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329{
2330#ifdef FEAT_WINDOWS
2331 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002332 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333
Bram Moolenaarf740b292006-02-16 22:11:02 +00002334 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002335 if (win->w_alist == curwin->w_alist)
2336 check_arg_idx(win);
2337#else
2338 check_arg_idx(curwin);
2339#endif
2340}
2341
2342/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002343 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002344 * index.
2345 */
2346 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002347editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002348{
2349 return !(win->w_arg_idx >= WARGCOUNT(win)
2350 || (win->w_buffer->b_fnum
2351 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2352 && (win->w_buffer->b_ffname == NULL
2353 || !(fullpathcmp(
2354 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2355 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2356}
2357
2358/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002359 * Check if window "win" is editing the w_arg_idx file in its argument list.
2360 */
2361 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002362check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002364 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002365 {
2366 /* We are not editing the current entry in the argument list.
2367 * Set "arg_had_last" if we are editing the last one. */
2368 win->w_arg_idx_invalid = TRUE;
2369 if (win->w_arg_idx != WARGCOUNT(win) - 1
2370 && arg_had_last == FALSE
2371#ifdef FEAT_WINDOWS
2372 && ALIST(win) == &global_alist
2373#endif
2374 && GARGCOUNT > 0
2375 && win->w_arg_idx < GARGCOUNT
2376 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2377 || (win->w_buffer->b_ffname != NULL
2378 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2379 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2380 arg_had_last = TRUE;
2381 }
2382 else
2383 {
2384 /* We are editing the current entry in the argument list.
2385 * Set "arg_had_last" if it's also the last one */
2386 win->w_arg_idx_invalid = FALSE;
2387 if (win->w_arg_idx == WARGCOUNT(win) - 1
2388#ifdef FEAT_WINDOWS
2389 && win->w_alist == &global_alist
2390#endif
2391 )
2392 arg_had_last = TRUE;
2393 }
2394}
2395
2396/*
2397 * ":args", ":argslocal" and ":argsglobal".
2398 */
2399 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002400ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002401{
2402 int i;
2403
2404 if (eap->cmdidx != CMD_args)
2405 {
2406#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2407 alist_unlink(ALIST(curwin));
2408 if (eap->cmdidx == CMD_argglobal)
2409 ALIST(curwin) = &global_alist;
2410 else /* eap->cmdidx == CMD_arglocal */
2411 alist_new();
2412#else
2413 ex_ni(eap);
2414 return;
2415#endif
2416 }
2417
2418 if (!ends_excmd(*eap->arg))
2419 {
2420 /*
2421 * ":args file ..": define new argument list, handle like ":next"
2422 * Also for ":argslocal file .." and ":argsglobal file ..".
2423 */
2424 ex_next(eap);
2425 }
2426 else
2427#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2428 if (eap->cmdidx == CMD_args)
2429#endif
2430 {
2431 /*
2432 * ":args": list arguments.
2433 */
2434 if (ARGCOUNT > 0)
2435 {
2436 /* Overwrite the command, for a short list there is no scrolling
2437 * required and no wait_return(). */
2438 gotocmdline(TRUE);
2439 for (i = 0; i < ARGCOUNT; ++i)
2440 {
2441 if (i == curwin->w_arg_idx)
2442 msg_putchar('[');
2443 msg_outtrans(alist_name(&ARGLIST[i]));
2444 if (i == curwin->w_arg_idx)
2445 msg_putchar(']');
2446 msg_putchar(' ');
2447 }
2448 }
2449 }
2450#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2451 else if (eap->cmdidx == CMD_arglocal)
2452 {
2453 garray_T *gap = &curwin->w_alist->al_ga;
2454
2455 /*
2456 * ":argslocal": make a local copy of the global argument list.
2457 */
2458 if (ga_grow(gap, GARGCOUNT) == OK)
2459 for (i = 0; i < GARGCOUNT; ++i)
2460 if (GARGLIST[i].ae_fname != NULL)
2461 {
2462 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2463 vim_strsave(GARGLIST[i].ae_fname);
2464 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2465 GARGLIST[i].ae_fnum;
2466 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467 }
2468 }
2469#endif
2470}
2471
2472/*
2473 * ":previous", ":sprevious", ":Next" and ":sNext".
2474 */
2475 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002476ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477{
2478 /* If past the last one already, go to the last one. */
2479 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2480 do_argfile(eap, ARGCOUNT - 1);
2481 else
2482 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2483}
2484
2485/*
2486 * ":rewind", ":first", ":sfirst" and ":srewind".
2487 */
2488 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002489ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002490{
2491 do_argfile(eap, 0);
2492}
2493
2494/*
2495 * ":last" and ":slast".
2496 */
2497 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002498ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499{
2500 do_argfile(eap, ARGCOUNT - 1);
2501}
2502
2503/*
2504 * ":argument" and ":sargument".
2505 */
2506 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002507ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002508{
2509 int i;
2510
2511 if (eap->addr_count > 0)
2512 i = eap->line2 - 1;
2513 else
2514 i = curwin->w_arg_idx;
2515 do_argfile(eap, i);
2516}
2517
2518/*
2519 * Edit file "argn" of the argument lists.
2520 */
2521 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002522do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002523{
2524 int other;
2525 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002526 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527
2528 if (argn < 0 || argn >= ARGCOUNT)
2529 {
2530 if (ARGCOUNT <= 1)
2531 EMSG(_("E163: There is only one file to edit"));
2532 else if (argn < 0)
2533 EMSG(_("E164: Cannot go before first file"));
2534 else
2535 EMSG(_("E165: Cannot go beyond last file"));
2536 }
2537 else
2538 {
2539 setpcmark();
2540#ifdef FEAT_GUI
2541 need_mouse_correct = TRUE;
2542#endif
2543
2544#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002545 /* split window or create new tab page first */
2546 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002547 {
2548 if (win_split(0, 0) == FAIL)
2549 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002550 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002551 }
2552 else
2553#endif
2554 {
2555 /*
2556 * if 'hidden' set, only check for changed file when re-editing
2557 * the same buffer
2558 */
2559 other = TRUE;
2560 if (P_HID(curbuf))
2561 {
2562 p = fix_fname(alist_name(&ARGLIST[argn]));
2563 other = otherfile(p);
2564 vim_free(p);
2565 }
2566 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002567 && check_changed(curbuf, CCGD_AW
2568 | (other ? 0 : CCGD_MULTWIN)
2569 | (eap->forceit ? CCGD_FORCEIT : 0)
2570 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 return;
2572 }
2573
2574 curwin->w_arg_idx = argn;
2575 if (argn == ARGCOUNT - 1
2576#ifdef FEAT_WINDOWS
2577 && curwin->w_alist == &global_alist
2578#endif
2579 )
2580 arg_had_last = TRUE;
2581
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002582 /* Edit the file; always use the last known line number.
2583 * When it fails (e.g. Abort for already edited file) restore the
2584 * argument index. */
2585 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002587 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2588 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002589 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002590 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002591 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592 setmark('\'');
2593 }
2594}
2595
2596/*
2597 * ":next", and commands that behave like it.
2598 */
2599 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002600ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002601{
2602 int i;
2603
2604 /*
2605 * check for changed buffer now, if this fails the argument list is not
2606 * redefined.
2607 */
2608 if ( P_HID(curbuf)
2609 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002610 || !check_changed(curbuf, CCGD_AW
2611 | (eap->forceit ? CCGD_FORCEIT : 0)
2612 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002613 {
2614 if (*eap->arg != NUL) /* redefine file list */
2615 {
2616 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2617 return;
2618 i = 0;
2619 }
2620 else
2621 i = curwin->w_arg_idx + (int)eap->line2;
2622 do_argfile(eap, i);
2623 }
2624}
2625
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002626#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627/*
2628 * ":argedit"
2629 */
2630 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002631ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632{
2633 int fnum;
2634 int i;
2635 char_u *s;
2636
2637 /* Add the argument to the buffer list and get the buffer number. */
2638 fnum = buflist_add(eap->arg, BLN_LISTED);
2639
2640 /* Check if this argument is already in the argument list. */
2641 for (i = 0; i < ARGCOUNT; ++i)
2642 if (ARGLIST[i].ae_fnum == fnum)
2643 break;
2644 if (i == ARGCOUNT)
2645 {
2646 /* Can't find it, add it to the argument list. */
2647 s = vim_strsave(eap->arg);
2648 if (s == NULL)
2649 return;
2650 i = alist_add_list(1, &s,
2651 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2652 if (i < 0)
2653 return;
2654 curwin->w_arg_idx = i;
2655 }
2656
2657 alist_check_arg_idx();
2658
2659 /* Edit the argument. */
2660 do_argfile(eap, i);
2661}
2662
2663/*
2664 * ":argadd"
2665 */
2666 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002667ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002668{
2669 do_arglist(eap->arg, AL_ADD,
2670 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2671#ifdef FEAT_TITLE
2672 maketitle();
2673#endif
2674}
2675
2676/*
2677 * ":argdelete"
2678 */
2679 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002680ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681{
2682 int i;
2683 int n;
2684
2685 if (eap->addr_count > 0)
2686 {
2687 /* ":1,4argdel": Delete all arguments in the range. */
2688 if (eap->line2 > ARGCOUNT)
2689 eap->line2 = ARGCOUNT;
2690 n = eap->line2 - eap->line1 + 1;
2691 if (*eap->arg != NUL || n <= 0)
2692 EMSG(_(e_invarg));
2693 else
2694 {
2695 for (i = eap->line1; i <= eap->line2; ++i)
2696 vim_free(ARGLIST[i - 1].ae_fname);
2697 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2698 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2699 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 if (curwin->w_arg_idx >= eap->line2)
2701 curwin->w_arg_idx -= n;
2702 else if (curwin->w_arg_idx > eap->line1)
2703 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002704 if (ARGCOUNT == 0)
2705 curwin->w_arg_idx = 0;
2706 else if (curwin->w_arg_idx >= ARGCOUNT)
2707 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 }
2709 }
2710 else if (*eap->arg == NUL)
2711 EMSG(_(e_argreq));
2712 else
2713 do_arglist(eap->arg, AL_DEL, 0);
2714#ifdef FEAT_TITLE
2715 maketitle();
2716#endif
2717}
2718
2719/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002720 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002721 */
2722 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002723ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724{
2725 int i;
2726#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002727 win_T *wp;
2728 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002730 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002731 int next_fnum = 0;
2732#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2733 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002735 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002736#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002737 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002738 int qf_idx;
2739#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002740
2741#ifndef FEAT_WINDOWS
2742 if (eap->cmdidx == CMD_windo)
2743 {
2744 ex_ni(eap);
2745 return;
2746 }
2747#endif
2748
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002749#ifndef FEAT_QUICKFIX
2750 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2751 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2752 {
2753 ex_ni(eap);
2754 return;
2755 }
2756#endif
2757
Bram Moolenaar071d4272004-06-13 20:20:40 +00002758#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002759 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002760 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2761 * great speed improvement. */
2762 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002763#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002764#ifdef FEAT_CLIPBOARD
2765 start_global_changes();
2766#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002767
2768 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002769 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002770 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002771 || !check_changed(curbuf, CCGD_AW
2772 | (eap->forceit ? CCGD_FORCEIT : 0)
2773 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002774 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002776 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002777#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002778 wp = firstwin;
2779 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002780#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002781 switch (eap->cmdidx)
2782 {
2783#ifdef FEAT_WINDOWS
2784 case CMD_windo:
2785 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2786 i++;
2787 break;
2788 case CMD_tabdo:
2789 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2790 i++;
2791 break;
2792#endif
2793 case CMD_argdo:
2794 i = eap->line1 - 1;
2795 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002796 default:
2797 break;
2798 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 /* set pcmark now */
2800 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002801 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002802 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002803 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002804 || !buf->b_p_bl); buf = buf->b_next)
2805 if (buf->b_fnum > eap->line2)
2806 {
2807 buf = NULL;
2808 break;
2809 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002810 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002811 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002812 }
2813#ifdef FEAT_QUICKFIX
2814 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2815 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2816 {
2817 qf_size = qf_get_size(eap);
2818 if (qf_size <= 0 || eap->line1 > qf_size)
2819 buf = NULL;
2820 else
2821 {
2822 ex_cc(eap);
2823
2824 buf = curbuf;
2825 i = eap->line1 - 1;
2826 if (eap->addr_count <= 0)
2827 /* default is all the quickfix/location list entries */
2828 eap->line2 = qf_size;
2829 }
2830 }
2831#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832 else
2833 setpcmark();
2834 listcmd_busy = TRUE; /* avoids setting pcmark below */
2835
Bram Moolenaare25bb902015-02-27 20:33:37 +01002836 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837 {
2838 if (eap->cmdidx == CMD_argdo)
2839 {
2840 /* go to argument "i" */
2841 if (i == ARGCOUNT)
2842 break;
2843 /* Don't call do_argfile() when already there, it will try
2844 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002845 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002846 {
2847 /* Clear 'shm' to avoid that the file message overwrites
2848 * any output from the command. */
2849 p_shm_save = vim_strsave(p_shm);
2850 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002852 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2853 vim_free(p_shm_save);
2854 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855 if (curwin->w_arg_idx != i)
2856 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857 }
2858#ifdef FEAT_WINDOWS
2859 else if (eap->cmdidx == CMD_windo)
2860 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002861 /* go to window "wp" */
2862 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002863 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002864 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002865 if (curwin != wp)
2866 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002867 wp = curwin->w_next;
2868 }
2869 else if (eap->cmdidx == CMD_tabdo)
2870 {
2871 /* go to window "tp" */
2872 if (!valid_tabpage(tp))
2873 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002874 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002875 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876 }
2877#endif
2878 else if (eap->cmdidx == CMD_bufdo)
2879 {
2880 /* Remember the number of the next listed buffer, in case
2881 * ":bwipe" is used or autocommands do something strange. */
2882 next_fnum = -1;
2883 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2884 if (buf->b_p_bl)
2885 {
2886 next_fnum = buf->b_fnum;
2887 break;
2888 }
2889 }
2890
Bram Moolenaara162bc52015-01-07 16:54:21 +01002891 ++i;
2892
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893 /* execute the command */
2894 do_cmdline(eap->arg, eap->getline, eap->cookie,
2895 DOCMD_VERBOSE + DOCMD_NOWAIT);
2896
2897 if (eap->cmdidx == CMD_bufdo)
2898 {
2899 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002900 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901 break;
2902 /* Check if the buffer still exists. */
2903 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2904 if (buf->b_fnum == next_fnum)
2905 break;
2906 if (buf == NULL)
2907 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002908
2909 /* Go to the next buffer. Clear 'shm' to avoid that the file
2910 * message overwrites any output from the command. */
2911 p_shm_save = vim_strsave(p_shm);
2912 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002914 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2915 vim_free(p_shm_save);
2916
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002917 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002918 if (curbuf->b_fnum != next_fnum)
2919 break;
2920 }
2921
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002922#ifdef FEAT_QUICKFIX
2923 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2924 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2925 {
2926 if (i >= qf_size || i >= eap->line2)
2927 break;
2928
2929 qf_idx = qf_get_cur_idx(eap);
2930
2931 ex_cnext(eap);
2932
2933 /* If jumping to the next quickfix entry fails, quit here */
2934 if (qf_get_cur_idx(eap) == qf_idx)
2935 break;
2936 }
2937#endif
2938
Bram Moolenaar071d4272004-06-13 20:20:40 +00002939 if (eap->cmdidx == CMD_windo)
2940 {
2941 validate_cursor(); /* cursor may have moved */
2942#ifdef FEAT_SCROLLBIND
2943 /* required when 'scrollbind' has been set */
2944 if (curwin->w_p_scb)
2945 do_check_scrollbind(TRUE);
2946#endif
2947 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002948
2949#ifdef FEAT_WINDOWS
2950 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2951 if (i+1 > eap->line2)
2952 break;
2953#endif
2954 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2955 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956 }
2957 listcmd_busy = FALSE;
2958 }
2959
2960#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002961 if (save_ei != NULL)
2962 {
2963 au_event_restore(save_ei);
2964 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2965 curbuf->b_fname, TRUE, curbuf);
2966 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002968#ifdef FEAT_CLIPBOARD
2969 end_global_changes();
2970#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971}
2972
2973/*
2974 * Add files[count] to the arglist of the current window after arg "after".
2975 * The file names in files[count] must have been allocated and are taken over.
2976 * Files[] itself is not taken over.
2977 * Returns index of first added argument. Returns -1 when failed (out of mem).
2978 */
2979 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002980alist_add_list(
2981 int count,
2982 char_u **files,
2983 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002984{
2985 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002986 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987
2988 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2989 {
2990 if (after < 0)
2991 after = 0;
2992 if (after > ARGCOUNT)
2993 after = ARGCOUNT;
2994 if (after < ARGCOUNT)
2995 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2996 (ARGCOUNT - after) * sizeof(aentry_T));
2997 for (i = 0; i < count; ++i)
2998 {
2999 ARGLIST[after + i].ae_fname = files[i];
3000 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
3001 }
3002 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003003 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3004 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003005 return after;
3006 }
3007
3008 for (i = 0; i < count; ++i)
3009 vim_free(files[i]);
3010 return -1;
3011}
3012
3013#endif /* FEAT_LISTCMDS */
3014
3015#ifdef FEAT_EVAL
3016/*
3017 * ":compiler[!] {name}"
3018 */
3019 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003020ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021{
3022 char_u *buf;
3023 char_u *old_cur_comp = NULL;
3024 char_u *p;
3025
3026 if (*eap->arg == NUL)
3027 {
3028 /* List all compiler scripts. */
3029 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3030 /* ) keep the indenter happy... */
3031 }
3032 else
3033 {
3034 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3035 if (buf != NULL)
3036 {
3037 if (eap->forceit)
3038 {
3039 /* ":compiler! {name}" sets global options */
3040 do_cmdline_cmd((char_u *)
3041 "command -nargs=* CompilerSet set <args>");
3042 }
3043 else
3044 {
3045 /* ":compiler! {name}" sets local options.
3046 * To remain backwards compatible "current_compiler" is always
3047 * used. A user's compiler plugin may set it, the distributed
3048 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003049 * "b:current_compiler" and restore "current_compiler".
3050 * Explicitly prepend "g:" to make it work in a function. */
3051 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052 if (old_cur_comp != NULL)
3053 old_cur_comp = vim_strsave(old_cur_comp);
3054 do_cmdline_cmd((char_u *)
3055 "command -nargs=* CompilerSet setlocal <args>");
3056 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003057 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003058 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059
3060 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003061 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3063 vim_free(buf);
3064
3065 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3066
3067 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003068 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069 if (p != NULL)
3070 set_internal_string_var((char_u *)"b:current_compiler", p);
3071
3072 /* Restore "current_compiler" for ":compiler {name}". */
3073 if (!eap->forceit)
3074 {
3075 if (old_cur_comp != NULL)
3076 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003077 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003078 old_cur_comp);
3079 vim_free(old_cur_comp);
3080 }
3081 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003082 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083 }
3084 }
3085 }
3086}
3087#endif
3088
3089/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003090 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003091 */
3092 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003093ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003095 char_u *arg = eap->arg;
3096 char_u *p = skiptowhite(arg);
3097 int len = (int)(p - arg);
3098 int flags = eap->forceit ? DIP_ALL : 0;
3099
3100 if (STRNCMP(arg, "START", len) == 0)
3101 {
3102 flags += DIP_START + DIP_NORTP;
3103 arg = skipwhite(arg + len);
3104 }
3105 else if (STRNCMP(arg, "OPT", len) == 0)
3106 {
3107 flags += DIP_OPT + DIP_NORTP;
3108 arg = skipwhite(arg + len);
3109 }
3110 else if (STRNCMP(arg, "PACK", len) == 0)
3111 {
3112 flags += DIP_START + DIP_OPT + DIP_NORTP;
3113 arg = skipwhite(arg + len);
3114 }
3115 else if (STRNCMP(arg, "ALL", len) == 0)
3116 {
3117 flags += DIP_START + DIP_OPT;
3118 arg = skipwhite(arg + len);
3119 }
3120
3121 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003122}
3123
Bram Moolenaar071d4272004-06-13 20:20:40 +00003124 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003125source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003127 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128}
3129
3130/*
3131 * Source the file "name" from all directories in 'runtimepath'.
3132 * "name" can contain wildcards.
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003133 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
Bram Moolenaar91715872016-03-03 17:13:03 +01003134 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 * return FAIL when no file could be sourced, OK otherwise.
3136 */
3137 int
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003138source_runtime(char_u *name, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139{
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003140 return do_in_runtimepath(name, flags, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141}
3142
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003143/*
3144 * Find the file "name" in all directories in "path" and invoke
3145 * "callback(fname, cookie)".
3146 * "name" can contain wildcards.
3147 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3148 * When "flags" has DIP_DIR: find directories instead of files.
3149 * When "flags" has DIP_ERR: give an error message if there is no match.
3150 *
3151 * return FAIL when no file could be sourced, OK otherwise.
3152 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003153 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003154do_in_path(
3155 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003156 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003157 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003158 void (*callback)(char_u *fname, void *ck),
3159 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003160{
3161 char_u *rtp;
3162 char_u *np;
3163 char_u *buf;
3164 char_u *rtp_copy;
3165 char_u *tail;
3166 int num_files;
3167 char_u **files;
3168 int i;
3169 int did_one = FALSE;
3170#ifdef AMIGA
3171 struct Process *proc = (struct Process *)FindTask(0L);
3172 APTR save_winptr = proc->pr_WindowPtr;
3173
3174 /* Avoid a requester here for a volume that doesn't exist. */
3175 proc->pr_WindowPtr = (APTR)-1L;
3176#endif
3177
3178 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3179 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003180 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003181 buf = alloc(MAXPATHL);
3182 if (buf != NULL && rtp_copy != NULL)
3183 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003184 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003185 {
3186 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003187 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003188 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003189 verbose_leave();
3190 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003191
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192 /* Loop over all entries in 'runtimepath'. */
3193 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003194 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003195 {
3196 /* Copy the path from 'runtimepath' to buf[]. */
3197 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003198 if (name == NULL)
3199 {
3200 (*callback)(buf, (void *) &cookie);
3201 if (!did_one)
3202 did_one = (cookie == NULL);
3203 }
3204 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003205 {
3206 add_pathsep(buf);
3207 tail = buf + STRLEN(buf);
3208
3209 /* Loop over all patterns in "name" */
3210 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003211 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 {
3213 /* Append the pattern from "name" to buf[]. */
3214 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3215 "\t ");
3216
3217 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003218 {
3219 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003220 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003221 verbose_leave();
3222 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223
3224 /* Expand wildcards, invoke the callback for each match. */
3225 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003226 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 {
3228 for (i = 0; i < num_files; ++i)
3229 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003230 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003232 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003233 break;
3234 }
3235 FreeWild(num_files, files);
3236 }
3237 }
3238 }
3239 }
3240 }
3241 vim_free(buf);
3242 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003243 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003244 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003245 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3246
3247 if (flags & DIP_ERR)
3248 EMSG3(_(e_dirnotf), basepath, name);
3249 else if (p_verbose > 0)
3250 {
3251 verbose_enter();
3252 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3253 verbose_leave();
3254 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003255 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256
3257#ifdef AMIGA
3258 proc->pr_WindowPtr = save_winptr;
3259#endif
3260
3261 return did_one ? OK : FAIL;
3262}
3263
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003264/*
3265 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3266 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003267 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3268 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003269 * Returns OK when at least one match found, FAIL otherwise.
3270 *
3271 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3272 * passed by reference in this case, setting it to NULL indicates that callback
3273 * has done its job.
3274 */
3275 int
3276do_in_runtimepath(
3277 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003278 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003279 void (*callback)(char_u *fname, void *ck),
3280 void *cookie)
3281{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003282 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003283 char_u *s;
3284 int len;
3285 char *start_dir = "pack/*/start/*/%s";
3286 char *opt_dir = "pack/*/opt/*/%s";
3287
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003288 if ((flags & DIP_NORTP) == 0)
3289 done = do_in_path(p_rtp, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003290
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003291 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003292 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003293 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003294 s = alloc(len);
3295 if (s == NULL)
3296 return FAIL;
3297 vim_snprintf((char *)s, len, start_dir, name);
3298 done = do_in_path(p_pp, s, flags, callback, cookie);
3299 vim_free(s);
3300 }
3301
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003302 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003303 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003304 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003305 s = alloc(len);
3306 if (s == NULL)
3307 return FAIL;
3308 vim_snprintf((char *)s, len, opt_dir, name);
3309 done = do_in_path(p_pp, s, flags, callback, cookie);
3310 vim_free(s);
3311 }
3312
3313 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003314}
3315
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003316/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003317 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003318 */
3319 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003320source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003321{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003322 int num_files;
3323 char_u **files;
3324 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003325
Bram Moolenaarf3654822016-03-04 22:12:23 +01003326 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003327 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003328 for (i = 0; i < num_files; ++i)
3329 (void)do_source(files[i], FALSE, DOSO_NONE);
3330 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003331 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003332}
3333
Bram Moolenaar49b27322016-04-05 21:13:00 +02003334/* used for "cookie" of add_pack_plugin() */
3335static int APP_ADD_DIR;
3336static int APP_LOAD;
3337static int APP_BOTH;
3338
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003339 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003340add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003341{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003342 char_u *p4, *p3, *p2, *p1, *p;
3343 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003344 int c;
3345 char_u *new_rtp;
3346 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003347 size_t oldlen;
3348 size_t addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003349 char_u *afterdir;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003350 size_t afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003351 char_u *ffname = fix_fname(fname);
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003352 int fname_len;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003353
Bram Moolenaar91715872016-03-03 17:13:03 +01003354 if (ffname == NULL)
3355 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003356 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003357 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003358 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003359 p4 = p3 = p2 = p1 = get_past_head(ffname);
3360 for (p = p1; *p; mb_ptr_adv(p))
3361 if (vim_ispathsep_nocolon(*p))
3362 {
3363 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3364 }
3365
3366 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003367 * rtp/pack/name/start/name
3368 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003369 *
3370 * find the part up to "pack" in 'runtimepath' */
3371 c = *p4;
3372 *p4 = NUL;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003373
3374 /* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3375 fname_len = STRLEN(ffname);
3376 insp = p_rtp;
3377 for (;;)
3378 {
3379 if (vim_fnamencmp(insp, ffname, fname_len) == 0)
3380 break;
3381 insp = vim_strchr(insp, ',');
3382 if (insp == NULL)
3383 break;
3384 ++insp;
3385 }
3386
Bram Moolenaarf3654822016-03-04 22:12:23 +01003387 if (insp == NULL)
3388 /* not found, append at the end */
3389 insp = p_rtp + STRLEN(p_rtp);
3390 else
3391 {
3392 /* append after the matching directory. */
3393 insp += STRLEN(ffname);
3394 while (*insp != NUL && *insp != ',')
3395 ++insp;
3396 }
3397 *p4 = c;
3398
Bram Moolenaara5702442016-05-24 19:37:29 +02003399 /* check if rtp/pack/name/start/name/after exists */
3400 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3401 if (afterdir != NULL && mch_isdir(afterdir))
3402 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3403
Bram Moolenaarb0550662016-05-31 21:37:36 +02003404 oldlen = STRLEN(p_rtp);
3405 addlen = STRLEN(ffname) + 1; /* add one for comma */
3406 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003407 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003408 goto theend;
3409 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003410 mch_memmove(new_rtp, p_rtp, keep);
3411 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003412 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003413 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003414 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003415 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003416 if (afterlen > 0)
3417 {
3418 STRCAT(new_rtp, ",");
3419 STRCAT(new_rtp, afterdir);
3420 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003421 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3422 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003423 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003424 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003425
Bram Moolenaar49b27322016-04-05 21:13:00 +02003426 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003427 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003428 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003429 static char *ftpat = "%s/ftdetect/*.vim";
3430 int len;
3431 char_u *pat;
3432
3433 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3434 pat = alloc(len);
3435 if (pat == NULL)
3436 goto theend;
3437 vim_snprintf((char *)pat, len, plugpat, ffname);
3438 source_all_matches(pat);
3439
3440#ifdef FEAT_AUTOCMD
3441 {
3442 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3443
3444 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3445 * found when it loads. */
3446 if (cmd != NULL && eval_to_number(cmd) > 0)
3447 {
3448 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3449 vim_snprintf((char *)pat, len, ftpat, ffname);
3450 source_all_matches(pat);
3451 do_cmdline_cmd((char_u *)"augroup END");
3452 }
3453 vim_free(cmd);
3454 }
3455#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003456 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003457 }
3458
3459theend:
3460 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003461}
3462
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003463static int did_source_packages = FALSE;
3464
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003465/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003466 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003467 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003468 */
3469 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003470ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003471{
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003472 if (!did_source_packages || (eap != NULL && eap->forceit))
3473 {
3474 did_source_packages = TRUE;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003475
3476 /* First do a round to add all directories to 'runtimepath', then load
3477 * the plugins. This allows for plugins to use an autoload directory
3478 * of another plugin. */
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003479 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003480 add_pack_plugin, &APP_ADD_DIR);
3481 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3482 add_pack_plugin, &APP_LOAD);
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003483 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003484}
3485
3486/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003487 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003488 */
3489 void
3490ex_packadd(exarg_T *eap)
3491{
3492 static char *plugpat = "pack/*/opt/%s";
3493 int len;
3494 char *pat;
3495
3496 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3497 pat = (char *)alloc(len);
3498 if (pat == NULL)
3499 return;
3500 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003501 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003502 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003503 vim_free(pat);
3504}
3505
Bram Moolenaar071d4272004-06-13 20:20:40 +00003506#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3507/*
3508 * ":options"
3509 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003511ex_options(
3512 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003513{
3514 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3515}
3516#endif
3517
3518/*
3519 * ":source {fname}"
3520 */
3521 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003522ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003523{
3524#ifdef FEAT_BROWSE
3525 if (cmdmod.browse)
3526 {
3527 char_u *fname = NULL;
3528
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003529 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003530 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3531 if (fname != NULL)
3532 {
3533 cmd_source(fname, eap);
3534 vim_free(fname);
3535 }
3536 }
3537 else
3538#endif
3539 cmd_source(eap->arg, eap);
3540}
3541
3542 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003543cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544{
3545 if (*fname == NUL)
3546 EMSG(_(e_argreq));
3547
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003549 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003550 * Need to execute the commands directly. This is required at least
3551 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552 * - ":g" command busy
3553 * - after ":argdo", ":windo" or ":bufdo"
3554 * - another command follows
3555 * - inside a loop
3556 */
3557 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3558#ifdef FEAT_EVAL
3559 || eap->cstack->cs_idx >= 0
3560#endif
3561 );
3562
3563 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003564 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565 EMSG2(_(e_notopen), fname);
3566}
3567
3568/*
3569 * ":source" and associated commands.
3570 */
3571/*
3572 * Structure used to store info for each sourced file.
3573 * It is shared between do_source() and getsourceline().
3574 * This is required, because it needs to be handed to do_cmdline() and
3575 * sourcing can be done recursively.
3576 */
3577struct source_cookie
3578{
3579 FILE *fp; /* opened file for sourcing */
3580 char_u *nextline; /* if not NULL: line that was read ahead */
3581 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003582#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003583 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3584 int error; /* TRUE if LF found after CR-LF */
3585#endif
3586#ifdef FEAT_EVAL
3587 linenr_T breakpoint; /* next line with breakpoint or zero */
3588 char_u *fname; /* name of sourced file */
3589 int dbg_tick; /* debug_tick when breakpoint was set */
3590 int level; /* top nesting level of sourced file */
3591#endif
3592#ifdef FEAT_MBYTE
3593 vimconv_T conv; /* type of conversion */
3594#endif
3595};
3596
3597#ifdef FEAT_EVAL
3598/*
3599 * Return the address holding the next breakpoint line for a source cookie.
3600 */
3601 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003602source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003603{
3604 return &((struct source_cookie *)cookie)->breakpoint;
3605}
3606
3607/*
3608 * Return the address holding the debug tick for a source cookie.
3609 */
3610 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003611source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612{
3613 return &((struct source_cookie *)cookie)->dbg_tick;
3614}
3615
3616/*
3617 * Return the nesting level for a source cookie.
3618 */
3619 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003620source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003621{
3622 return ((struct source_cookie *)cookie)->level;
3623}
3624#endif
3625
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003626static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003628#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3629# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003630static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003631
3632/*
3633 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003634 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003635 */
3636 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003637fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003638{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003639# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003640 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3641# else
3642 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003643# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003644
3645 if (fd_tmp == -1)
3646 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003647
3648# ifdef HAVE_FD_CLOEXEC
3649 {
3650 int fdflags = fcntl(fd_tmp, F_GETFD);
3651 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003652 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003653 }
3654# endif
3655
Bram Moolenaar071d4272004-06-13 20:20:40 +00003656 return fdopen(fd_tmp, READBIN);
3657}
3658#endif
3659
3660
3661/*
3662 * do_source: Read the file "fname" and execute its lines as EX commands.
3663 *
3664 * This function may be called recursively!
3665 *
3666 * return FAIL if file could not be opened, OK otherwise
3667 */
3668 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003669do_source(
3670 char_u *fname,
3671 int check_other, /* check for .vimrc and _vimrc */
3672 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673{
3674 struct source_cookie cookie;
3675 char_u *save_sourcing_name;
3676 linenr_T save_sourcing_lnum;
3677 char_u *p;
3678 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003679 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680 int retval = FAIL;
3681#ifdef FEAT_EVAL
3682 scid_T save_current_SID;
3683 static scid_T last_current_SID = 0;
3684 void *save_funccalp;
3685 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003686 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003687# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003688 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 int stat_ok;
3690# endif
3691#endif
3692#ifdef STARTUPTIME
3693 struct timeval tv_rel;
3694 struct timeval tv_start;
3695#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003696#ifdef FEAT_PROFILE
3697 proftime_T wait_start;
3698#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003699
Bram Moolenaar071d4272004-06-13 20:20:40 +00003700 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701 if (p == NULL)
3702 return retval;
3703 fname_exp = fix_fname(p);
3704 vim_free(p);
3705 if (fname_exp == NULL)
3706 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 if (mch_isdir(fname_exp))
3708 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003709 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710 goto theend;
3711 }
3712
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003713#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003714 /* Apply SourceCmd autocommands, they should get the file and source it. */
3715 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3716 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3717 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003718 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003719# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003720 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003721# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003722 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003723# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003724 goto theend;
3725 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003726
3727 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003728 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3729#endif
3730
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003731#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3733#else
3734 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3735#endif
3736 if (cookie.fp == NULL && check_other)
3737 {
3738 /*
3739 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3740 * and ".exrc" by "_exrc" or vice versa.
3741 */
3742 p = gettail(fname_exp);
3743 if ((*p == '.' || *p == '_')
3744 && (STRICMP(p + 1, "vimrc") == 0
3745 || STRICMP(p + 1, "gvimrc") == 0
3746 || STRICMP(p + 1, "exrc") == 0))
3747 {
3748 if (*p == '_')
3749 *p = '.';
3750 else
3751 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003752#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3754#else
3755 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3756#endif
3757 }
3758 }
3759
3760 if (cookie.fp == NULL)
3761 {
3762 if (p_verbose > 0)
3763 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003764 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003766 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003767 else
3768 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003769 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003770 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771 }
3772 goto theend;
3773 }
3774
3775 /*
3776 * The file exists.
3777 * - In verbose mode, give a message.
3778 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3779 */
3780 if (p_verbose > 1)
3781 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003782 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003784 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003785 else
3786 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003787 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003788 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003790 if (is_vimrc == DOSO_VIMRC)
3791 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3792 else if (is_vimrc == DOSO_GVIMRC)
3793 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794
3795#ifdef USE_CRNL
3796 /* If no automatic file format: Set default to CR-NL. */
3797 if (*p_ffs == NUL)
3798 cookie.fileformat = EOL_DOS;
3799 else
3800 cookie.fileformat = EOL_UNKNOWN;
3801 cookie.error = FALSE;
3802#endif
3803
3804#ifdef USE_CR
3805 /* If no automatic file format: Set default to CR. */
3806 if (*p_ffs == NUL)
3807 cookie.fileformat = EOL_MAC;
3808 else
3809 cookie.fileformat = EOL_UNKNOWN;
3810 cookie.error = FALSE;
3811#endif
3812
3813 cookie.nextline = NULL;
3814 cookie.finished = FALSE;
3815
3816#ifdef FEAT_EVAL
3817 /*
3818 * Check if this script has a breakpoint.
3819 */
3820 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3821 cookie.fname = fname_exp;
3822 cookie.dbg_tick = debug_tick;
3823
3824 cookie.level = ex_nesting_level;
3825#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826
3827 /*
3828 * Keep the sourcing name/lnum, for recursive calls.
3829 */
3830 save_sourcing_name = sourcing_name;
3831 sourcing_name = fname_exp;
3832 save_sourcing_lnum = sourcing_lnum;
3833 sourcing_lnum = 0;
3834
Bram Moolenaar73881402009-02-04 16:50:47 +00003835#ifdef FEAT_MBYTE
3836 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3837
3838 /* Read the first line so we can check for a UTF-8 BOM. */
3839 firstline = getsourceline(0, (void *)&cookie, 0);
3840 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3841 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3842 {
3843 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3844 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3845 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003846 if (p == NULL)
3847 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003848 if (p != NULL)
3849 {
3850 vim_free(firstline);
3851 firstline = p;
3852 }
3853 }
3854#endif
3855
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003857 if (time_fd != NULL)
3858 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003859#endif
3860
3861#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003862# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003863 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003864 prof_child_enter(&wait_start); /* entering a child now */
3865# endif
3866
3867 /* Don't use local function variables, if called from a function.
3868 * Also starts profiling timer for nested script. */
3869 save_funccalp = save_funccal();
3870
Bram Moolenaar071d4272004-06-13 20:20:40 +00003871 /*
3872 * Check if this script was sourced before to finds its SID.
3873 * If it's new, generate a new SID.
3874 */
3875 save_current_SID = current_SID;
3876# ifdef UNIX
3877 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3878# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003879 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3880 {
3881 si = &SCRIPT_ITEM(current_SID);
3882 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003883 && (
3884# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003885 /* Compare dev/ino when possible, it catches symbolic
3886 * links. Also compare file names, the inode may change
3887 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003888 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003889 && (si->sn_dev == st.st_dev
3890 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003891# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003892 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003894 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895 if (current_SID == 0)
3896 {
3897 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003898 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3899 == FAIL)
3900 goto almosttheend;
3901 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003902 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003903 ++script_items.ga_len;
3904 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3905# ifdef FEAT_PROFILE
3906 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003907# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003909 si = &SCRIPT_ITEM(current_SID);
3910 si->sn_name = fname_exp;
3911 fname_exp = NULL;
3912# ifdef UNIX
3913 if (stat_ok)
3914 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003915 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003916 si->sn_dev = st.st_dev;
3917 si->sn_ino = st.st_ino;
3918 }
3919 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003920 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003921# endif
3922
Bram Moolenaar071d4272004-06-13 20:20:40 +00003923 /* Allocate the local script variables to use for this script. */
3924 new_script_vars(current_SID);
3925 }
3926
Bram Moolenaar05159a02005-02-26 23:04:13 +00003927# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003928 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003929 {
3930 int forceit;
3931
3932 /* Check if we do profiling for this script. */
3933 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3934 {
3935 script_do_profile(si);
3936 si->sn_pr_force = forceit;
3937 }
3938 if (si->sn_prof_on)
3939 {
3940 ++si->sn_pr_count;
3941 profile_start(&si->sn_pr_start);
3942 profile_zero(&si->sn_pr_children);
3943 }
3944 }
3945# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003946#endif
3947
3948 /*
3949 * Call do_cmdline, which will call getsourceline() to get the lines.
3950 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003951 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003952 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003953 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003954
3955#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003956 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003957 {
3958 /* Get "si" again, "script_items" may have been reallocated. */
3959 si = &SCRIPT_ITEM(current_SID);
3960 if (si->sn_prof_on)
3961 {
3962 profile_end(&si->sn_pr_start);
3963 profile_sub_wait(&wait_start, &si->sn_pr_start);
3964 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003965 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3966 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003967 }
3968 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003969#endif
3970
3971 if (got_int)
3972 EMSG(_(e_interr));
3973 sourcing_name = save_sourcing_name;
3974 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003975 if (p_verbose > 1)
3976 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003977 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003978 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003979 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003980 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003981 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003982 }
3983#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003984 if (time_fd != NULL)
3985 {
3986 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3987 time_msg((char *)IObuff, &tv_start);
3988 time_pop(&tv_rel);
3989 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003990#endif
3991
3992#ifdef FEAT_EVAL
3993 /*
3994 * After a "finish" in debug mode, need to break at first command of next
3995 * sourced file.
3996 */
3997 if (save_debug_break_level > ex_nesting_level
3998 && debug_break_level == ex_nesting_level)
3999 ++debug_break_level;
4000#endif
4001
Bram Moolenaar05159a02005-02-26 23:04:13 +00004002#ifdef FEAT_EVAL
4003almosttheend:
4004 current_SID = save_current_SID;
4005 restore_funccal(save_funccalp);
4006# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004007 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004008 prof_child_exit(&wait_start); /* leaving a child now */
4009# endif
4010#endif
4011 fclose(cookie.fp);
4012 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004013 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004014#ifdef FEAT_MBYTE
4015 convert_setup(&cookie.conv, NULL, NULL);
4016#endif
4017
Bram Moolenaar071d4272004-06-13 20:20:40 +00004018theend:
4019 vim_free(fname_exp);
4020 return retval;
4021}
4022
4023#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004024
Bram Moolenaar071d4272004-06-13 20:20:40 +00004025/*
4026 * ":scriptnames"
4027 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004029ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004030{
4031 int i;
4032
Bram Moolenaar05159a02005-02-26 23:04:13 +00004033 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4034 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004035 {
4036 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4037 NameBuff, MAXPATHL, TRUE);
4038 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004039 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040}
4041
4042# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4043/*
4044 * Fix slashes in the list of script names for 'shellslash'.
4045 */
4046 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004047scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004048{
4049 int i;
4050
Bram Moolenaar05159a02005-02-26 23:04:13 +00004051 for (i = 1; i <= script_items.ga_len; ++i)
4052 if (SCRIPT_ITEM(i).sn_name != NULL)
4053 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054}
4055# endif
4056
4057/*
4058 * Get a pointer to a script name. Used for ":verbose set".
4059 */
4060 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004061get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004062{
4063 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004064 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004065 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004066 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004067 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004068 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004069 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004070 return (char_u *)_("environment variable");
4071 if (id == SID_ERROR)
4072 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004073 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004075
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004076# if defined(EXITFREE) || defined(PROTO)
4077 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004078free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004079{
4080 int i;
4081
4082 for (i = script_items.ga_len; i > 0; --i)
4083 vim_free(SCRIPT_ITEM(i).sn_name);
4084 ga_clear(&script_items);
4085}
4086# endif
4087
Bram Moolenaar071d4272004-06-13 20:20:40 +00004088#endif
4089
4090#if defined(USE_CR) || defined(PROTO)
4091
4092# if defined(__MSL__) && (__MSL__ >= 22)
4093/*
4094 * Newer version of the Metrowerks library handle DOS and UNIX files
4095 * without help.
4096 * Test with earlier versions, MSL 2.2 is the library supplied with
4097 * Codewarrior Pro 2.
4098 */
4099 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004100fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101{
4102 return fgets(s, n, stream);
4103}
4104# else
4105/*
4106 * Version of fgets() which also works for lines ending in a <CR> only
4107 * (Macintosh format).
4108 * For older versions of the Metrowerks library.
4109 * At least CodeWarrior 9 needed this code.
4110 */
4111 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004112fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113{
4114 int c = 0;
4115 int char_read = 0;
4116
4117 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4118 {
4119 c = fgetc(stream);
4120 s[char_read++] = c;
4121 /* If the file is in DOS format, we need to skip a NL after a CR. I
4122 * thought it was the other way around, but this appears to work... */
4123 if (c == '\n')
4124 {
4125 c = fgetc(stream);
4126 if (c != '\r')
4127 ungetc(c, stream);
4128 }
4129 }
4130
4131 s[char_read] = 0;
4132 if (char_read == 0)
4133 return NULL;
4134
4135 if (feof(stream) && char_read == 1)
4136 return NULL;
4137
4138 return s;
4139}
4140# endif
4141#endif
4142
4143/*
4144 * Get one full line from a sourced file.
4145 * Called by do_cmdline() when it's called from do_source().
4146 *
4147 * Return a pointer to the line in allocated memory.
4148 * Return NULL for end-of-file or some error.
4149 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004151getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004152{
4153 struct source_cookie *sp = (struct source_cookie *)cookie;
4154 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004155 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004156
4157#ifdef FEAT_EVAL
4158 /* If breakpoints have been added/deleted need to check for it. */
4159 if (sp->dbg_tick < debug_tick)
4160 {
4161 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4162 sp->dbg_tick = debug_tick;
4163 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004164# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004165 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004166 script_line_end();
4167# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168#endif
4169 /*
4170 * Get current line. If there is a read-ahead line, use it, otherwise get
4171 * one now.
4172 */
4173 if (sp->finished)
4174 line = NULL;
4175 else if (sp->nextline == NULL)
4176 line = get_one_sourceline(sp);
4177 else
4178 {
4179 line = sp->nextline;
4180 sp->nextline = NULL;
4181 ++sourcing_lnum;
4182 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004183#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004184 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004185 script_line_start();
4186#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187
4188 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4189 * contain the 'C' flag. */
4190 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4191 {
4192 /* compensate for the one line read-ahead */
4193 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004194
4195 /* Get the next line and concatenate it when it starts with a
4196 * backslash. We always need to read the next line, keep it in
4197 * sp->nextline. */
4198 sp->nextline = get_one_sourceline(sp);
4199 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004200 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004201 garray_T ga;
4202
Bram Moolenaarb549a732012-02-22 18:29:33 +01004203 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004204 ga_concat(&ga, line);
4205 ga_concat(&ga, p + 1);
4206 for (;;)
4207 {
4208 vim_free(sp->nextline);
4209 sp->nextline = get_one_sourceline(sp);
4210 if (sp->nextline == NULL)
4211 break;
4212 p = skipwhite(sp->nextline);
4213 if (*p != '\\')
4214 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004215 /* Adjust the growsize to the current length to speed up
4216 * concatenating many lines. */
4217 if (ga.ga_len > 400)
4218 {
4219 if (ga.ga_len > 8000)
4220 ga.ga_growsize = 8000;
4221 else
4222 ga.ga_growsize = ga.ga_len;
4223 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004224 ga_concat(&ga, p + 1);
4225 }
4226 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004228 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229 }
4230 }
4231
4232#ifdef FEAT_MBYTE
4233 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4234 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004235 char_u *s;
4236
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237 /* Convert the encoding of the script line. */
4238 s = string_convert(&sp->conv, line, NULL);
4239 if (s != NULL)
4240 {
4241 vim_free(line);
4242 line = s;
4243 }
4244 }
4245#endif
4246
4247#ifdef FEAT_EVAL
4248 /* Did we encounter a breakpoint? */
4249 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4250 {
4251 dbg_breakpoint(sp->fname, sourcing_lnum);
4252 /* Find next breakpoint. */
4253 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4254 sp->dbg_tick = debug_tick;
4255 }
4256#endif
4257
4258 return line;
4259}
4260
4261 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004262get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263{
4264 garray_T ga;
4265 int len;
4266 int c;
4267 char_u *buf;
4268#ifdef USE_CRNL
4269 int has_cr; /* CR-LF found */
4270#endif
4271#ifdef USE_CR
4272 char_u *scan;
4273#endif
4274 int have_read = FALSE;
4275
4276 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004277 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278
4279 /*
4280 * Loop until there is a finished line (or end-of-file).
4281 */
4282 sourcing_lnum++;
4283 for (;;)
4284 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004285 /* make room to read at least 120 (more) characters */
4286 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287 break;
4288 buf = (char_u *)ga.ga_data;
4289
4290#ifdef USE_CR
4291 if (sp->fileformat == EOL_MAC)
4292 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004293 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4294 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004295 break;
4296 }
4297 else
4298#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004299 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4300 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004302 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303#ifdef USE_CRNL
4304 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4305 * CTRL-Z by its own, or after a NL. */
4306 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4307 && sp->fileformat == EOL_DOS
4308 && buf[len - 1] == Ctrl_Z)
4309 {
4310 buf[len - 1] = NUL;
4311 break;
4312 }
4313#endif
4314
4315#ifdef USE_CR
4316 /* If the read doesn't stop on a new line, and there's
4317 * some CR then we assume a Mac format */
4318 if (sp->fileformat == EOL_UNKNOWN)
4319 {
4320 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4321 sp->fileformat = EOL_MAC;
4322 else
4323 sp->fileformat = EOL_UNIX;
4324 }
4325
4326 if (sp->fileformat == EOL_MAC)
4327 {
4328 scan = vim_strchr(buf, '\r');
4329
4330 if (scan != NULL)
4331 {
4332 *scan = '\n';
4333 if (*(scan + 1) != 0)
4334 {
4335 *(scan + 1) = 0;
4336 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4337 }
4338 }
4339 len = STRLEN(buf);
4340 }
4341#endif
4342
4343 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004344 ga.ga_len = len;
4345
4346 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004347 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348 continue;
4349
4350 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4351 {
4352#ifdef USE_CRNL
4353 has_cr = (len >= 2 && buf[len - 2] == '\r');
4354 if (sp->fileformat == EOL_UNKNOWN)
4355 {
4356 if (has_cr)
4357 sp->fileformat = EOL_DOS;
4358 else
4359 sp->fileformat = EOL_UNIX;
4360 }
4361
4362 if (sp->fileformat == EOL_DOS)
4363 {
4364 if (has_cr) /* replace trailing CR */
4365 {
4366 buf[len - 2] = '\n';
4367 --len;
4368 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 }
4370 else /* lines like ":map xx yy^M" will have failed */
4371 {
4372 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004373 {
4374 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004375 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004376 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004377 sp->error = TRUE;
4378 sp->fileformat = EOL_UNIX;
4379 }
4380 }
4381#endif
4382 /* The '\n' is escaped if there is an odd number of ^V's just
4383 * before it, first set "c" just before the 'V's and then check
4384 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4385 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4386 ;
4387 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4388 {
4389 sourcing_lnum++;
4390 continue;
4391 }
4392
4393 buf[len - 1] = NUL; /* remove the NL */
4394 }
4395
4396 /*
4397 * Check for ^C here now and then, so recursive :so can be broken.
4398 */
4399 line_breakcheck();
4400 break;
4401 }
4402
4403 if (have_read)
4404 return (char_u *)ga.ga_data;
4405
4406 vim_free(ga.ga_data);
4407 return NULL;
4408}
4409
Bram Moolenaar05159a02005-02-26 23:04:13 +00004410#if defined(FEAT_PROFILE) || defined(PROTO)
4411/*
4412 * Called when starting to read a script line.
4413 * "sourcing_lnum" must be correct!
4414 * When skipping lines it may not actually be executed, but we won't find out
4415 * until later and we need to store the time now.
4416 */
4417 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004418script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004419{
4420 scriptitem_T *si;
4421 sn_prl_T *pp;
4422
4423 if (current_SID <= 0 || current_SID > script_items.ga_len)
4424 return;
4425 si = &SCRIPT_ITEM(current_SID);
4426 if (si->sn_prof_on && sourcing_lnum >= 1)
4427 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004428 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004429 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004430 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004431 si->sn_prl_idx = sourcing_lnum - 1;
4432 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4433 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4434 {
4435 /* Zero counters for a line that was not used before. */
4436 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4437 pp->snp_count = 0;
4438 profile_zero(&pp->sn_prl_total);
4439 profile_zero(&pp->sn_prl_self);
4440 ++si->sn_prl_ga.ga_len;
4441 }
4442 si->sn_prl_execed = FALSE;
4443 profile_start(&si->sn_prl_start);
4444 profile_zero(&si->sn_prl_children);
4445 profile_get_wait(&si->sn_prl_wait);
4446 }
4447}
4448
4449/*
4450 * Called when actually executing a function line.
4451 */
4452 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004453script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004454{
4455 scriptitem_T *si;
4456
4457 if (current_SID <= 0 || current_SID > script_items.ga_len)
4458 return;
4459 si = &SCRIPT_ITEM(current_SID);
4460 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4461 si->sn_prl_execed = TRUE;
4462}
4463
4464/*
4465 * Called when done with a function line.
4466 */
4467 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004468script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004469{
4470 scriptitem_T *si;
4471 sn_prl_T *pp;
4472
4473 if (current_SID <= 0 || current_SID > script_items.ga_len)
4474 return;
4475 si = &SCRIPT_ITEM(current_SID);
4476 if (si->sn_prof_on && si->sn_prl_idx >= 0
4477 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4478 {
4479 if (si->sn_prl_execed)
4480 {
4481 pp = &PRL_ITEM(si, si->sn_prl_idx);
4482 ++pp->snp_count;
4483 profile_end(&si->sn_prl_start);
4484 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004485 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004486 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4487 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004488 }
4489 si->sn_prl_idx = -1;
4490 }
4491}
4492#endif
4493
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494/*
4495 * ":scriptencoding": Set encoding conversion for a sourced script.
4496 * Without the multi-byte feature it's simply ignored.
4497 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004499ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004500{
4501#ifdef FEAT_MBYTE
4502 struct source_cookie *sp;
4503 char_u *name;
4504
4505 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4506 {
4507 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4508 return;
4509 }
4510
4511 if (*eap->arg != NUL)
4512 {
4513 name = enc_canonize(eap->arg);
4514 if (name == NULL) /* out of memory */
4515 return;
4516 }
4517 else
4518 name = eap->arg;
4519
4520 /* Setup for conversion from the specified encoding to 'encoding'. */
4521 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4522 convert_setup(&sp->conv, name, p_enc);
4523
4524 if (name != eap->arg)
4525 vim_free(name);
4526#endif
4527}
4528
4529#if defined(FEAT_EVAL) || defined(PROTO)
4530/*
4531 * ":finish": Mark a sourced file as finished.
4532 */
4533 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004534ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535{
4536 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4537 do_finish(eap, FALSE);
4538 else
4539 EMSG(_("E168: :finish used outside of a sourced file"));
4540}
4541
4542/*
4543 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4544 * Also called for a pending finish at the ":endtry" or after returning from
4545 * an extra do_cmdline(). "reanimate" is used in the latter case.
4546 */
4547 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004548do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549{
4550 int idx;
4551
4552 if (reanimate)
4553 ((struct source_cookie *)getline_cookie(eap->getline,
4554 eap->cookie))->finished = FALSE;
4555
4556 /*
4557 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4558 * not in its finally clause (which then is to be executed next) is found.
4559 * In this case, make the ":finish" pending for execution at the ":endtry".
4560 * Otherwise, finish normally.
4561 */
4562 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4563 if (idx >= 0)
4564 {
4565 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4566 report_make_pending(CSTP_FINISH, NULL);
4567 }
4568 else
4569 ((struct source_cookie *)getline_cookie(eap->getline,
4570 eap->cookie))->finished = TRUE;
4571}
4572
4573
4574/*
4575 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4576 * message for missing ":endif".
4577 * Return FALSE when not sourcing a file.
4578 */
4579 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004580source_finished(
4581 char_u *(*fgetline)(int, void *, int),
4582 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004584 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004585 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004586 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004587}
4588#endif
4589
4590#if defined(FEAT_LISTCMDS) || defined(PROTO)
4591/*
4592 * ":checktime [buffer]"
4593 */
4594 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004595ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004596{
4597 buf_T *buf;
4598 int save_no_check_timestamps = no_check_timestamps;
4599
4600 no_check_timestamps = 0;
4601 if (eap->addr_count == 0) /* default is all buffers */
4602 check_timestamps(FALSE);
4603 else
4604 {
4605 buf = buflist_findnr((int)eap->line2);
4606 if (buf != NULL) /* cannot happen? */
4607 (void)buf_check_timestamp(buf, FALSE);
4608 }
4609 no_check_timestamps = save_no_check_timestamps;
4610}
4611#endif
4612
Bram Moolenaar071d4272004-06-13 20:20:40 +00004613#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4614 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004615# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004616static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004618 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004619get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004621 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004623 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004624 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004625
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004626# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 if (loc != NULL)
4628 {
4629 char_u *p;
4630
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004631 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4632 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004633 p = vim_strchr(loc, '=');
4634 if (p != NULL)
4635 {
4636 loc = ++p;
4637 while (*p != NUL) /* remove trailing newline */
4638 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004639 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004640 {
4641 *p = NUL;
4642 break;
4643 }
4644 ++p;
4645 }
4646 }
4647 }
4648# endif
4649
4650 return loc;
4651}
4652#endif
4653
4654
4655#ifdef WIN32
4656/*
4657 * On MS-Windows locale names are strings like "German_Germany.1252", but
4658 * gettext expects "de". Try to translate one into another here for a few
4659 * supported languages.
4660 */
4661 static char_u *
4662gettext_lang(char_u *name)
4663{
4664 int i;
4665 static char *(mtable[]) = {
4666 "afrikaans", "af",
4667 "czech", "cs",
4668 "dutch", "nl",
4669 "german", "de",
4670 "english_united kingdom", "en_GB",
4671 "spanish", "es",
4672 "french", "fr",
4673 "italian", "it",
4674 "japanese", "ja",
4675 "korean", "ko",
4676 "norwegian", "no",
4677 "polish", "pl",
4678 "russian", "ru",
4679 "slovak", "sk",
4680 "swedish", "sv",
4681 "ukrainian", "uk",
4682 "chinese_china", "zh_CN",
4683 "chinese_taiwan", "zh_TW",
4684 NULL};
4685
4686 for (i = 0; mtable[i] != NULL; i += 2)
4687 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004688 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004689 return name;
4690}
4691#endif
4692
4693#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4694/*
4695 * Obtain the current messages language. Used to set the default for
4696 * 'helplang'. May return NULL or an empty string.
4697 */
4698 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004699get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004700{
4701 char_u *p;
4702
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004703# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004704# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004705 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004706# else
4707 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004708 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4709 * and LC_MONETARY may be set differently for a Japanese working in the
4710 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004711 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004712# endif
4713# else
4714 p = mch_getenv((char_u *)"LC_ALL");
4715 if (p == NULL || *p == NUL)
4716 {
4717 p = mch_getenv((char_u *)"LC_MESSAGES");
4718 if (p == NULL || *p == NUL)
4719 p = mch_getenv((char_u *)"LANG");
4720 }
4721# endif
4722# ifdef WIN32
4723 p = gettext_lang(p);
4724# endif
4725 return p;
4726}
4727#endif
4728
Bram Moolenaardef9e822004-12-31 20:58:58 +00004729/* Complicated #if; matches with where get_mess_env() is used below. */
4730#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4731 && defined(LC_MESSAGES))) \
4732 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4733 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4734 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004735static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736
4737/*
4738 * Get the language used for messages from the environment.
4739 */
4740 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004741get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742{
4743 char_u *p;
4744
4745 p = mch_getenv((char_u *)"LC_ALL");
4746 if (p == NULL || *p == NUL)
4747 {
4748 p = mch_getenv((char_u *)"LC_MESSAGES");
4749 if (p == NULL || *p == NUL)
4750 {
4751 p = mch_getenv((char_u *)"LANG");
4752 if (p != NULL && VIM_ISDIGIT(*p))
4753 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004754# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004755 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004756 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004757# endif
4758 }
4759 }
4760 return p;
4761}
4762#endif
4763
4764#if defined(FEAT_EVAL) || defined(PROTO)
4765
4766/*
4767 * Set the "v:lang" variable according to the current locale setting.
4768 * Also do "v:lc_time"and "v:ctype".
4769 */
4770 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004771set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772{
4773 char_u *loc;
4774
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004775# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004776 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004777# else
4778 /* setlocale() not supported: use the default value */
4779 loc = (char_u *)"C";
4780# endif
4781 set_vim_var_string(VV_CTYPE, loc, -1);
4782
4783 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4784 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004785# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004786 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004787# else
4788 loc = get_mess_env();
4789# endif
4790 set_vim_var_string(VV_LANG, loc, -1);
4791
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004792# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004793 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004794# endif
4795 set_vim_var_string(VV_LC_TIME, loc, -1);
4796}
4797#endif
4798
4799#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4800 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4801/*
4802 * ":language": Set the language (locale).
4803 */
4804 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004805ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004806{
4807 char *loc;
4808 char_u *p;
4809 char_u *name;
4810 int what = LC_ALL;
4811 char *whatstr = "";
4812#ifdef LC_MESSAGES
4813# define VIM_LC_MESSAGES LC_MESSAGES
4814#else
4815# define VIM_LC_MESSAGES 6789
4816#endif
4817
4818 name = eap->arg;
4819
4820 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4821 * Allow abbreviation, but require at least 3 characters to avoid
4822 * confusion with a two letter language name "me" or "ct". */
4823 p = skiptowhite(eap->arg);
4824 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4825 {
4826 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4827 {
4828 what = VIM_LC_MESSAGES;
4829 name = skipwhite(p);
4830 whatstr = "messages ";
4831 }
4832 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4833 {
4834 what = LC_CTYPE;
4835 name = skipwhite(p);
4836 whatstr = "ctype ";
4837 }
4838 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4839 {
4840 what = LC_TIME;
4841 name = skipwhite(p);
4842 whatstr = "time ";
4843 }
4844 }
4845
4846 if (*name == NUL)
4847 {
4848#ifndef LC_MESSAGES
4849 if (what == VIM_LC_MESSAGES)
4850 p = get_mess_env();
4851 else
4852#endif
4853 p = (char_u *)setlocale(what, NULL);
4854 if (p == NULL || *p == NUL)
4855 p = (char_u *)"Unknown";
4856 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4857 }
4858 else
4859 {
4860#ifndef LC_MESSAGES
4861 if (what == VIM_LC_MESSAGES)
4862 loc = "";
4863 else
4864#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004865 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004866 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004867#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4868 /* Make sure strtod() uses a decimal point, not a comma. */
4869 setlocale(LC_NUMERIC, "C");
4870#endif
4871 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004872 if (loc == NULL)
4873 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4874 else
4875 {
4876#ifdef HAVE_NL_MSG_CAT_CNTR
4877 /* Need to do this for GNU gettext, otherwise cached translations
4878 * will be used again. */
4879 extern int _nl_msg_cat_cntr;
4880
4881 ++_nl_msg_cat_cntr;
4882#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004883 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004884 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4885
4886 if (what != LC_TIME)
4887 {
4888 /* Tell gettext() what to translate to. It apparently doesn't
4889 * use the currently effective locale. Also do this when
4890 * FEAT_GETTEXT isn't defined, so that shell commands use this
4891 * value. */
4892 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004893 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004894 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004895
4896 /* Clear $LANGUAGE because GNU gettext uses it. */
4897 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004898# ifdef WIN32
4899 /* Apparently MS-Windows printf() may cause a crash when
4900 * we give it 8-bit text while it's expecting text in the
4901 * current locale. This call avoids that. */
4902 setlocale(LC_CTYPE, "C");
4903# endif
4904 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905 if (what != LC_CTYPE)
4906 {
4907 char_u *mname;
4908#ifdef WIN32
4909 mname = gettext_lang(name);
4910#else
4911 mname = name;
4912#endif
4913 vim_setenv((char_u *)"LC_MESSAGES", mname);
4914#ifdef FEAT_MULTI_LANG
4915 set_helplang_default(mname);
4916#endif
4917 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918 }
4919
4920# ifdef FEAT_EVAL
4921 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4922 set_lang_var();
4923# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004924# ifdef FEAT_TITLE
4925 maketitle();
4926# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927 }
4928 }
4929}
4930
4931# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004932
4933static char_u **locales = NULL; /* Array of all available locales */
4934static int did_init_locales = FALSE;
4935
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004936static void init_locales(void);
4937static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004938
4939/*
4940 * Lazy initialization of all available locales.
4941 */
4942 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004943init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004944{
4945 if (!did_init_locales)
4946 {
4947 did_init_locales = TRUE;
4948 locales = find_locales();
4949 }
4950}
4951
4952/* Return an array of strings for all available locales + NULL for the
4953 * last element. Return NULL in case of error. */
4954 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004955find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004956{
4957 garray_T locales_ga;
4958 char_u *loc;
4959
4960 /* Find all available locales by running command "locale -a". If this
4961 * doesn't work we won't have completion. */
4962 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004963 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004964 if (locale_a == NULL)
4965 return NULL;
4966 ga_init2(&locales_ga, sizeof(char_u *), 20);
4967
4968 /* Transform locale_a string where each locale is separated by "\n"
4969 * into an array of locale strings. */
4970 loc = (char_u *)strtok((char *)locale_a, "\n");
4971
4972 while (loc != NULL)
4973 {
4974 if (ga_grow(&locales_ga, 1) == FAIL)
4975 break;
4976 loc = vim_strsave(loc);
4977 if (loc == NULL)
4978 break;
4979
4980 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4981 loc = (char_u *)strtok(NULL, "\n");
4982 }
4983 vim_free(locale_a);
4984 if (ga_grow(&locales_ga, 1) == FAIL)
4985 {
4986 ga_clear(&locales_ga);
4987 return NULL;
4988 }
4989 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4990 return (char_u **)locales_ga.ga_data;
4991}
4992
4993# if defined(EXITFREE) || defined(PROTO)
4994 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004995free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004996{
4997 int i;
4998 if (locales != NULL)
4999 {
5000 for (i = 0; locales[i] != NULL; i++)
5001 vim_free(locales[i]);
5002 vim_free(locales);
5003 locales = NULL;
5004 }
5005}
5006# endif
5007
Bram Moolenaar071d4272004-06-13 20:20:40 +00005008/*
5009 * Function given to ExpandGeneric() to obtain the possible arguments of the
5010 * ":language" command.
5011 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005012 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005013get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005014{
5015 if (idx == 0)
5016 return (char_u *)"messages";
5017 if (idx == 1)
5018 return (char_u *)"ctype";
5019 if (idx == 2)
5020 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005021
5022 init_locales();
5023 if (locales == NULL)
5024 return NULL;
5025 return locales[idx - 3];
5026}
5027
5028/*
5029 * Function given to ExpandGeneric() to obtain the available locales.
5030 */
5031 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005032get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005033{
5034 init_locales();
5035 if (locales == NULL)
5036 return NULL;
5037 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038}
5039# endif
5040
5041#endif