blob: a90fe7d8c6565e08f66a3fe647147a0300e4e3c9 [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;
1104}
1105
1106/*
1107 * Take a timer out of the list of timers.
1108 */
1109 static void
1110remove_timer(timer_T *timer)
1111{
1112 if (timer->tr_prev == NULL)
1113 first_timer = timer->tr_next;
1114 else
1115 timer->tr_prev->tr_next = timer->tr_next;
1116 if (timer->tr_next != NULL)
1117 timer->tr_next->tr_prev = timer->tr_prev;
1118}
1119
1120 static void
1121free_timer(timer_T *timer)
1122{
1123 vim_free(timer->tr_callback);
1124 partial_unref(timer->tr_partial);
1125 vim_free(timer);
1126}
1127
1128/*
1129 * Create a timer and return it. NULL if out of memory.
1130 * Caller should set the callback.
1131 */
1132 timer_T *
1133create_timer(long msec, int repeat)
1134{
1135 timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
1136
1137 if (timer == NULL)
1138 return NULL;
1139 timer->tr_id = ++last_timer_id;
1140 insert_timer(timer);
1141 if (repeat != 0)
1142 {
1143 timer->tr_repeat = repeat - 1;
1144 timer->tr_interval = msec;
1145 }
1146
1147 profile_setlimit(msec, &timer->tr_due);
1148 return timer;
1149}
1150
1151/*
1152 * Invoke the callback of "timer".
1153 */
1154 static void
1155timer_callback(timer_T *timer)
1156{
1157 typval_T rettv;
1158 int dummy;
1159 typval_T argv[2];
1160
1161 argv[0].v_type = VAR_NUMBER;
1162 argv[0].vval.v_number = timer->tr_id;
1163 argv[1].v_type = VAR_UNKNOWN;
1164
1165 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
1166 &rettv, 1, argv, 0L, 0L, &dummy, TRUE,
1167 timer->tr_partial, NULL);
1168 clear_tv(&rettv);
1169}
1170
1171/*
1172 * Call timers that are due.
1173 * Return the time in msec until the next timer is due.
1174 */
1175 long
1176check_due_timer()
1177{
1178 timer_T *timer;
1179 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001180 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001181 proftime_T now;
1182 int did_one = FALSE;
1183# ifdef WIN3264
1184 LARGE_INTEGER fr;
1185
1186 QueryPerformanceFrequency(&fr);
1187# endif
1188 while (!got_int)
1189 {
1190 profile_start(&now);
1191 next_due = -1;
1192 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1193 {
1194# ifdef WIN3264
1195 this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
1196 / (double)fr.QuadPart) * 1000);
1197# else
1198 this_due = (timer->tr_due.tv_sec - now.tv_sec) * 1000
1199 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1200# endif
1201 if (this_due <= 1)
1202 {
1203 remove_timer(timer);
1204 timer_callback(timer);
1205 did_one = TRUE;
1206 if (timer->tr_repeat != 0)
1207 {
1208 profile_setlimit(timer->tr_interval, &timer->tr_due);
1209 if (timer->tr_repeat > 0)
1210 --timer->tr_repeat;
1211 insert_timer(timer);
1212 }
1213 else
1214 free_timer(timer);
1215 /* the callback may do anything, start all over */
1216 break;
1217 }
1218 if (next_due == -1 || next_due > this_due)
1219 next_due = this_due;
1220 }
1221 if (timer == NULL)
1222 break;
1223 }
1224
1225 if (did_one)
1226 redraw_after_callback();
1227
1228 return next_due;
1229}
1230
1231/*
1232 * Find a timer by ID. Returns NULL if not found;
1233 */
1234 timer_T *
1235find_timer(int id)
1236{
1237 timer_T *timer;
1238
1239 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1240 if (timer->tr_id == id)
1241 break;
1242 return timer;
1243}
1244
1245
1246/*
1247 * Stop a timer and delete it.
1248 */
1249 void
1250stop_timer(timer_T *timer)
1251{
1252 remove_timer(timer);
1253 free_timer(timer);
1254}
1255# endif
1256
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001257#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1258# if defined(HAVE_MATH_H)
1259# include <math.h>
1260# endif
1261
1262/*
1263 * Divide the time "tm" by "count" and store in "tm2".
1264 */
1265 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001266profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001267{
1268 if (count == 0)
1269 profile_zero(tm2);
1270 else
1271 {
1272# ifdef WIN3264
1273 tm2->QuadPart = tm->QuadPart / count;
1274# else
1275 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1276
1277 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001278 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001279# endif
1280 }
1281}
1282#endif
1283
Bram Moolenaar76929292008-01-06 19:07:36 +00001284# if defined(FEAT_PROFILE) || defined(PROTO)
1285/*
1286 * Functions for profiling.
1287 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001288static void script_do_profile(scriptitem_T *si);
1289static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001290static proftime_T prof_wait_time;
1291
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001292/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001293 * Add the time "tm2" to "tm".
1294 */
1295 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001296profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001297{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001298# ifdef WIN3264
1299 tm->QuadPart += tm2->QuadPart;
1300# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001301 tm->tv_usec += tm2->tv_usec;
1302 tm->tv_sec += tm2->tv_sec;
1303 if (tm->tv_usec >= 1000000)
1304 {
1305 tm->tv_usec -= 1000000;
1306 ++tm->tv_sec;
1307 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001308# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001309}
1310
1311/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001312 * Add the "self" time from the total time and the children's time.
1313 */
1314 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001315profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001316{
1317 /* Check that the result won't be negative. Can happen with recursive
1318 * calls. */
1319#ifdef WIN3264
1320 if (total->QuadPart <= children->QuadPart)
1321 return;
1322#else
1323 if (total->tv_sec < children->tv_sec
1324 || (total->tv_sec == children->tv_sec
1325 && total->tv_usec <= children->tv_usec))
1326 return;
1327#endif
1328 profile_add(self, total);
1329 profile_sub(self, children);
1330}
1331
1332/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001333 * Get the current waittime.
1334 */
1335 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001336profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001337{
1338 *tm = prof_wait_time;
1339}
1340
1341/*
1342 * Subtract the passed waittime since "tm" from "tma".
1343 */
1344 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001345profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001346{
1347 proftime_T tm3 = prof_wait_time;
1348
1349 profile_sub(&tm3, tm);
1350 profile_sub(tma, &tm3);
1351}
1352
1353/*
1354 * Return TRUE if "tm1" and "tm2" are equal.
1355 */
1356 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001357profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001358{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001359# ifdef WIN3264
1360 return (tm1->QuadPart == tm2->QuadPart);
1361# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001362 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001363# endif
1364}
1365
1366/*
1367 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1368 */
1369 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001370profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001371{
1372# ifdef WIN3264
1373 return (int)(tm2->QuadPart - tm1->QuadPart);
1374# else
1375 if (tm1->tv_sec == tm2->tv_sec)
1376 return tm2->tv_usec - tm1->tv_usec;
1377 return tm2->tv_sec - tm1->tv_sec;
1378# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001379}
1380
Bram Moolenaar05159a02005-02-26 23:04:13 +00001381static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001382static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001383
1384/*
1385 * ":profile cmd args"
1386 */
1387 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001388ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001389{
1390 char_u *e;
1391 int len;
1392
1393 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001394 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001395 e = skipwhite(e);
1396
1397 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1398 {
1399 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001400 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001401 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001402 profile_zero(&prof_wait_time);
1403 set_vim_var_nr(VV_PROFILING, 1L);
1404 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001405 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001406 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001407 else if (STRCMP(eap->arg, "pause") == 0)
1408 {
1409 if (do_profiling == PROF_YES)
1410 profile_start(&pause_time);
1411 do_profiling = PROF_PAUSED;
1412 }
1413 else if (STRCMP(eap->arg, "continue") == 0)
1414 {
1415 if (do_profiling == PROF_PAUSED)
1416 {
1417 profile_end(&pause_time);
1418 profile_add(&prof_wait_time, &pause_time);
1419 }
1420 do_profiling = PROF_YES;
1421 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001422 else
1423 {
1424 /* The rest is similar to ":breakadd". */
1425 ex_breakadd(eap);
1426 }
1427}
1428
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001429/* Command line expansion for :profile. */
1430static enum
1431{
1432 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001433 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001434} pexpand_what;
1435
1436static char *pexpand_cmds[] = {
1437 "start",
1438#define PROFCMD_START 0
1439 "pause",
1440#define PROFCMD_PAUSE 1
1441 "continue",
1442#define PROFCMD_CONTINUE 2
1443 "func",
1444#define PROFCMD_FUNC 3
1445 "file",
1446#define PROFCMD_FILE 4
1447 NULL
1448#define PROFCMD_LAST 5
1449};
1450
1451/*
1452 * Function given to ExpandGeneric() to obtain the profile command
1453 * specific expansion.
1454 */
1455 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001456get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001457{
1458 switch (pexpand_what)
1459 {
1460 case PEXP_SUBCMD:
1461 return (char_u *)pexpand_cmds[idx];
1462 /* case PEXP_FUNC: TODO */
1463 default:
1464 return NULL;
1465 }
1466}
1467
1468/*
1469 * Handle command line completion for :profile command.
1470 */
1471 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001472set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001473{
1474 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001475
1476 /* Default: expand subcommands. */
1477 xp->xp_context = EXPAND_PROFILE;
1478 pexpand_what = PEXP_SUBCMD;
1479 xp->xp_pattern = arg;
1480
1481 end_subcmd = skiptowhite(arg);
1482 if (*end_subcmd == NUL)
1483 return;
1484
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001485 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001486 {
1487 xp->xp_context = EXPAND_FILES;
1488 xp->xp_pattern = skipwhite(end_subcmd);
1489 return;
1490 }
1491
1492 /* TODO: expand function names after "func" */
1493 xp->xp_context = EXPAND_NOTHING;
1494}
1495
Bram Moolenaar05159a02005-02-26 23:04:13 +00001496/*
1497 * Dump the profiling info.
1498 */
1499 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001500profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001501{
1502 FILE *fd;
1503
1504 if (profile_fname != NULL)
1505 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001506 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001507 if (fd == NULL)
1508 EMSG2(_(e_notopen), profile_fname);
1509 else
1510 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001511 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001512 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001513 fclose(fd);
1514 }
1515 }
1516}
1517
1518/*
1519 * Start profiling script "fp".
1520 */
1521 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001522script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001523{
1524 si->sn_pr_count = 0;
1525 profile_zero(&si->sn_pr_total);
1526 profile_zero(&si->sn_pr_self);
1527
1528 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1529 si->sn_prl_idx = -1;
1530 si->sn_prof_on = TRUE;
1531 si->sn_pr_nest = 0;
1532}
1533
1534/*
1535 * save time when starting to invoke another script or function.
1536 */
1537 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001538script_prof_save(
1539 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001540{
1541 scriptitem_T *si;
1542
1543 if (current_SID > 0 && current_SID <= script_items.ga_len)
1544 {
1545 si = &SCRIPT_ITEM(current_SID);
1546 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1547 profile_start(&si->sn_pr_child);
1548 }
1549 profile_get_wait(tm);
1550}
1551
1552/*
1553 * Count time spent in children after invoking another script or function.
1554 */
1555 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001556script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001557{
1558 scriptitem_T *si;
1559
1560 if (current_SID > 0 && current_SID <= script_items.ga_len)
1561 {
1562 si = &SCRIPT_ITEM(current_SID);
1563 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1564 {
1565 profile_end(&si->sn_pr_child);
1566 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1567 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1568 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1569 }
1570 }
1571}
1572
1573static proftime_T inchar_time;
1574
1575/*
1576 * Called when starting to wait for the user to type a character.
1577 */
1578 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001579prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001580{
1581 profile_start(&inchar_time);
1582}
1583
1584/*
1585 * Called when finished waiting for the user to type a character.
1586 */
1587 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001588prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001589{
1590 profile_end(&inchar_time);
1591 profile_add(&prof_wait_time, &inchar_time);
1592}
1593
1594/*
1595 * Dump the profiling results for all scripts in file "fd".
1596 */
1597 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001598script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001599{
1600 int id;
1601 scriptitem_T *si;
1602 int i;
1603 FILE *sfd;
1604 sn_prl_T *pp;
1605
1606 for (id = 1; id <= script_items.ga_len; ++id)
1607 {
1608 si = &SCRIPT_ITEM(id);
1609 if (si->sn_prof_on)
1610 {
1611 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1612 if (si->sn_pr_count == 1)
1613 fprintf(fd, "Sourced 1 time\n");
1614 else
1615 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1616 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1617 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1618 fprintf(fd, "\n");
1619 fprintf(fd, "count total (s) self (s)\n");
1620
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001621 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001622 if (sfd == NULL)
1623 fprintf(fd, "Cannot open file!\n");
1624 else
1625 {
1626 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1627 {
1628 if (vim_fgets(IObuff, IOSIZE, sfd))
1629 break;
1630 pp = &PRL_ITEM(si, i);
1631 if (pp->snp_count > 0)
1632 {
1633 fprintf(fd, "%5d ", pp->snp_count);
1634 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1635 fprintf(fd, " ");
1636 else
1637 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1638 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1639 }
1640 else
1641 fprintf(fd, " ");
1642 fprintf(fd, "%s", IObuff);
1643 }
1644 fclose(sfd);
1645 }
1646 fprintf(fd, "\n");
1647 }
1648 }
1649}
1650
1651/*
1652 * Return TRUE when a function defined in the current script should be
1653 * profiled.
1654 */
1655 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001656prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001657{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001658 if (current_SID > 0)
1659 return SCRIPT_ITEM(current_SID).sn_pr_force;
1660 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001661}
1662
1663# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664#endif
1665
1666/*
1667 * If 'autowrite' option set, try to write the file.
1668 * Careful: autocommands may make "buf" invalid!
1669 *
1670 * return FAIL for failure, OK otherwise
1671 */
1672 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001673autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001675 int r;
1676
Bram Moolenaar071d4272004-06-13 20:20:40 +00001677 if (!(p_aw || p_awa) || !p_write
1678#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001679 /* never autowrite a "nofile" or "nowrite" buffer */
1680 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001681#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001682 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001683 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001684 r = buf_write_all(buf, forceit);
1685
1686 /* Writing may succeed but the buffer still changed, e.g., when there is a
1687 * conversion error. We do want to return FAIL then. */
1688 if (buf_valid(buf) && bufIsChanged(buf))
1689 r = FAIL;
1690 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691}
1692
1693/*
1694 * flush all buffers, except the ones that are readonly
1695 */
1696 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001697autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001698{
1699 buf_T *buf;
1700
1701 if (!(p_aw || p_awa) || !p_write)
1702 return;
1703 for (buf = firstbuf; buf; buf = buf->b_next)
1704 if (bufIsChanged(buf) && !buf->b_p_ro)
1705 {
1706 (void)buf_write_all(buf, FALSE);
1707#ifdef FEAT_AUTOCMD
1708 /* an autocommand may have deleted the buffer */
1709 if (!buf_valid(buf))
1710 buf = firstbuf;
1711#endif
1712 }
1713}
1714
1715/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001716 * Return TRUE if buffer was changed and cannot be abandoned.
1717 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001718 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001720check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001721{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001722 int forceit = (flags & CCGD_FORCEIT);
1723
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 if ( !forceit
1725 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001726 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1727 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 {
1729#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1730 if ((p_confirm || cmdmod.confirm) && p_write)
1731 {
1732 buf_T *buf2;
1733 int count = 0;
1734
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001735 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001736 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1737 if (bufIsChanged(buf2)
1738 && (buf2->b_ffname != NULL
1739# ifdef FEAT_BROWSE
1740 || cmdmod.browse
1741# endif
1742 ))
1743 ++count;
1744# ifdef FEAT_AUTOCMD
1745 if (!buf_valid(buf))
1746 /* Autocommand deleted buffer, oops! It's not changed now. */
1747 return FALSE;
1748# endif
1749 dialog_changed(buf, count > 1);
1750# ifdef FEAT_AUTOCMD
1751 if (!buf_valid(buf))
1752 /* Autocommand deleted buffer, oops! It's not changed now. */
1753 return FALSE;
1754# endif
1755 return bufIsChanged(buf);
1756 }
1757#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001758 if (flags & CCGD_EXCMD)
1759 EMSG(_(e_nowrtmsg));
1760 else
1761 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762 return TRUE;
1763 }
1764 return FALSE;
1765}
1766
1767#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1768
1769#if defined(FEAT_BROWSE) || defined(PROTO)
1770/*
1771 * When wanting to write a file without a file name, ask the user for a name.
1772 */
1773 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001774browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775{
1776 if (buf->b_fname == NULL)
1777 {
1778 char_u *fname;
1779
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001780 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1781 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001782 if (fname != NULL)
1783 {
1784 if (setfname(buf, fname, NULL, TRUE) == OK)
1785 buf->b_flags |= BF_NOTEDITED;
1786 vim_free(fname);
1787 }
1788 }
1789}
1790#endif
1791
1792/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001793 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 * Must check 'write' option first!
1795 */
1796 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001797dialog_changed(
1798 buf_T *buf,
1799 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001801 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802 int ret;
1803 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001804 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001805
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001806 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001807 (buf->b_fname != NULL) ?
1808 buf->b_fname : (char_u *)_("Untitled"));
1809 if (checkall)
1810 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1811 else
1812 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1813
Bram Moolenaar8218f602012-04-25 17:32:18 +02001814 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1815 * function. */
1816 ea.append = ea.forceit = FALSE;
1817
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818 if (ret == VIM_YES)
1819 {
1820#ifdef FEAT_BROWSE
1821 /* May get file name, when there is none */
1822 browse_save_fname(buf);
1823#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001824 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1825 buf->b_fname, buf->b_ffname, FALSE) == OK)
1826 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827 (void)buf_write_all(buf, FALSE);
1828 }
1829 else if (ret == VIM_NO)
1830 {
1831 unchanged(buf, TRUE);
1832 }
1833 else if (ret == VIM_ALL)
1834 {
1835 /*
1836 * Write all modified files that can be written.
1837 * Skip readonly buffers, these need to be confirmed
1838 * individually.
1839 */
1840 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1841 {
1842 if (bufIsChanged(buf2)
1843 && (buf2->b_ffname != NULL
1844#ifdef FEAT_BROWSE
1845 || cmdmod.browse
1846#endif
1847 )
1848 && !buf2->b_p_ro)
1849 {
1850#ifdef FEAT_BROWSE
1851 /* May get file name, when there is none */
1852 browse_save_fname(buf2);
1853#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001854 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1855 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1856 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857 (void)buf_write_all(buf2, FALSE);
1858#ifdef FEAT_AUTOCMD
1859 /* an autocommand may have deleted the buffer */
1860 if (!buf_valid(buf2))
1861 buf2 = firstbuf;
1862#endif
1863 }
1864 }
1865 }
1866 else if (ret == VIM_DISCARDALL)
1867 {
1868 /*
1869 * mark all buffers as unchanged
1870 */
1871 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1872 unchanged(buf2, TRUE);
1873 }
1874}
1875#endif
1876
1877/*
1878 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1879 * hidden, autowriting it or unloading it.
1880 */
1881 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001882can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883{
1884 return ( P_HID(buf)
1885 || !bufIsChanged(buf)
1886 || buf->b_nwindows > 1
1887 || autowrite(buf, forceit) == OK
1888 || forceit);
1889}
1890
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001891static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001892
1893/*
1894 * Add a buffer number to "bufnrs", unless it's already there.
1895 */
1896 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001897add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001898{
1899 int i;
1900
1901 for (i = 0; i < *bufnump; ++i)
1902 if (bufnrs[i] == nr)
1903 return;
1904 bufnrs[*bufnump] = nr;
1905 *bufnump = *bufnump + 1;
1906}
1907
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908/*
1909 * Return TRUE if any buffer was changed and cannot be abandoned.
1910 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001911 * When "unload" is true the current buffer is unloaded instead of making it
1912 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001913 */
1914 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001915check_changed_any(
1916 int hidden, /* Only check hidden buffers */
1917 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001919 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920 buf_T *buf;
1921 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001922 int i;
1923 int bufnum = 0;
1924 int bufcount = 0;
1925 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001927 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 win_T *wp;
1929#endif
1930
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001931 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1932 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001934 if (bufcount == 0)
1935 return FALSE;
1936
1937 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1938 if (bufnrs == NULL)
1939 return FALSE;
1940
1941 /* curbuf */
1942 bufnrs[bufnum++] = curbuf->b_fnum;
1943#ifdef FEAT_WINDOWS
1944 /* buf in curtab */
1945 FOR_ALL_WINDOWS(wp)
1946 if (wp->w_buffer != curbuf)
1947 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1948
1949 /* buf in other tab */
1950 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1951 if (tp != curtab)
1952 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1953 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1954#endif
1955 /* any other buf */
1956 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1957 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1958
1959 for (i = 0; i < bufnum; ++i)
1960 {
1961 buf = buflist_findnr(bufnrs[i]);
1962 if (buf == NULL)
1963 continue;
1964 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1965 {
1966 /* Try auto-writing the buffer. If this fails but the buffer no
1967 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001968 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1969 | CCGD_MULTWIN
1970 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001971 break; /* didn't save - still changes */
1972 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973 }
1974
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001975 if (i >= bufnum)
1976 goto theend;
1977
1978 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979 exiting = FALSE;
1980#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1981 /*
1982 * When ":confirm" used, don't give an error message.
1983 */
1984 if (!(p_confirm || cmdmod.confirm))
1985#endif
1986 {
1987 /* There must be a wait_return for this message, do_buffer()
1988 * may cause a redraw. But wait_return() is a no-op when vgetc()
1989 * is busy (Quit used from window menu), then make sure we don't
1990 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001991 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992 {
1993 msg_row = cmdline_row;
1994 msg_col = 0;
1995 msg_didout = FALSE;
1996 }
1997 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001998 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999 {
2000 save = no_wait_return;
2001 no_wait_return = FALSE;
2002 wait_return(FALSE);
2003 no_wait_return = save;
2004 }
2005 }
2006
2007#ifdef FEAT_WINDOWS
2008 /* Try to find a window that contains the buffer. */
2009 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002010 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002011 if (wp->w_buffer == buf)
2012 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002013 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002014# ifdef FEAT_AUTOCMD
2015 /* Paranoia: did autocms wipe out the buffer with changes? */
2016 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002017 {
2018 goto theend;
2019 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002020# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002021 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002022 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002023buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002024#endif
2025
2026 /* Open the changed buffer in the current window. */
2027 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002028 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002029
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002030theend:
2031 vim_free(bufnrs);
2032 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002033}
2034
2035/*
2036 * return FAIL if there is no file name, OK if there is one
2037 * give error message for FAIL
2038 */
2039 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002040check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002041{
2042 if (curbuf->b_ffname == NULL)
2043 {
2044 EMSG(_(e_noname));
2045 return FAIL;
2046 }
2047 return OK;
2048}
2049
2050/*
2051 * flush the contents of a buffer, unless it has no file name
2052 *
2053 * return FAIL for failure, OK otherwise
2054 */
2055 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002056buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057{
2058 int retval;
2059#ifdef FEAT_AUTOCMD
2060 buf_T *old_curbuf = curbuf;
2061#endif
2062
2063 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2064 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2065 FALSE, forceit, TRUE, FALSE));
2066#ifdef FEAT_AUTOCMD
2067 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002068 {
2069 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002070 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002071 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002072#endif
2073 return retval;
2074}
2075
2076/*
2077 * Code to handle the argument list.
2078 */
2079
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002080static char_u *do_one_arg(char_u *str);
2081static int do_arglist(char_u *str, int what, int after);
2082static void alist_check_arg_idx(void);
2083static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002084#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002085static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002086#endif
2087#define AL_SET 1
2088#define AL_ADD 2
2089#define AL_DEL 3
2090
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002092 * Isolate one argument, taking backticks.
2093 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 * Return a pointer to the start of the next argument.
2095 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002096 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002097do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002098{
2099 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002100 int inbacktick;
2101
Bram Moolenaar071d4272004-06-13 20:20:40 +00002102 inbacktick = FALSE;
2103 for (p = str; *str; ++str)
2104 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002105 /* When the backslash is used for escaping the special meaning of a
2106 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002107 if (rem_backslash(str))
2108 {
2109 *p++ = *str++;
2110 *p++ = *str;
2111 }
2112 else
2113 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002114 /* An item ends at a space not in backticks */
2115 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002117 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002118 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002119 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002120 }
2121 }
2122 str = skipwhite(str);
2123 *p = NUL;
2124
2125 return str;
2126}
2127
Bram Moolenaar86b68352004-12-27 21:59:20 +00002128/*
2129 * Separate the arguments in "str" and return a list of pointers in the
2130 * growarray "gap".
2131 */
2132 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002133get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002134{
2135 ga_init2(gap, (int)sizeof(char_u *), 20);
2136 while (*str != NUL)
2137 {
2138 if (ga_grow(gap, 1) == FAIL)
2139 {
2140 ga_clear(gap);
2141 return FAIL;
2142 }
2143 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2144
2145 /* Isolate one argument, change it in-place, put a NUL after it. */
2146 str = do_one_arg(str);
2147 }
2148 return OK;
2149}
2150
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002151#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002152/*
2153 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002154 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002155 * Return FAIL or OK.
2156 */
2157 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002158get_arglist_exp(
2159 char_u *str,
2160 int *fcountp,
2161 char_u ***fnamesp,
2162 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002163{
2164 garray_T ga;
2165 int i;
2166
2167 if (get_arglist(&ga, str) == FAIL)
2168 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002169 if (wig == TRUE)
2170 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2171 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2172 else
2173 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2174 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2175
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002176 ga_clear(&ga);
2177 return i;
2178}
2179#endif
2180
Bram Moolenaar071d4272004-06-13 20:20:40 +00002181#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2182/*
2183 * Redefine the argument list.
2184 */
2185 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002186set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002187{
2188 do_arglist(str, AL_SET, 0);
2189}
2190#endif
2191
2192/*
2193 * "what" == AL_SET: Redefine the argument list to 'str'.
2194 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2195 * "what" == AL_DEL: remove files in 'str' from the argument list.
2196 *
2197 * Return FAIL for failure, OK otherwise.
2198 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002199 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002200do_arglist(
2201 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002202 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002203 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002204{
2205 garray_T new_ga;
2206 int exp_count;
2207 char_u **exp_files;
2208 int i;
2209#ifdef FEAT_LISTCMDS
2210 char_u *p;
2211 int match;
2212#endif
2213
2214 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002215 * Set default argument for ":argadd" command.
2216 */
2217 if (what == AL_ADD && *str == NUL)
2218 {
2219 if (curbuf->b_ffname == NULL)
2220 return FAIL;
2221 str = curbuf->b_fname;
2222 }
2223
2224 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225 * Collect all file name arguments in "new_ga".
2226 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002227 if (get_arglist(&new_ga, str) == FAIL)
2228 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002229
2230#ifdef FEAT_LISTCMDS
2231 if (what == AL_DEL)
2232 {
2233 regmatch_T regmatch;
2234 int didone;
2235
2236 /*
2237 * Delete the items: use each item as a regexp and find a match in the
2238 * argument list.
2239 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002240 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002241 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2242 {
2243 p = ((char_u **)new_ga.ga_data)[i];
2244 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2245 if (p == NULL)
2246 break;
2247 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2248 if (regmatch.regprog == NULL)
2249 {
2250 vim_free(p);
2251 break;
2252 }
2253
2254 didone = FALSE;
2255 for (match = 0; match < ARGCOUNT; ++match)
2256 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2257 (colnr_T)0))
2258 {
2259 didone = TRUE;
2260 vim_free(ARGLIST[match].ae_fname);
2261 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2262 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2263 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002264 if (curwin->w_arg_idx > match)
2265 --curwin->w_arg_idx;
2266 --match;
2267 }
2268
Bram Moolenaar473de612013-06-08 18:19:48 +02002269 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 vim_free(p);
2271 if (!didone)
2272 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2273 }
2274 ga_clear(&new_ga);
2275 }
2276 else
2277#endif
2278 {
2279 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2280 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2281 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002282 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 {
2284 EMSG(_(e_nomatch));
2285 return FAIL;
2286 }
2287
2288#ifdef FEAT_LISTCMDS
2289 if (what == AL_ADD)
2290 {
2291 (void)alist_add_list(exp_count, exp_files, after);
2292 vim_free(exp_files);
2293 }
2294 else /* what == AL_SET */
2295#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002296 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 }
2298
2299 alist_check_arg_idx();
2300
2301 return OK;
2302}
2303
2304/*
2305 * Check the validity of the arg_idx for each other window.
2306 */
2307 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002308alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309{
2310#ifdef FEAT_WINDOWS
2311 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002312 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002313
Bram Moolenaarf740b292006-02-16 22:11:02 +00002314 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002315 if (win->w_alist == curwin->w_alist)
2316 check_arg_idx(win);
2317#else
2318 check_arg_idx(curwin);
2319#endif
2320}
2321
2322/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002323 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002324 * index.
2325 */
2326 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002327editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002328{
2329 return !(win->w_arg_idx >= WARGCOUNT(win)
2330 || (win->w_buffer->b_fnum
2331 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2332 && (win->w_buffer->b_ffname == NULL
2333 || !(fullpathcmp(
2334 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2335 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2336}
2337
2338/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339 * Check if window "win" is editing the w_arg_idx file in its argument list.
2340 */
2341 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002342check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002343{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002344 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345 {
2346 /* We are not editing the current entry in the argument list.
2347 * Set "arg_had_last" if we are editing the last one. */
2348 win->w_arg_idx_invalid = TRUE;
2349 if (win->w_arg_idx != WARGCOUNT(win) - 1
2350 && arg_had_last == FALSE
2351#ifdef FEAT_WINDOWS
2352 && ALIST(win) == &global_alist
2353#endif
2354 && GARGCOUNT > 0
2355 && win->w_arg_idx < GARGCOUNT
2356 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2357 || (win->w_buffer->b_ffname != NULL
2358 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2359 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2360 arg_had_last = TRUE;
2361 }
2362 else
2363 {
2364 /* We are editing the current entry in the argument list.
2365 * Set "arg_had_last" if it's also the last one */
2366 win->w_arg_idx_invalid = FALSE;
2367 if (win->w_arg_idx == WARGCOUNT(win) - 1
2368#ifdef FEAT_WINDOWS
2369 && win->w_alist == &global_alist
2370#endif
2371 )
2372 arg_had_last = TRUE;
2373 }
2374}
2375
2376/*
2377 * ":args", ":argslocal" and ":argsglobal".
2378 */
2379 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002380ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381{
2382 int i;
2383
2384 if (eap->cmdidx != CMD_args)
2385 {
2386#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2387 alist_unlink(ALIST(curwin));
2388 if (eap->cmdidx == CMD_argglobal)
2389 ALIST(curwin) = &global_alist;
2390 else /* eap->cmdidx == CMD_arglocal */
2391 alist_new();
2392#else
2393 ex_ni(eap);
2394 return;
2395#endif
2396 }
2397
2398 if (!ends_excmd(*eap->arg))
2399 {
2400 /*
2401 * ":args file ..": define new argument list, handle like ":next"
2402 * Also for ":argslocal file .." and ":argsglobal file ..".
2403 */
2404 ex_next(eap);
2405 }
2406 else
2407#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2408 if (eap->cmdidx == CMD_args)
2409#endif
2410 {
2411 /*
2412 * ":args": list arguments.
2413 */
2414 if (ARGCOUNT > 0)
2415 {
2416 /* Overwrite the command, for a short list there is no scrolling
2417 * required and no wait_return(). */
2418 gotocmdline(TRUE);
2419 for (i = 0; i < ARGCOUNT; ++i)
2420 {
2421 if (i == curwin->w_arg_idx)
2422 msg_putchar('[');
2423 msg_outtrans(alist_name(&ARGLIST[i]));
2424 if (i == curwin->w_arg_idx)
2425 msg_putchar(']');
2426 msg_putchar(' ');
2427 }
2428 }
2429 }
2430#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2431 else if (eap->cmdidx == CMD_arglocal)
2432 {
2433 garray_T *gap = &curwin->w_alist->al_ga;
2434
2435 /*
2436 * ":argslocal": make a local copy of the global argument list.
2437 */
2438 if (ga_grow(gap, GARGCOUNT) == OK)
2439 for (i = 0; i < GARGCOUNT; ++i)
2440 if (GARGLIST[i].ae_fname != NULL)
2441 {
2442 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2443 vim_strsave(GARGLIST[i].ae_fname);
2444 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2445 GARGLIST[i].ae_fnum;
2446 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 }
2448 }
2449#endif
2450}
2451
2452/*
2453 * ":previous", ":sprevious", ":Next" and ":sNext".
2454 */
2455 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002456ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457{
2458 /* If past the last one already, go to the last one. */
2459 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2460 do_argfile(eap, ARGCOUNT - 1);
2461 else
2462 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2463}
2464
2465/*
2466 * ":rewind", ":first", ":sfirst" and ":srewind".
2467 */
2468 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002469ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470{
2471 do_argfile(eap, 0);
2472}
2473
2474/*
2475 * ":last" and ":slast".
2476 */
2477 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002478ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479{
2480 do_argfile(eap, ARGCOUNT - 1);
2481}
2482
2483/*
2484 * ":argument" and ":sargument".
2485 */
2486 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002487ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488{
2489 int i;
2490
2491 if (eap->addr_count > 0)
2492 i = eap->line2 - 1;
2493 else
2494 i = curwin->w_arg_idx;
2495 do_argfile(eap, i);
2496}
2497
2498/*
2499 * Edit file "argn" of the argument lists.
2500 */
2501 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002502do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503{
2504 int other;
2505 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002506 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507
2508 if (argn < 0 || argn >= ARGCOUNT)
2509 {
2510 if (ARGCOUNT <= 1)
2511 EMSG(_("E163: There is only one file to edit"));
2512 else if (argn < 0)
2513 EMSG(_("E164: Cannot go before first file"));
2514 else
2515 EMSG(_("E165: Cannot go beyond last file"));
2516 }
2517 else
2518 {
2519 setpcmark();
2520#ifdef FEAT_GUI
2521 need_mouse_correct = TRUE;
2522#endif
2523
2524#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002525 /* split window or create new tab page first */
2526 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527 {
2528 if (win_split(0, 0) == FAIL)
2529 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002530 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531 }
2532 else
2533#endif
2534 {
2535 /*
2536 * if 'hidden' set, only check for changed file when re-editing
2537 * the same buffer
2538 */
2539 other = TRUE;
2540 if (P_HID(curbuf))
2541 {
2542 p = fix_fname(alist_name(&ARGLIST[argn]));
2543 other = otherfile(p);
2544 vim_free(p);
2545 }
2546 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002547 && check_changed(curbuf, CCGD_AW
2548 | (other ? 0 : CCGD_MULTWIN)
2549 | (eap->forceit ? CCGD_FORCEIT : 0)
2550 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002551 return;
2552 }
2553
2554 curwin->w_arg_idx = argn;
2555 if (argn == ARGCOUNT - 1
2556#ifdef FEAT_WINDOWS
2557 && curwin->w_alist == &global_alist
2558#endif
2559 )
2560 arg_had_last = TRUE;
2561
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002562 /* Edit the file; always use the last known line number.
2563 * When it fails (e.g. Abort for already edited file) restore the
2564 * argument index. */
2565 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002566 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002567 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2568 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002569 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002571 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 setmark('\'');
2573 }
2574}
2575
2576/*
2577 * ":next", and commands that behave like it.
2578 */
2579 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002580ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002581{
2582 int i;
2583
2584 /*
2585 * check for changed buffer now, if this fails the argument list is not
2586 * redefined.
2587 */
2588 if ( P_HID(curbuf)
2589 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002590 || !check_changed(curbuf, CCGD_AW
2591 | (eap->forceit ? CCGD_FORCEIT : 0)
2592 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593 {
2594 if (*eap->arg != NUL) /* redefine file list */
2595 {
2596 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2597 return;
2598 i = 0;
2599 }
2600 else
2601 i = curwin->w_arg_idx + (int)eap->line2;
2602 do_argfile(eap, i);
2603 }
2604}
2605
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002606#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607/*
2608 * ":argedit"
2609 */
2610 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002611ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612{
2613 int fnum;
2614 int i;
2615 char_u *s;
2616
2617 /* Add the argument to the buffer list and get the buffer number. */
2618 fnum = buflist_add(eap->arg, BLN_LISTED);
2619
2620 /* Check if this argument is already in the argument list. */
2621 for (i = 0; i < ARGCOUNT; ++i)
2622 if (ARGLIST[i].ae_fnum == fnum)
2623 break;
2624 if (i == ARGCOUNT)
2625 {
2626 /* Can't find it, add it to the argument list. */
2627 s = vim_strsave(eap->arg);
2628 if (s == NULL)
2629 return;
2630 i = alist_add_list(1, &s,
2631 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2632 if (i < 0)
2633 return;
2634 curwin->w_arg_idx = i;
2635 }
2636
2637 alist_check_arg_idx();
2638
2639 /* Edit the argument. */
2640 do_argfile(eap, i);
2641}
2642
2643/*
2644 * ":argadd"
2645 */
2646 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002647ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648{
2649 do_arglist(eap->arg, AL_ADD,
2650 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2651#ifdef FEAT_TITLE
2652 maketitle();
2653#endif
2654}
2655
2656/*
2657 * ":argdelete"
2658 */
2659 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002660ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661{
2662 int i;
2663 int n;
2664
2665 if (eap->addr_count > 0)
2666 {
2667 /* ":1,4argdel": Delete all arguments in the range. */
2668 if (eap->line2 > ARGCOUNT)
2669 eap->line2 = ARGCOUNT;
2670 n = eap->line2 - eap->line1 + 1;
2671 if (*eap->arg != NUL || n <= 0)
2672 EMSG(_(e_invarg));
2673 else
2674 {
2675 for (i = eap->line1; i <= eap->line2; ++i)
2676 vim_free(ARGLIST[i - 1].ae_fname);
2677 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2678 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2679 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680 if (curwin->w_arg_idx >= eap->line2)
2681 curwin->w_arg_idx -= n;
2682 else if (curwin->w_arg_idx > eap->line1)
2683 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002684 if (ARGCOUNT == 0)
2685 curwin->w_arg_idx = 0;
2686 else if (curwin->w_arg_idx >= ARGCOUNT)
2687 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688 }
2689 }
2690 else if (*eap->arg == NUL)
2691 EMSG(_(e_argreq));
2692 else
2693 do_arglist(eap->arg, AL_DEL, 0);
2694#ifdef FEAT_TITLE
2695 maketitle();
2696#endif
2697}
2698
2699/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002700 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002701 */
2702 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002703ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002704{
2705 int i;
2706#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002707 win_T *wp;
2708 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002710 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711 int next_fnum = 0;
2712#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2713 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002715 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002716#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002717 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002718 int qf_idx;
2719#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720
2721#ifndef FEAT_WINDOWS
2722 if (eap->cmdidx == CMD_windo)
2723 {
2724 ex_ni(eap);
2725 return;
2726 }
2727#endif
2728
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002729#ifndef FEAT_QUICKFIX
2730 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2731 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2732 {
2733 ex_ni(eap);
2734 return;
2735 }
2736#endif
2737
Bram Moolenaar071d4272004-06-13 20:20:40 +00002738#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002739 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002740 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2741 * great speed improvement. */
2742 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002744#ifdef FEAT_CLIPBOARD
2745 start_global_changes();
2746#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747
2748 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002749 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002750 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002751 || !check_changed(curbuf, CCGD_AW
2752 | (eap->forceit ? CCGD_FORCEIT : 0)
2753 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002756 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002758 wp = firstwin;
2759 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002760#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002761 switch (eap->cmdidx)
2762 {
2763#ifdef FEAT_WINDOWS
2764 case CMD_windo:
2765 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2766 i++;
2767 break;
2768 case CMD_tabdo:
2769 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2770 i++;
2771 break;
2772#endif
2773 case CMD_argdo:
2774 i = eap->line1 - 1;
2775 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002776 default:
2777 break;
2778 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779 /* set pcmark now */
2780 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002781 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002782 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002783 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002784 || !buf->b_p_bl); buf = buf->b_next)
2785 if (buf->b_fnum > eap->line2)
2786 {
2787 buf = NULL;
2788 break;
2789 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002790 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002791 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002792 }
2793#ifdef FEAT_QUICKFIX
2794 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2795 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2796 {
2797 qf_size = qf_get_size(eap);
2798 if (qf_size <= 0 || eap->line1 > qf_size)
2799 buf = NULL;
2800 else
2801 {
2802 ex_cc(eap);
2803
2804 buf = curbuf;
2805 i = eap->line1 - 1;
2806 if (eap->addr_count <= 0)
2807 /* default is all the quickfix/location list entries */
2808 eap->line2 = qf_size;
2809 }
2810 }
2811#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812 else
2813 setpcmark();
2814 listcmd_busy = TRUE; /* avoids setting pcmark below */
2815
Bram Moolenaare25bb902015-02-27 20:33:37 +01002816 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817 {
2818 if (eap->cmdidx == CMD_argdo)
2819 {
2820 /* go to argument "i" */
2821 if (i == ARGCOUNT)
2822 break;
2823 /* Don't call do_argfile() when already there, it will try
2824 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002825 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002826 {
2827 /* Clear 'shm' to avoid that the file message overwrites
2828 * any output from the command. */
2829 p_shm_save = vim_strsave(p_shm);
2830 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002831 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002832 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2833 vim_free(p_shm_save);
2834 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835 if (curwin->w_arg_idx != i)
2836 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837 }
2838#ifdef FEAT_WINDOWS
2839 else if (eap->cmdidx == CMD_windo)
2840 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002841 /* go to window "wp" */
2842 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002844 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002845 if (curwin != wp)
2846 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002847 wp = curwin->w_next;
2848 }
2849 else if (eap->cmdidx == CMD_tabdo)
2850 {
2851 /* go to window "tp" */
2852 if (!valid_tabpage(tp))
2853 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002854 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002855 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002856 }
2857#endif
2858 else if (eap->cmdidx == CMD_bufdo)
2859 {
2860 /* Remember the number of the next listed buffer, in case
2861 * ":bwipe" is used or autocommands do something strange. */
2862 next_fnum = -1;
2863 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2864 if (buf->b_p_bl)
2865 {
2866 next_fnum = buf->b_fnum;
2867 break;
2868 }
2869 }
2870
Bram Moolenaara162bc52015-01-07 16:54:21 +01002871 ++i;
2872
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873 /* execute the command */
2874 do_cmdline(eap->arg, eap->getline, eap->cookie,
2875 DOCMD_VERBOSE + DOCMD_NOWAIT);
2876
2877 if (eap->cmdidx == CMD_bufdo)
2878 {
2879 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002880 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881 break;
2882 /* Check if the buffer still exists. */
2883 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2884 if (buf->b_fnum == next_fnum)
2885 break;
2886 if (buf == NULL)
2887 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002888
2889 /* Go to the next buffer. Clear 'shm' to avoid that the file
2890 * message overwrites any output from the command. */
2891 p_shm_save = vim_strsave(p_shm);
2892 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002894 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2895 vim_free(p_shm_save);
2896
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002897 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898 if (curbuf->b_fnum != next_fnum)
2899 break;
2900 }
2901
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002902#ifdef FEAT_QUICKFIX
2903 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2904 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2905 {
2906 if (i >= qf_size || i >= eap->line2)
2907 break;
2908
2909 qf_idx = qf_get_cur_idx(eap);
2910
2911 ex_cnext(eap);
2912
2913 /* If jumping to the next quickfix entry fails, quit here */
2914 if (qf_get_cur_idx(eap) == qf_idx)
2915 break;
2916 }
2917#endif
2918
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919 if (eap->cmdidx == CMD_windo)
2920 {
2921 validate_cursor(); /* cursor may have moved */
2922#ifdef FEAT_SCROLLBIND
2923 /* required when 'scrollbind' has been set */
2924 if (curwin->w_p_scb)
2925 do_check_scrollbind(TRUE);
2926#endif
2927 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002928
2929#ifdef FEAT_WINDOWS
2930 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2931 if (i+1 > eap->line2)
2932 break;
2933#endif
2934 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2935 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936 }
2937 listcmd_busy = FALSE;
2938 }
2939
2940#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002941 if (save_ei != NULL)
2942 {
2943 au_event_restore(save_ei);
2944 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2945 curbuf->b_fname, TRUE, curbuf);
2946 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002948#ifdef FEAT_CLIPBOARD
2949 end_global_changes();
2950#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951}
2952
2953/*
2954 * Add files[count] to the arglist of the current window after arg "after".
2955 * The file names in files[count] must have been allocated and are taken over.
2956 * Files[] itself is not taken over.
2957 * Returns index of first added argument. Returns -1 when failed (out of mem).
2958 */
2959 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002960alist_add_list(
2961 int count,
2962 char_u **files,
2963 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002964{
2965 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002966 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967
2968 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2969 {
2970 if (after < 0)
2971 after = 0;
2972 if (after > ARGCOUNT)
2973 after = ARGCOUNT;
2974 if (after < ARGCOUNT)
2975 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2976 (ARGCOUNT - after) * sizeof(aentry_T));
2977 for (i = 0; i < count; ++i)
2978 {
2979 ARGLIST[after + i].ae_fname = files[i];
2980 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2981 }
2982 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002983 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2984 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002985 return after;
2986 }
2987
2988 for (i = 0; i < count; ++i)
2989 vim_free(files[i]);
2990 return -1;
2991}
2992
2993#endif /* FEAT_LISTCMDS */
2994
2995#ifdef FEAT_EVAL
2996/*
2997 * ":compiler[!] {name}"
2998 */
2999 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003000ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003001{
3002 char_u *buf;
3003 char_u *old_cur_comp = NULL;
3004 char_u *p;
3005
3006 if (*eap->arg == NUL)
3007 {
3008 /* List all compiler scripts. */
3009 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3010 /* ) keep the indenter happy... */
3011 }
3012 else
3013 {
3014 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3015 if (buf != NULL)
3016 {
3017 if (eap->forceit)
3018 {
3019 /* ":compiler! {name}" sets global options */
3020 do_cmdline_cmd((char_u *)
3021 "command -nargs=* CompilerSet set <args>");
3022 }
3023 else
3024 {
3025 /* ":compiler! {name}" sets local options.
3026 * To remain backwards compatible "current_compiler" is always
3027 * used. A user's compiler plugin may set it, the distributed
3028 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003029 * "b:current_compiler" and restore "current_compiler".
3030 * Explicitly prepend "g:" to make it work in a function. */
3031 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032 if (old_cur_comp != NULL)
3033 old_cur_comp = vim_strsave(old_cur_comp);
3034 do_cmdline_cmd((char_u *)
3035 "command -nargs=* CompilerSet setlocal <args>");
3036 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003037 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003038 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003039
3040 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003041 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3043 vim_free(buf);
3044
3045 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3046
3047 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003048 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049 if (p != NULL)
3050 set_internal_string_var((char_u *)"b:current_compiler", p);
3051
3052 /* Restore "current_compiler" for ":compiler {name}". */
3053 if (!eap->forceit)
3054 {
3055 if (old_cur_comp != NULL)
3056 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003057 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058 old_cur_comp);
3059 vim_free(old_cur_comp);
3060 }
3061 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003062 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003063 }
3064 }
3065 }
3066}
3067#endif
3068
3069/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003070 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 */
3072 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003073ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003075 char_u *arg = eap->arg;
3076 char_u *p = skiptowhite(arg);
3077 int len = (int)(p - arg);
3078 int flags = eap->forceit ? DIP_ALL : 0;
3079
3080 if (STRNCMP(arg, "START", len) == 0)
3081 {
3082 flags += DIP_START + DIP_NORTP;
3083 arg = skipwhite(arg + len);
3084 }
3085 else if (STRNCMP(arg, "OPT", len) == 0)
3086 {
3087 flags += DIP_OPT + DIP_NORTP;
3088 arg = skipwhite(arg + len);
3089 }
3090 else if (STRNCMP(arg, "PACK", len) == 0)
3091 {
3092 flags += DIP_START + DIP_OPT + DIP_NORTP;
3093 arg = skipwhite(arg + len);
3094 }
3095 else if (STRNCMP(arg, "ALL", len) == 0)
3096 {
3097 flags += DIP_START + DIP_OPT;
3098 arg = skipwhite(arg + len);
3099 }
3100
3101 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003102}
3103
Bram Moolenaar071d4272004-06-13 20:20:40 +00003104 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003105source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003107 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003108}
3109
3110/*
3111 * Source the file "name" from all directories in 'runtimepath'.
3112 * "name" can contain wildcards.
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003113 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
Bram Moolenaar91715872016-03-03 17:13:03 +01003114 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003115 * return FAIL when no file could be sourced, OK otherwise.
3116 */
3117 int
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003118source_runtime(char_u *name, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003119{
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003120 return do_in_runtimepath(name, flags, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003121}
3122
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003123/*
3124 * Find the file "name" in all directories in "path" and invoke
3125 * "callback(fname, cookie)".
3126 * "name" can contain wildcards.
3127 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3128 * When "flags" has DIP_DIR: find directories instead of files.
3129 * When "flags" has DIP_ERR: give an error message if there is no match.
3130 *
3131 * return FAIL when no file could be sourced, OK otherwise.
3132 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003133 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003134do_in_path(
3135 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003136 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003137 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003138 void (*callback)(char_u *fname, void *ck),
3139 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003140{
3141 char_u *rtp;
3142 char_u *np;
3143 char_u *buf;
3144 char_u *rtp_copy;
3145 char_u *tail;
3146 int num_files;
3147 char_u **files;
3148 int i;
3149 int did_one = FALSE;
3150#ifdef AMIGA
3151 struct Process *proc = (struct Process *)FindTask(0L);
3152 APTR save_winptr = proc->pr_WindowPtr;
3153
3154 /* Avoid a requester here for a volume that doesn't exist. */
3155 proc->pr_WindowPtr = (APTR)-1L;
3156#endif
3157
3158 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3159 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003160 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003161 buf = alloc(MAXPATHL);
3162 if (buf != NULL && rtp_copy != NULL)
3163 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003164 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003165 {
3166 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003167 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003168 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003169 verbose_leave();
3170 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003171
Bram Moolenaar071d4272004-06-13 20:20:40 +00003172 /* Loop over all entries in 'runtimepath'. */
3173 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003174 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003175 {
3176 /* Copy the path from 'runtimepath' to buf[]. */
3177 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003178 if (name == NULL)
3179 {
3180 (*callback)(buf, (void *) &cookie);
3181 if (!did_one)
3182 did_one = (cookie == NULL);
3183 }
3184 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003185 {
3186 add_pathsep(buf);
3187 tail = buf + STRLEN(buf);
3188
3189 /* Loop over all patterns in "name" */
3190 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003191 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192 {
3193 /* Append the pattern from "name" to buf[]. */
3194 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3195 "\t ");
3196
3197 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003198 {
3199 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003200 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003201 verbose_leave();
3202 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003203
3204 /* Expand wildcards, invoke the callback for each match. */
3205 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003206 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003207 {
3208 for (i = 0; i < num_files; ++i)
3209 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003210 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003212 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213 break;
3214 }
3215 FreeWild(num_files, files);
3216 }
3217 }
3218 }
3219 }
3220 }
3221 vim_free(buf);
3222 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003223 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003224 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003225 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3226
3227 if (flags & DIP_ERR)
3228 EMSG3(_(e_dirnotf), basepath, name);
3229 else if (p_verbose > 0)
3230 {
3231 verbose_enter();
3232 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3233 verbose_leave();
3234 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003235 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236
3237#ifdef AMIGA
3238 proc->pr_WindowPtr = save_winptr;
3239#endif
3240
3241 return did_one ? OK : FAIL;
3242}
3243
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003244/*
3245 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3246 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003247 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3248 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003249 * Returns OK when at least one match found, FAIL otherwise.
3250 *
3251 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3252 * passed by reference in this case, setting it to NULL indicates that callback
3253 * has done its job.
3254 */
3255 int
3256do_in_runtimepath(
3257 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003258 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003259 void (*callback)(char_u *fname, void *ck),
3260 void *cookie)
3261{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003262 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003263 char_u *s;
3264 int len;
3265 char *start_dir = "pack/*/start/*/%s";
3266 char *opt_dir = "pack/*/opt/*/%s";
3267
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003268 if ((flags & DIP_NORTP) == 0)
3269 done = do_in_path(p_rtp, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003270
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003271 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003272 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003273 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003274 s = alloc(len);
3275 if (s == NULL)
3276 return FAIL;
3277 vim_snprintf((char *)s, len, start_dir, name);
3278 done = do_in_path(p_pp, s, flags, callback, cookie);
3279 vim_free(s);
3280 }
3281
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003282 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003283 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003284 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003285 s = alloc(len);
3286 if (s == NULL)
3287 return FAIL;
3288 vim_snprintf((char *)s, len, opt_dir, name);
3289 done = do_in_path(p_pp, s, flags, callback, cookie);
3290 vim_free(s);
3291 }
3292
3293 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003294}
3295
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003296/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003297 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003298 */
3299 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003300source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003301{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003302 int num_files;
3303 char_u **files;
3304 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003305
Bram Moolenaarf3654822016-03-04 22:12:23 +01003306 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003307 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003308 for (i = 0; i < num_files; ++i)
3309 (void)do_source(files[i], FALSE, DOSO_NONE);
3310 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003311 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003312}
3313
Bram Moolenaar49b27322016-04-05 21:13:00 +02003314/* used for "cookie" of add_pack_plugin() */
3315static int APP_ADD_DIR;
3316static int APP_LOAD;
3317static int APP_BOTH;
3318
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003319 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003320add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003321{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003322 char_u *p4, *p3, *p2, *p1, *p;
3323 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003324 int c;
3325 char_u *new_rtp;
3326 int keep;
3327 int oldlen;
3328 int addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003329 char_u *afterdir;
3330 int afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003331 char_u *ffname = fix_fname(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003332
Bram Moolenaar91715872016-03-03 17:13:03 +01003333 if (ffname == NULL)
3334 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003335 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003336 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003337 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003338 p4 = p3 = p2 = p1 = get_past_head(ffname);
3339 for (p = p1; *p; mb_ptr_adv(p))
3340 if (vim_ispathsep_nocolon(*p))
3341 {
3342 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3343 }
3344
3345 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003346 * rtp/pack/name/start/name
3347 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003348 *
3349 * find the part up to "pack" in 'runtimepath' */
3350 c = *p4;
3351 *p4 = NUL;
3352 insp = (char_u *)strstr((char *)p_rtp, (char *)ffname);
3353 if (insp == NULL)
3354 /* not found, append at the end */
3355 insp = p_rtp + STRLEN(p_rtp);
3356 else
3357 {
3358 /* append after the matching directory. */
3359 insp += STRLEN(ffname);
3360 while (*insp != NUL && *insp != ',')
3361 ++insp;
3362 }
3363 *p4 = c;
3364
Bram Moolenaara5702442016-05-24 19:37:29 +02003365 /* check if rtp/pack/name/start/name/after exists */
3366 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3367 if (afterdir != NULL && mch_isdir(afterdir))
3368 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3369
Bram Moolenaar1daae442016-02-22 23:25:25 +01003370 oldlen = (int)STRLEN(p_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003371 addlen = (int)STRLEN(ffname) + 1; /* add one for comma */
3372 new_rtp = alloc(oldlen + addlen + afterlen + 1); /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003373 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003374 goto theend;
3375 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003376 mch_memmove(new_rtp, p_rtp, keep);
3377 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003378 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003379 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003380 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003381 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003382 if (afterlen > 0)
3383 {
3384 STRCAT(new_rtp, ",");
3385 STRCAT(new_rtp, afterdir);
3386 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003387 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3388 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003389 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003390 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003391
Bram Moolenaar49b27322016-04-05 21:13:00 +02003392 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003393 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003394 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003395 static char *ftpat = "%s/ftdetect/*.vim";
3396 int len;
3397 char_u *pat;
3398
3399 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3400 pat = alloc(len);
3401 if (pat == NULL)
3402 goto theend;
3403 vim_snprintf((char *)pat, len, plugpat, ffname);
3404 source_all_matches(pat);
3405
3406#ifdef FEAT_AUTOCMD
3407 {
3408 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3409
3410 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3411 * found when it loads. */
3412 if (cmd != NULL && eval_to_number(cmd) > 0)
3413 {
3414 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3415 vim_snprintf((char *)pat, len, ftpat, ffname);
3416 source_all_matches(pat);
3417 do_cmdline_cmd((char_u *)"augroup END");
3418 }
3419 vim_free(cmd);
3420 }
3421#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003422 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003423 }
3424
3425theend:
3426 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003427}
3428
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003429static int did_source_packages = FALSE;
3430
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003431/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003432 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003433 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003434 */
3435 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003436ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003437{
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003438 if (!did_source_packages || (eap != NULL && eap->forceit))
3439 {
3440 did_source_packages = TRUE;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003441
3442 /* First do a round to add all directories to 'runtimepath', then load
3443 * the plugins. This allows for plugins to use an autoload directory
3444 * of another plugin. */
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003445 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003446 add_pack_plugin, &APP_ADD_DIR);
3447 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3448 add_pack_plugin, &APP_LOAD);
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003449 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003450}
3451
3452/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003453 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003454 */
3455 void
3456ex_packadd(exarg_T *eap)
3457{
3458 static char *plugpat = "pack/*/opt/%s";
3459 int len;
3460 char *pat;
3461
3462 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3463 pat = (char *)alloc(len);
3464 if (pat == NULL)
3465 return;
3466 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003467 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003468 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003469 vim_free(pat);
3470}
3471
Bram Moolenaar071d4272004-06-13 20:20:40 +00003472#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3473/*
3474 * ":options"
3475 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003477ex_options(
3478 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003479{
3480 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3481}
3482#endif
3483
3484/*
3485 * ":source {fname}"
3486 */
3487 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003488ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003489{
3490#ifdef FEAT_BROWSE
3491 if (cmdmod.browse)
3492 {
3493 char_u *fname = NULL;
3494
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003495 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003496 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3497 if (fname != NULL)
3498 {
3499 cmd_source(fname, eap);
3500 vim_free(fname);
3501 }
3502 }
3503 else
3504#endif
3505 cmd_source(eap->arg, eap);
3506}
3507
3508 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003509cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510{
3511 if (*fname == NUL)
3512 EMSG(_(e_argreq));
3513
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003515 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003516 * Need to execute the commands directly. This is required at least
3517 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518 * - ":g" command busy
3519 * - after ":argdo", ":windo" or ":bufdo"
3520 * - another command follows
3521 * - inside a loop
3522 */
3523 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3524#ifdef FEAT_EVAL
3525 || eap->cstack->cs_idx >= 0
3526#endif
3527 );
3528
3529 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003530 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531 EMSG2(_(e_notopen), fname);
3532}
3533
3534/*
3535 * ":source" and associated commands.
3536 */
3537/*
3538 * Structure used to store info for each sourced file.
3539 * It is shared between do_source() and getsourceline().
3540 * This is required, because it needs to be handed to do_cmdline() and
3541 * sourcing can be done recursively.
3542 */
3543struct source_cookie
3544{
3545 FILE *fp; /* opened file for sourcing */
3546 char_u *nextline; /* if not NULL: line that was read ahead */
3547 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003548#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003549 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3550 int error; /* TRUE if LF found after CR-LF */
3551#endif
3552#ifdef FEAT_EVAL
3553 linenr_T breakpoint; /* next line with breakpoint or zero */
3554 char_u *fname; /* name of sourced file */
3555 int dbg_tick; /* debug_tick when breakpoint was set */
3556 int level; /* top nesting level of sourced file */
3557#endif
3558#ifdef FEAT_MBYTE
3559 vimconv_T conv; /* type of conversion */
3560#endif
3561};
3562
3563#ifdef FEAT_EVAL
3564/*
3565 * Return the address holding the next breakpoint line for a source cookie.
3566 */
3567 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003568source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569{
3570 return &((struct source_cookie *)cookie)->breakpoint;
3571}
3572
3573/*
3574 * Return the address holding the debug tick for a source cookie.
3575 */
3576 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003577source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578{
3579 return &((struct source_cookie *)cookie)->dbg_tick;
3580}
3581
3582/*
3583 * Return the nesting level for a source cookie.
3584 */
3585 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003586source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003587{
3588 return ((struct source_cookie *)cookie)->level;
3589}
3590#endif
3591
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003592static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003594#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3595# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003596static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597
3598/*
3599 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003600 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003601 */
3602 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003603fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003604{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003605# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003606 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3607# else
3608 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003609# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003610
3611 if (fd_tmp == -1)
3612 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003613
3614# ifdef HAVE_FD_CLOEXEC
3615 {
3616 int fdflags = fcntl(fd_tmp, F_GETFD);
3617 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003618 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003619 }
3620# endif
3621
Bram Moolenaar071d4272004-06-13 20:20:40 +00003622 return fdopen(fd_tmp, READBIN);
3623}
3624#endif
3625
3626
3627/*
3628 * do_source: Read the file "fname" and execute its lines as EX commands.
3629 *
3630 * This function may be called recursively!
3631 *
3632 * return FAIL if file could not be opened, OK otherwise
3633 */
3634 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003635do_source(
3636 char_u *fname,
3637 int check_other, /* check for .vimrc and _vimrc */
3638 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003639{
3640 struct source_cookie cookie;
3641 char_u *save_sourcing_name;
3642 linenr_T save_sourcing_lnum;
3643 char_u *p;
3644 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003645 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646 int retval = FAIL;
3647#ifdef FEAT_EVAL
3648 scid_T save_current_SID;
3649 static scid_T last_current_SID = 0;
3650 void *save_funccalp;
3651 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003652 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003653# ifdef UNIX
3654 struct stat st;
3655 int stat_ok;
3656# endif
3657#endif
3658#ifdef STARTUPTIME
3659 struct timeval tv_rel;
3660 struct timeval tv_start;
3661#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003662#ifdef FEAT_PROFILE
3663 proftime_T wait_start;
3664#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665
Bram Moolenaar071d4272004-06-13 20:20:40 +00003666 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667 if (p == NULL)
3668 return retval;
3669 fname_exp = fix_fname(p);
3670 vim_free(p);
3671 if (fname_exp == NULL)
3672 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673 if (mch_isdir(fname_exp))
3674 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003675 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676 goto theend;
3677 }
3678
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003679#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003680 /* Apply SourceCmd autocommands, they should get the file and source it. */
3681 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3682 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3683 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003684 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003685# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003686 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003687# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003688 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003689# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003690 goto theend;
3691 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003692
3693 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003694 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3695#endif
3696
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003697#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003698 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3699#else
3700 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3701#endif
3702 if (cookie.fp == NULL && check_other)
3703 {
3704 /*
3705 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3706 * and ".exrc" by "_exrc" or vice versa.
3707 */
3708 p = gettail(fname_exp);
3709 if ((*p == '.' || *p == '_')
3710 && (STRICMP(p + 1, "vimrc") == 0
3711 || STRICMP(p + 1, "gvimrc") == 0
3712 || STRICMP(p + 1, "exrc") == 0))
3713 {
3714 if (*p == '_')
3715 *p = '.';
3716 else
3717 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003718#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003719 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3720#else
3721 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3722#endif
3723 }
3724 }
3725
3726 if (cookie.fp == NULL)
3727 {
3728 if (p_verbose > 0)
3729 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003730 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003732 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733 else
3734 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003735 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003736 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737 }
3738 goto theend;
3739 }
3740
3741 /*
3742 * The file exists.
3743 * - In verbose mode, give a message.
3744 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3745 */
3746 if (p_verbose > 1)
3747 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003748 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003750 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 else
3752 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003753 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003754 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003756 if (is_vimrc == DOSO_VIMRC)
3757 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3758 else if (is_vimrc == DOSO_GVIMRC)
3759 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003760
3761#ifdef USE_CRNL
3762 /* If no automatic file format: Set default to CR-NL. */
3763 if (*p_ffs == NUL)
3764 cookie.fileformat = EOL_DOS;
3765 else
3766 cookie.fileformat = EOL_UNKNOWN;
3767 cookie.error = FALSE;
3768#endif
3769
3770#ifdef USE_CR
3771 /* If no automatic file format: Set default to CR. */
3772 if (*p_ffs == NUL)
3773 cookie.fileformat = EOL_MAC;
3774 else
3775 cookie.fileformat = EOL_UNKNOWN;
3776 cookie.error = FALSE;
3777#endif
3778
3779 cookie.nextline = NULL;
3780 cookie.finished = FALSE;
3781
3782#ifdef FEAT_EVAL
3783 /*
3784 * Check if this script has a breakpoint.
3785 */
3786 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3787 cookie.fname = fname_exp;
3788 cookie.dbg_tick = debug_tick;
3789
3790 cookie.level = ex_nesting_level;
3791#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003792
3793 /*
3794 * Keep the sourcing name/lnum, for recursive calls.
3795 */
3796 save_sourcing_name = sourcing_name;
3797 sourcing_name = fname_exp;
3798 save_sourcing_lnum = sourcing_lnum;
3799 sourcing_lnum = 0;
3800
Bram Moolenaar73881402009-02-04 16:50:47 +00003801#ifdef FEAT_MBYTE
3802 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3803
3804 /* Read the first line so we can check for a UTF-8 BOM. */
3805 firstline = getsourceline(0, (void *)&cookie, 0);
3806 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3807 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3808 {
3809 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3810 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3811 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003812 if (p == NULL)
3813 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003814 if (p != NULL)
3815 {
3816 vim_free(firstline);
3817 firstline = p;
3818 }
3819 }
3820#endif
3821
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003823 if (time_fd != NULL)
3824 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825#endif
3826
3827#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003828# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003829 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003830 prof_child_enter(&wait_start); /* entering a child now */
3831# endif
3832
3833 /* Don't use local function variables, if called from a function.
3834 * Also starts profiling timer for nested script. */
3835 save_funccalp = save_funccal();
3836
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 /*
3838 * Check if this script was sourced before to finds its SID.
3839 * If it's new, generate a new SID.
3840 */
3841 save_current_SID = current_SID;
3842# ifdef UNIX
3843 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3844# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003845 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3846 {
3847 si = &SCRIPT_ITEM(current_SID);
3848 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849 && (
3850# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003851 /* Compare dev/ino when possible, it catches symbolic
3852 * links. Also compare file names, the inode may change
3853 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003854 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003855 && (si->sn_dev == st.st_dev
3856 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003857# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003858 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003859 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003860 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003861 if (current_SID == 0)
3862 {
3863 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003864 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3865 == FAIL)
3866 goto almosttheend;
3867 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003869 ++script_items.ga_len;
3870 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3871# ifdef FEAT_PROFILE
3872 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003875 si = &SCRIPT_ITEM(current_SID);
3876 si->sn_name = fname_exp;
3877 fname_exp = NULL;
3878# ifdef UNIX
3879 if (stat_ok)
3880 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003881 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003882 si->sn_dev = st.st_dev;
3883 si->sn_ino = st.st_ino;
3884 }
3885 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003886 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003887# endif
3888
Bram Moolenaar071d4272004-06-13 20:20:40 +00003889 /* Allocate the local script variables to use for this script. */
3890 new_script_vars(current_SID);
3891 }
3892
Bram Moolenaar05159a02005-02-26 23:04:13 +00003893# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003894 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003895 {
3896 int forceit;
3897
3898 /* Check if we do profiling for this script. */
3899 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3900 {
3901 script_do_profile(si);
3902 si->sn_pr_force = forceit;
3903 }
3904 if (si->sn_prof_on)
3905 {
3906 ++si->sn_pr_count;
3907 profile_start(&si->sn_pr_start);
3908 profile_zero(&si->sn_pr_children);
3909 }
3910 }
3911# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003912#endif
3913
3914 /*
3915 * Call do_cmdline, which will call getsourceline() to get the lines.
3916 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003917 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003918 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003919 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003920
3921#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003922 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003923 {
3924 /* Get "si" again, "script_items" may have been reallocated. */
3925 si = &SCRIPT_ITEM(current_SID);
3926 if (si->sn_prof_on)
3927 {
3928 profile_end(&si->sn_pr_start);
3929 profile_sub_wait(&wait_start, &si->sn_pr_start);
3930 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003931 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3932 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003933 }
3934 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003935#endif
3936
3937 if (got_int)
3938 EMSG(_(e_interr));
3939 sourcing_name = save_sourcing_name;
3940 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003941 if (p_verbose > 1)
3942 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003943 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003944 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003945 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003946 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003947 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948 }
3949#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003950 if (time_fd != NULL)
3951 {
3952 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3953 time_msg((char *)IObuff, &tv_start);
3954 time_pop(&tv_rel);
3955 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003956#endif
3957
3958#ifdef FEAT_EVAL
3959 /*
3960 * After a "finish" in debug mode, need to break at first command of next
3961 * sourced file.
3962 */
3963 if (save_debug_break_level > ex_nesting_level
3964 && debug_break_level == ex_nesting_level)
3965 ++debug_break_level;
3966#endif
3967
Bram Moolenaar05159a02005-02-26 23:04:13 +00003968#ifdef FEAT_EVAL
3969almosttheend:
3970 current_SID = save_current_SID;
3971 restore_funccal(save_funccalp);
3972# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003973 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003974 prof_child_exit(&wait_start); /* leaving a child now */
3975# endif
3976#endif
3977 fclose(cookie.fp);
3978 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003979 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003980#ifdef FEAT_MBYTE
3981 convert_setup(&cookie.conv, NULL, NULL);
3982#endif
3983
Bram Moolenaar071d4272004-06-13 20:20:40 +00003984theend:
3985 vim_free(fname_exp);
3986 return retval;
3987}
3988
3989#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003990
Bram Moolenaar071d4272004-06-13 20:20:40 +00003991/*
3992 * ":scriptnames"
3993 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003995ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003996{
3997 int i;
3998
Bram Moolenaar05159a02005-02-26 23:04:13 +00003999 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4000 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004001 {
4002 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4003 NameBuff, MAXPATHL, TRUE);
4004 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004005 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004006}
4007
4008# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4009/*
4010 * Fix slashes in the list of script names for 'shellslash'.
4011 */
4012 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004013scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014{
4015 int i;
4016
Bram Moolenaar05159a02005-02-26 23:04:13 +00004017 for (i = 1; i <= script_items.ga_len; ++i)
4018 if (SCRIPT_ITEM(i).sn_name != NULL)
4019 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004020}
4021# endif
4022
4023/*
4024 * Get a pointer to a script name. Used for ":verbose set".
4025 */
4026 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004027get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028{
4029 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004030 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004031 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004032 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004034 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004035 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004036 return (char_u *)_("environment variable");
4037 if (id == SID_ERROR)
4038 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004039 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004041
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004042# if defined(EXITFREE) || defined(PROTO)
4043 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004044free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004045{
4046 int i;
4047
4048 for (i = script_items.ga_len; i > 0; --i)
4049 vim_free(SCRIPT_ITEM(i).sn_name);
4050 ga_clear(&script_items);
4051}
4052# endif
4053
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054#endif
4055
4056#if defined(USE_CR) || defined(PROTO)
4057
4058# if defined(__MSL__) && (__MSL__ >= 22)
4059/*
4060 * Newer version of the Metrowerks library handle DOS and UNIX files
4061 * without help.
4062 * Test with earlier versions, MSL 2.2 is the library supplied with
4063 * Codewarrior Pro 2.
4064 */
4065 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004066fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004067{
4068 return fgets(s, n, stream);
4069}
4070# else
4071/*
4072 * Version of fgets() which also works for lines ending in a <CR> only
4073 * (Macintosh format).
4074 * For older versions of the Metrowerks library.
4075 * At least CodeWarrior 9 needed this code.
4076 */
4077 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004078fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004079{
4080 int c = 0;
4081 int char_read = 0;
4082
4083 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4084 {
4085 c = fgetc(stream);
4086 s[char_read++] = c;
4087 /* If the file is in DOS format, we need to skip a NL after a CR. I
4088 * thought it was the other way around, but this appears to work... */
4089 if (c == '\n')
4090 {
4091 c = fgetc(stream);
4092 if (c != '\r')
4093 ungetc(c, stream);
4094 }
4095 }
4096
4097 s[char_read] = 0;
4098 if (char_read == 0)
4099 return NULL;
4100
4101 if (feof(stream) && char_read == 1)
4102 return NULL;
4103
4104 return s;
4105}
4106# endif
4107#endif
4108
4109/*
4110 * Get one full line from a sourced file.
4111 * Called by do_cmdline() when it's called from do_source().
4112 *
4113 * Return a pointer to the line in allocated memory.
4114 * Return NULL for end-of-file or some error.
4115 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004116 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004117getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118{
4119 struct source_cookie *sp = (struct source_cookie *)cookie;
4120 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004121 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122
4123#ifdef FEAT_EVAL
4124 /* If breakpoints have been added/deleted need to check for it. */
4125 if (sp->dbg_tick < debug_tick)
4126 {
4127 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4128 sp->dbg_tick = debug_tick;
4129 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004130# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004131 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004132 script_line_end();
4133# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004134#endif
4135 /*
4136 * Get current line. If there is a read-ahead line, use it, otherwise get
4137 * one now.
4138 */
4139 if (sp->finished)
4140 line = NULL;
4141 else if (sp->nextline == NULL)
4142 line = get_one_sourceline(sp);
4143 else
4144 {
4145 line = sp->nextline;
4146 sp->nextline = NULL;
4147 ++sourcing_lnum;
4148 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004149#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004150 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004151 script_line_start();
4152#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004153
4154 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4155 * contain the 'C' flag. */
4156 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4157 {
4158 /* compensate for the one line read-ahead */
4159 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004160
4161 /* Get the next line and concatenate it when it starts with a
4162 * backslash. We always need to read the next line, keep it in
4163 * sp->nextline. */
4164 sp->nextline = get_one_sourceline(sp);
4165 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004166 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004167 garray_T ga;
4168
Bram Moolenaarb549a732012-02-22 18:29:33 +01004169 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004170 ga_concat(&ga, line);
4171 ga_concat(&ga, p + 1);
4172 for (;;)
4173 {
4174 vim_free(sp->nextline);
4175 sp->nextline = get_one_sourceline(sp);
4176 if (sp->nextline == NULL)
4177 break;
4178 p = skipwhite(sp->nextline);
4179 if (*p != '\\')
4180 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004181 /* Adjust the growsize to the current length to speed up
4182 * concatenating many lines. */
4183 if (ga.ga_len > 400)
4184 {
4185 if (ga.ga_len > 8000)
4186 ga.ga_growsize = 8000;
4187 else
4188 ga.ga_growsize = ga.ga_len;
4189 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004190 ga_concat(&ga, p + 1);
4191 }
4192 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004193 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004194 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004195 }
4196 }
4197
4198#ifdef FEAT_MBYTE
4199 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4200 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004201 char_u *s;
4202
Bram Moolenaar071d4272004-06-13 20:20:40 +00004203 /* Convert the encoding of the script line. */
4204 s = string_convert(&sp->conv, line, NULL);
4205 if (s != NULL)
4206 {
4207 vim_free(line);
4208 line = s;
4209 }
4210 }
4211#endif
4212
4213#ifdef FEAT_EVAL
4214 /* Did we encounter a breakpoint? */
4215 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4216 {
4217 dbg_breakpoint(sp->fname, sourcing_lnum);
4218 /* Find next breakpoint. */
4219 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4220 sp->dbg_tick = debug_tick;
4221 }
4222#endif
4223
4224 return line;
4225}
4226
4227 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004228get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229{
4230 garray_T ga;
4231 int len;
4232 int c;
4233 char_u *buf;
4234#ifdef USE_CRNL
4235 int has_cr; /* CR-LF found */
4236#endif
4237#ifdef USE_CR
4238 char_u *scan;
4239#endif
4240 int have_read = FALSE;
4241
4242 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004243 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004244
4245 /*
4246 * Loop until there is a finished line (or end-of-file).
4247 */
4248 sourcing_lnum++;
4249 for (;;)
4250 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004251 /* make room to read at least 120 (more) characters */
4252 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253 break;
4254 buf = (char_u *)ga.ga_data;
4255
4256#ifdef USE_CR
4257 if (sp->fileformat == EOL_MAC)
4258 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004259 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4260 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 break;
4262 }
4263 else
4264#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004265 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4266 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004267 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004268 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004269#ifdef USE_CRNL
4270 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4271 * CTRL-Z by its own, or after a NL. */
4272 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4273 && sp->fileformat == EOL_DOS
4274 && buf[len - 1] == Ctrl_Z)
4275 {
4276 buf[len - 1] = NUL;
4277 break;
4278 }
4279#endif
4280
4281#ifdef USE_CR
4282 /* If the read doesn't stop on a new line, and there's
4283 * some CR then we assume a Mac format */
4284 if (sp->fileformat == EOL_UNKNOWN)
4285 {
4286 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4287 sp->fileformat = EOL_MAC;
4288 else
4289 sp->fileformat = EOL_UNIX;
4290 }
4291
4292 if (sp->fileformat == EOL_MAC)
4293 {
4294 scan = vim_strchr(buf, '\r');
4295
4296 if (scan != NULL)
4297 {
4298 *scan = '\n';
4299 if (*(scan + 1) != 0)
4300 {
4301 *(scan + 1) = 0;
4302 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4303 }
4304 }
4305 len = STRLEN(buf);
4306 }
4307#endif
4308
4309 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004310 ga.ga_len = len;
4311
4312 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004313 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314 continue;
4315
4316 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4317 {
4318#ifdef USE_CRNL
4319 has_cr = (len >= 2 && buf[len - 2] == '\r');
4320 if (sp->fileformat == EOL_UNKNOWN)
4321 {
4322 if (has_cr)
4323 sp->fileformat = EOL_DOS;
4324 else
4325 sp->fileformat = EOL_UNIX;
4326 }
4327
4328 if (sp->fileformat == EOL_DOS)
4329 {
4330 if (has_cr) /* replace trailing CR */
4331 {
4332 buf[len - 2] = '\n';
4333 --len;
4334 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335 }
4336 else /* lines like ":map xx yy^M" will have failed */
4337 {
4338 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004339 {
4340 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004342 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004343 sp->error = TRUE;
4344 sp->fileformat = EOL_UNIX;
4345 }
4346 }
4347#endif
4348 /* The '\n' is escaped if there is an odd number of ^V's just
4349 * before it, first set "c" just before the 'V's and then check
4350 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4351 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4352 ;
4353 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4354 {
4355 sourcing_lnum++;
4356 continue;
4357 }
4358
4359 buf[len - 1] = NUL; /* remove the NL */
4360 }
4361
4362 /*
4363 * Check for ^C here now and then, so recursive :so can be broken.
4364 */
4365 line_breakcheck();
4366 break;
4367 }
4368
4369 if (have_read)
4370 return (char_u *)ga.ga_data;
4371
4372 vim_free(ga.ga_data);
4373 return NULL;
4374}
4375
Bram Moolenaar05159a02005-02-26 23:04:13 +00004376#if defined(FEAT_PROFILE) || defined(PROTO)
4377/*
4378 * Called when starting to read a script line.
4379 * "sourcing_lnum" must be correct!
4380 * When skipping lines it may not actually be executed, but we won't find out
4381 * until later and we need to store the time now.
4382 */
4383 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004384script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004385{
4386 scriptitem_T *si;
4387 sn_prl_T *pp;
4388
4389 if (current_SID <= 0 || current_SID > script_items.ga_len)
4390 return;
4391 si = &SCRIPT_ITEM(current_SID);
4392 if (si->sn_prof_on && sourcing_lnum >= 1)
4393 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004394 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004395 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004396 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004397 si->sn_prl_idx = sourcing_lnum - 1;
4398 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4399 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4400 {
4401 /* Zero counters for a line that was not used before. */
4402 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4403 pp->snp_count = 0;
4404 profile_zero(&pp->sn_prl_total);
4405 profile_zero(&pp->sn_prl_self);
4406 ++si->sn_prl_ga.ga_len;
4407 }
4408 si->sn_prl_execed = FALSE;
4409 profile_start(&si->sn_prl_start);
4410 profile_zero(&si->sn_prl_children);
4411 profile_get_wait(&si->sn_prl_wait);
4412 }
4413}
4414
4415/*
4416 * Called when actually executing a function line.
4417 */
4418 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004419script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004420{
4421 scriptitem_T *si;
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 && si->sn_prl_idx >= 0)
4427 si->sn_prl_execed = TRUE;
4428}
4429
4430/*
4431 * Called when done with a function line.
4432 */
4433 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004434script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004435{
4436 scriptitem_T *si;
4437 sn_prl_T *pp;
4438
4439 if (current_SID <= 0 || current_SID > script_items.ga_len)
4440 return;
4441 si = &SCRIPT_ITEM(current_SID);
4442 if (si->sn_prof_on && si->sn_prl_idx >= 0
4443 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4444 {
4445 if (si->sn_prl_execed)
4446 {
4447 pp = &PRL_ITEM(si, si->sn_prl_idx);
4448 ++pp->snp_count;
4449 profile_end(&si->sn_prl_start);
4450 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004451 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004452 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4453 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004454 }
4455 si->sn_prl_idx = -1;
4456 }
4457}
4458#endif
4459
Bram Moolenaar071d4272004-06-13 20:20:40 +00004460/*
4461 * ":scriptencoding": Set encoding conversion for a sourced script.
4462 * Without the multi-byte feature it's simply ignored.
4463 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004464 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004465ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004466{
4467#ifdef FEAT_MBYTE
4468 struct source_cookie *sp;
4469 char_u *name;
4470
4471 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4472 {
4473 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4474 return;
4475 }
4476
4477 if (*eap->arg != NUL)
4478 {
4479 name = enc_canonize(eap->arg);
4480 if (name == NULL) /* out of memory */
4481 return;
4482 }
4483 else
4484 name = eap->arg;
4485
4486 /* Setup for conversion from the specified encoding to 'encoding'. */
4487 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4488 convert_setup(&sp->conv, name, p_enc);
4489
4490 if (name != eap->arg)
4491 vim_free(name);
4492#endif
4493}
4494
4495#if defined(FEAT_EVAL) || defined(PROTO)
4496/*
4497 * ":finish": Mark a sourced file as finished.
4498 */
4499 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004500ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501{
4502 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4503 do_finish(eap, FALSE);
4504 else
4505 EMSG(_("E168: :finish used outside of a sourced file"));
4506}
4507
4508/*
4509 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4510 * Also called for a pending finish at the ":endtry" or after returning from
4511 * an extra do_cmdline(). "reanimate" is used in the latter case.
4512 */
4513 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004514do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004515{
4516 int idx;
4517
4518 if (reanimate)
4519 ((struct source_cookie *)getline_cookie(eap->getline,
4520 eap->cookie))->finished = FALSE;
4521
4522 /*
4523 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4524 * not in its finally clause (which then is to be executed next) is found.
4525 * In this case, make the ":finish" pending for execution at the ":endtry".
4526 * Otherwise, finish normally.
4527 */
4528 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4529 if (idx >= 0)
4530 {
4531 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4532 report_make_pending(CSTP_FINISH, NULL);
4533 }
4534 else
4535 ((struct source_cookie *)getline_cookie(eap->getline,
4536 eap->cookie))->finished = TRUE;
4537}
4538
4539
4540/*
4541 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4542 * message for missing ":endif".
4543 * Return FALSE when not sourcing a file.
4544 */
4545 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004546source_finished(
4547 char_u *(*fgetline)(int, void *, int),
4548 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004550 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004552 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004553}
4554#endif
4555
4556#if defined(FEAT_LISTCMDS) || defined(PROTO)
4557/*
4558 * ":checktime [buffer]"
4559 */
4560 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004561ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562{
4563 buf_T *buf;
4564 int save_no_check_timestamps = no_check_timestamps;
4565
4566 no_check_timestamps = 0;
4567 if (eap->addr_count == 0) /* default is all buffers */
4568 check_timestamps(FALSE);
4569 else
4570 {
4571 buf = buflist_findnr((int)eap->line2);
4572 if (buf != NULL) /* cannot happen? */
4573 (void)buf_check_timestamp(buf, FALSE);
4574 }
4575 no_check_timestamps = save_no_check_timestamps;
4576}
4577#endif
4578
Bram Moolenaar071d4272004-06-13 20:20:40 +00004579#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4580 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004581# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004582static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004584 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004585get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004586{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004587 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004588
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004589 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004590 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004591
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004592# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004593 if (loc != NULL)
4594 {
4595 char_u *p;
4596
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004597 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4598 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004599 p = vim_strchr(loc, '=');
4600 if (p != NULL)
4601 {
4602 loc = ++p;
4603 while (*p != NUL) /* remove trailing newline */
4604 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004605 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606 {
4607 *p = NUL;
4608 break;
4609 }
4610 ++p;
4611 }
4612 }
4613 }
4614# endif
4615
4616 return loc;
4617}
4618#endif
4619
4620
4621#ifdef WIN32
4622/*
4623 * On MS-Windows locale names are strings like "German_Germany.1252", but
4624 * gettext expects "de". Try to translate one into another here for a few
4625 * supported languages.
4626 */
4627 static char_u *
4628gettext_lang(char_u *name)
4629{
4630 int i;
4631 static char *(mtable[]) = {
4632 "afrikaans", "af",
4633 "czech", "cs",
4634 "dutch", "nl",
4635 "german", "de",
4636 "english_united kingdom", "en_GB",
4637 "spanish", "es",
4638 "french", "fr",
4639 "italian", "it",
4640 "japanese", "ja",
4641 "korean", "ko",
4642 "norwegian", "no",
4643 "polish", "pl",
4644 "russian", "ru",
4645 "slovak", "sk",
4646 "swedish", "sv",
4647 "ukrainian", "uk",
4648 "chinese_china", "zh_CN",
4649 "chinese_taiwan", "zh_TW",
4650 NULL};
4651
4652 for (i = 0; mtable[i] != NULL; i += 2)
4653 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004654 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655 return name;
4656}
4657#endif
4658
4659#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4660/*
4661 * Obtain the current messages language. Used to set the default for
4662 * 'helplang'. May return NULL or an empty string.
4663 */
4664 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004665get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004666{
4667 char_u *p;
4668
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004669# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004670# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004671 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004672# else
4673 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004674 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4675 * and LC_MONETARY may be set differently for a Japanese working in the
4676 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004677 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678# endif
4679# else
4680 p = mch_getenv((char_u *)"LC_ALL");
4681 if (p == NULL || *p == NUL)
4682 {
4683 p = mch_getenv((char_u *)"LC_MESSAGES");
4684 if (p == NULL || *p == NUL)
4685 p = mch_getenv((char_u *)"LANG");
4686 }
4687# endif
4688# ifdef WIN32
4689 p = gettext_lang(p);
4690# endif
4691 return p;
4692}
4693#endif
4694
Bram Moolenaardef9e822004-12-31 20:58:58 +00004695/* Complicated #if; matches with where get_mess_env() is used below. */
4696#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4697 && defined(LC_MESSAGES))) \
4698 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4699 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4700 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004701static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702
4703/*
4704 * Get the language used for messages from the environment.
4705 */
4706 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004707get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708{
4709 char_u *p;
4710
4711 p = mch_getenv((char_u *)"LC_ALL");
4712 if (p == NULL || *p == NUL)
4713 {
4714 p = mch_getenv((char_u *)"LC_MESSAGES");
4715 if (p == NULL || *p == NUL)
4716 {
4717 p = mch_getenv((char_u *)"LANG");
4718 if (p != NULL && VIM_ISDIGIT(*p))
4719 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004720# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004722 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004723# endif
4724 }
4725 }
4726 return p;
4727}
4728#endif
4729
4730#if defined(FEAT_EVAL) || defined(PROTO)
4731
4732/*
4733 * Set the "v:lang" variable according to the current locale setting.
4734 * Also do "v:lc_time"and "v:ctype".
4735 */
4736 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004737set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004738{
4739 char_u *loc;
4740
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004741# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004742 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004743# else
4744 /* setlocale() not supported: use the default value */
4745 loc = (char_u *)"C";
4746# endif
4747 set_vim_var_string(VV_CTYPE, loc, -1);
4748
4749 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4750 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004751# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004752 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004753# else
4754 loc = get_mess_env();
4755# endif
4756 set_vim_var_string(VV_LANG, loc, -1);
4757
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004758# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004759 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760# endif
4761 set_vim_var_string(VV_LC_TIME, loc, -1);
4762}
4763#endif
4764
4765#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4766 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4767/*
4768 * ":language": Set the language (locale).
4769 */
4770 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004771ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772{
4773 char *loc;
4774 char_u *p;
4775 char_u *name;
4776 int what = LC_ALL;
4777 char *whatstr = "";
4778#ifdef LC_MESSAGES
4779# define VIM_LC_MESSAGES LC_MESSAGES
4780#else
4781# define VIM_LC_MESSAGES 6789
4782#endif
4783
4784 name = eap->arg;
4785
4786 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4787 * Allow abbreviation, but require at least 3 characters to avoid
4788 * confusion with a two letter language name "me" or "ct". */
4789 p = skiptowhite(eap->arg);
4790 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4791 {
4792 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4793 {
4794 what = VIM_LC_MESSAGES;
4795 name = skipwhite(p);
4796 whatstr = "messages ";
4797 }
4798 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4799 {
4800 what = LC_CTYPE;
4801 name = skipwhite(p);
4802 whatstr = "ctype ";
4803 }
4804 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4805 {
4806 what = LC_TIME;
4807 name = skipwhite(p);
4808 whatstr = "time ";
4809 }
4810 }
4811
4812 if (*name == NUL)
4813 {
4814#ifndef LC_MESSAGES
4815 if (what == VIM_LC_MESSAGES)
4816 p = get_mess_env();
4817 else
4818#endif
4819 p = (char_u *)setlocale(what, NULL);
4820 if (p == NULL || *p == NUL)
4821 p = (char_u *)"Unknown";
4822 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4823 }
4824 else
4825 {
4826#ifndef LC_MESSAGES
4827 if (what == VIM_LC_MESSAGES)
4828 loc = "";
4829 else
4830#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004831 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004832 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004833#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4834 /* Make sure strtod() uses a decimal point, not a comma. */
4835 setlocale(LC_NUMERIC, "C");
4836#endif
4837 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004838 if (loc == NULL)
4839 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4840 else
4841 {
4842#ifdef HAVE_NL_MSG_CAT_CNTR
4843 /* Need to do this for GNU gettext, otherwise cached translations
4844 * will be used again. */
4845 extern int _nl_msg_cat_cntr;
4846
4847 ++_nl_msg_cat_cntr;
4848#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004849 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004850 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4851
4852 if (what != LC_TIME)
4853 {
4854 /* Tell gettext() what to translate to. It apparently doesn't
4855 * use the currently effective locale. Also do this when
4856 * FEAT_GETTEXT isn't defined, so that shell commands use this
4857 * value. */
4858 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004859 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004860 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004861
4862 /* Clear $LANGUAGE because GNU gettext uses it. */
4863 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004864# ifdef WIN32
4865 /* Apparently MS-Windows printf() may cause a crash when
4866 * we give it 8-bit text while it's expecting text in the
4867 * current locale. This call avoids that. */
4868 setlocale(LC_CTYPE, "C");
4869# endif
4870 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004871 if (what != LC_CTYPE)
4872 {
4873 char_u *mname;
4874#ifdef WIN32
4875 mname = gettext_lang(name);
4876#else
4877 mname = name;
4878#endif
4879 vim_setenv((char_u *)"LC_MESSAGES", mname);
4880#ifdef FEAT_MULTI_LANG
4881 set_helplang_default(mname);
4882#endif
4883 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004884 }
4885
4886# ifdef FEAT_EVAL
4887 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4888 set_lang_var();
4889# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004890# ifdef FEAT_TITLE
4891 maketitle();
4892# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004893 }
4894 }
4895}
4896
4897# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004898
4899static char_u **locales = NULL; /* Array of all available locales */
4900static int did_init_locales = FALSE;
4901
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004902static void init_locales(void);
4903static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004904
4905/*
4906 * Lazy initialization of all available locales.
4907 */
4908 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004909init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004910{
4911 if (!did_init_locales)
4912 {
4913 did_init_locales = TRUE;
4914 locales = find_locales();
4915 }
4916}
4917
4918/* Return an array of strings for all available locales + NULL for the
4919 * last element. Return NULL in case of error. */
4920 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004921find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004922{
4923 garray_T locales_ga;
4924 char_u *loc;
4925
4926 /* Find all available locales by running command "locale -a". If this
4927 * doesn't work we won't have completion. */
4928 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004929 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004930 if (locale_a == NULL)
4931 return NULL;
4932 ga_init2(&locales_ga, sizeof(char_u *), 20);
4933
4934 /* Transform locale_a string where each locale is separated by "\n"
4935 * into an array of locale strings. */
4936 loc = (char_u *)strtok((char *)locale_a, "\n");
4937
4938 while (loc != NULL)
4939 {
4940 if (ga_grow(&locales_ga, 1) == FAIL)
4941 break;
4942 loc = vim_strsave(loc);
4943 if (loc == NULL)
4944 break;
4945
4946 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4947 loc = (char_u *)strtok(NULL, "\n");
4948 }
4949 vim_free(locale_a);
4950 if (ga_grow(&locales_ga, 1) == FAIL)
4951 {
4952 ga_clear(&locales_ga);
4953 return NULL;
4954 }
4955 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4956 return (char_u **)locales_ga.ga_data;
4957}
4958
4959# if defined(EXITFREE) || defined(PROTO)
4960 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004961free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004962{
4963 int i;
4964 if (locales != NULL)
4965 {
4966 for (i = 0; locales[i] != NULL; i++)
4967 vim_free(locales[i]);
4968 vim_free(locales);
4969 locales = NULL;
4970 }
4971}
4972# endif
4973
Bram Moolenaar071d4272004-06-13 20:20:40 +00004974/*
4975 * Function given to ExpandGeneric() to obtain the possible arguments of the
4976 * ":language" command.
4977 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004978 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004979get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004980{
4981 if (idx == 0)
4982 return (char_u *)"messages";
4983 if (idx == 1)
4984 return (char_u *)"ctype";
4985 if (idx == 2)
4986 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004987
4988 init_locales();
4989 if (locales == NULL)
4990 return NULL;
4991 return locales[idx - 3];
4992}
4993
4994/*
4995 * Function given to ExpandGeneric() to obtain the available locales.
4996 */
4997 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004998get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004999{
5000 init_locales();
5001 if (locales == NULL)
5002 return NULL;
5003 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005004}
5005# endif
5006
5007#endif