blob: 49e4d3df44f2ae0febfe91d535f8f280071b3037 [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;
134#ifdef FEAT_SNIFF
135 want_sniff_request = 0; /* No K_SNIFF wanted */
136#endif
137
138 if (!debug_did_msg)
139 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
140 if (sourcing_name != NULL)
141 msg(sourcing_name);
142 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000143 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000145 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146
147 /*
148 * Repeat getting a command and executing it.
149 */
150 for (;;)
151 {
152 msg_scroll = TRUE;
153 need_wait_return = FALSE;
154#ifdef FEAT_SNIFF
155 ProcessSniffRequests();
156#endif
157 /* Save the current typeahead buffer and replace it with an empty one.
158 * This makes sure we get input from the user here and don't interfere
159 * with the commands being executed. Reset "ex_normal_busy" to avoid
160 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000161 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162 save_ex_normal_busy = ex_normal_busy;
163 ex_normal_busy = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000165 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000167 typeahead_saved = TRUE;
168 save_ignore_script = ignore_script;
169 ignore_script = TRUE;
170 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000172 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000174 if (typeahead_saved)
175 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000177 ignore_script = save_ignore_script;
178 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180
181 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100182 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183 if (cmdline != NULL)
184 {
185 /* If this is a debug command, set "last_cmd".
186 * If not, reset "last_cmd".
187 * For a blank line use previous command. */
188 p = skipwhite(cmdline);
189 if (*p != NUL)
190 {
191 switch (*p)
192 {
193 case 'c': last_cmd = CMD_CONT;
194 tail = "ont";
195 break;
196 case 'n': last_cmd = CMD_NEXT;
197 tail = "ext";
198 break;
199 case 's': last_cmd = CMD_STEP;
200 tail = "tep";
201 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100202 case 'f':
203 last_cmd = 0;
204 if (p[1] == 'r')
205 {
206 last_cmd = CMD_FRAME;
207 tail = "rame";
208 }
209 else
210 {
211 last_cmd = CMD_FINISH;
212 tail = "inish";
213 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000214 break;
215 case 'q': last_cmd = CMD_QUIT;
216 tail = "uit";
217 break;
218 case 'i': last_cmd = CMD_INTERRUPT;
219 tail = "nterrupt";
220 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100221 case 'b': last_cmd = CMD_BACKTRACE;
222 if (p[1] == 't')
223 tail = "t";
224 else
225 tail = "acktrace";
226 break;
227 case 'w': last_cmd = CMD_BACKTRACE;
228 tail = "here";
229 break;
230 case 'u': last_cmd = CMD_UP;
231 tail = "p";
232 break;
233 case 'd': last_cmd = CMD_DOWN;
234 tail = "own";
235 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236 default: last_cmd = 0;
237 }
238 if (last_cmd != 0)
239 {
240 /* Check that the tail matches. */
241 ++p;
242 while (*p != NUL && *p == *tail)
243 {
244 ++p;
245 ++tail;
246 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100247 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000248 last_cmd = 0;
249 }
250 }
251
252 if (last_cmd != 0)
253 {
254 /* Execute debug command: decided where to break next and
255 * return. */
256 switch (last_cmd)
257 {
258 case CMD_CONT:
259 debug_break_level = -1;
260 break;
261 case CMD_NEXT:
262 debug_break_level = ex_nesting_level;
263 break;
264 case CMD_STEP:
265 debug_break_level = 9999;
266 break;
267 case CMD_FINISH:
268 debug_break_level = ex_nesting_level - 1;
269 break;
270 case CMD_QUIT:
271 got_int = TRUE;
272 debug_break_level = -1;
273 break;
274 case CMD_INTERRUPT:
275 got_int = TRUE;
276 debug_break_level = 9999;
277 /* Do not repeat ">interrupt" cmd, continue stepping. */
278 last_cmd = CMD_STEP;
279 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100280 case CMD_BACKTRACE:
281 do_showbacktrace(cmd);
282 continue;
283 case CMD_FRAME:
284 if (*p == NUL)
285 {
286 do_showbacktrace(cmd);
287 }
288 else
289 {
290 p = skipwhite(p);
291 do_setdebugtracelevel(p);
292 }
293 continue;
294 case CMD_UP:
295 debug_backtrace_level++;
296 do_checkbacktracelevel();
297 continue;
298 case CMD_DOWN:
299 debug_backtrace_level--;
300 do_checkbacktracelevel();
301 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000302 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100303 /* Going out reset backtrace_level */
304 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 break;
306 }
307
308 /* don't debug this command */
309 n = debug_break_level;
310 debug_break_level = -1;
311 (void)do_cmdline(cmdline, getexline, NULL,
312 DOCMD_VERBOSE|DOCMD_EXCRESET);
313 debug_break_level = n;
314
315 vim_free(cmdline);
316 }
317 lines_left = Rows - 1;
318 }
319 vim_free(cmdline);
320
321 --RedrawingDisabled;
322 --no_wait_return;
323 redraw_all_later(NOT_VALID);
324 need_wait_return = FALSE;
325 msg_scroll = save_msg_scroll;
326 lines_left = Rows - 1;
327 State = save_State;
328 did_emsg = save_did_emsg;
329 cmd_silent = save_cmd_silent;
330 msg_silent = save_msg_silent;
331 emsg_silent = save_emsg_silent;
332 redir_off = save_redir_off;
333
334 /* Only print the message again when typing a command before coming back
335 * here. */
336 debug_did_msg = TRUE;
337}
338
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100339 static int
340get_maxbacktrace_level(void)
341{
342 char *p, *q;
343 int maxbacktrace = 1;
344
345 maxbacktrace = 0;
346 if (sourcing_name != NULL)
347 {
348 p = (char *)sourcing_name;
349 while ((q = strstr(p, "..")) != NULL)
350 {
351 p = q + 2;
352 maxbacktrace++;
353 }
354 }
355 return maxbacktrace;
356}
357
358 static void
359do_setdebugtracelevel(char_u *arg)
360{
361 int level;
362
363 level = atoi((char *)arg);
364 if (*arg == '+' || level < 0)
365 debug_backtrace_level += level;
366 else
367 debug_backtrace_level = level;
368
369 do_checkbacktracelevel();
370}
371
372 static void
373do_checkbacktracelevel(void)
374{
375 if (debug_backtrace_level < 0)
376 {
377 debug_backtrace_level = 0;
378 MSG(_("frame is zero"));
379 }
380 else
381 {
382 int max = get_maxbacktrace_level();
383
384 if (debug_backtrace_level > max)
385 {
386 debug_backtrace_level = max;
387 smsg((char_u *)_("frame at highest level: %d"), max);
388 }
389 }
390}
391
392 static void
393do_showbacktrace(char_u *cmd)
394{
395 char *cur;
396 char *next;
397 int i = 0;
398 int max = get_maxbacktrace_level();
399
400 if (sourcing_name != NULL)
401 {
402 cur = (char *)sourcing_name;
403 while (!got_int)
404 {
405 next = strstr(cur, "..");
406 if (next != NULL)
407 *next = NUL;
408 if (i == max - debug_backtrace_level)
409 smsg((char_u *)"->%d %s", max - i, cur);
410 else
411 smsg((char_u *)" %d %s", max - i, cur);
412 ++i;
413 if (next == NULL)
414 break;
415 *next = '.';
416 cur = next + 2;
417 }
418 }
419 if (sourcing_lnum != 0)
420 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
421 else
422 smsg((char_u *)_("cmd: %s"), cmd);
423}
424
Bram Moolenaar071d4272004-06-13 20:20:40 +0000425/*
426 * ":debug".
427 */
428 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100429ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000430{
431 int debug_break_level_save = debug_break_level;
432
433 debug_break_level = 9999;
434 do_cmdline_cmd(eap->arg);
435 debug_break_level = debug_break_level_save;
436}
437
438static char_u *debug_breakpoint_name = NULL;
439static linenr_T debug_breakpoint_lnum;
440
441/*
442 * When debugging or a breakpoint is set on a skipped command, no debug prompt
443 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
444 * debug_skipped_name is then set to the source name in the breakpoint case. If
445 * a skipped command decides itself that a debug prompt should be displayed, it
446 * can do so by calling dbg_check_skipped().
447 */
448static int debug_skipped;
449static char_u *debug_skipped_name;
450
451/*
452 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
453 * at or below the break level. But only when the line is actually
454 * executed. Return TRUE and set breakpoint_name for skipped commands that
455 * decide to execute something themselves.
456 * Called from do_one_cmd() before executing a command.
457 */
458 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100459dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000460{
461 char_u *p;
462
463 debug_skipped = FALSE;
464 if (debug_breakpoint_name != NULL)
465 {
466 if (!eap->skip)
467 {
468 /* replace K_SNR with "<SNR>" */
469 if (debug_breakpoint_name[0] == K_SPECIAL
470 && debug_breakpoint_name[1] == KS_EXTRA
471 && debug_breakpoint_name[2] == (int)KE_SNR)
472 p = (char_u *)"<SNR>";
473 else
474 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000475 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
476 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 debug_breakpoint_name + (*p == NUL ? 0 : 3),
478 (long)debug_breakpoint_lnum);
479 debug_breakpoint_name = NULL;
480 do_debug(eap->cmd);
481 }
482 else
483 {
484 debug_skipped = TRUE;
485 debug_skipped_name = debug_breakpoint_name;
486 debug_breakpoint_name = NULL;
487 }
488 }
489 else if (ex_nesting_level <= debug_break_level)
490 {
491 if (!eap->skip)
492 do_debug(eap->cmd);
493 else
494 {
495 debug_skipped = TRUE;
496 debug_skipped_name = NULL;
497 }
498 }
499}
500
501/*
502 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
503 * set. Return TRUE when the debug mode is entered this time.
504 */
505 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100506dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507{
508 int prev_got_int;
509
510 if (debug_skipped)
511 {
512 /*
513 * Save the value of got_int and reset it. We don't want a previous
514 * interruption cause flushing the input buffer.
515 */
516 prev_got_int = got_int;
517 got_int = FALSE;
518 debug_breakpoint_name = debug_skipped_name;
519 /* eap->skip is TRUE */
520 eap->skip = FALSE;
521 (void)dbg_check_breakpoint(eap);
522 eap->skip = TRUE;
523 got_int |= prev_got_int;
524 return TRUE;
525 }
526 return FALSE;
527}
528
529/*
530 * The list of breakpoints: dbg_breakp.
531 * This is a grow-array of structs.
532 */
533struct debuggy
534{
535 int dbg_nr; /* breakpoint number */
536 int dbg_type; /* DBG_FUNC or DBG_FILE */
537 char_u *dbg_name; /* function or file name */
538 regprog_T *dbg_prog; /* regexp program */
539 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000540 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541};
542
543static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000544#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
545#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546static int last_breakp = 0; /* nr of last defined breakpoint */
547
Bram Moolenaar05159a02005-02-26 23:04:13 +0000548#ifdef FEAT_PROFILE
549/* Profiling uses file and func names similar to breakpoints. */
550static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
551#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000552#define DBG_FUNC 1
553#define DBG_FILE 2
554
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100555static int dbg_parsearg(char_u *arg, garray_T *gap);
556static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557
558/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000559 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
560 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
561 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000562 * Returns FAIL for failure.
563 */
564 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100565dbg_parsearg(
566 char_u *arg,
567 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568{
569 char_u *p = arg;
570 char_u *q;
571 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000572 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000573
Bram Moolenaar05159a02005-02-26 23:04:13 +0000574 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000576 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577
578 /* Find "func" or "file". */
579 if (STRNCMP(p, "func", 4) == 0)
580 bp->dbg_type = DBG_FUNC;
581 else if (STRNCMP(p, "file", 4) == 0)
582 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000583 else if (
584#ifdef FEAT_PROFILE
585 gap != &prof_ga &&
586#endif
587 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000588 {
589 if (curbuf->b_ffname == NULL)
590 {
591 EMSG(_(e_noname));
592 return FAIL;
593 }
594 bp->dbg_type = DBG_FILE;
595 here = TRUE;
596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 else
598 {
599 EMSG2(_(e_invarg2), p);
600 return FAIL;
601 }
602 p = skipwhite(p + 4);
603
604 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000605 if (here)
606 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000607 else if (
608#ifdef FEAT_PROFILE
609 gap != &prof_ga &&
610#endif
611 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612 {
613 bp->dbg_lnum = getdigits(&p);
614 p = skipwhite(p);
615 }
616 else
617 bp->dbg_lnum = 0;
618
619 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000620 if ((!here && *p == NUL)
621 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
623 {
624 EMSG2(_(e_invarg2), arg);
625 return FAIL;
626 }
627
628 if (bp->dbg_type == DBG_FUNC)
629 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000630 else if (here)
631 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 else
633 {
634 /* Expand the file name in the same way as do_source(). This means
635 * doing it twice, so that $DIR/file gets expanded when $DIR is
636 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 if (q == NULL)
639 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641 vim_free(q);
642 if (p == NULL)
643 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000644 if (*p != '*')
645 {
646 bp->dbg_name = fix_fname(p);
647 vim_free(p);
648 }
649 else
650 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 }
652
653 if (bp->dbg_name == NULL)
654 return FAIL;
655 return OK;
656}
657
658/*
659 * ":breakadd".
660 */
661 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100662ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663{
664 struct debuggy *bp;
665 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000666 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667
Bram Moolenaar05159a02005-02-26 23:04:13 +0000668 gap = &dbg_breakp;
669#ifdef FEAT_PROFILE
670 if (eap->cmdidx == CMD_profile)
671 gap = &prof_ga;
672#endif
673
674 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000676 bp = &DEBUGGY(gap, gap->ga_len);
677 bp->dbg_forceit = eap->forceit;
678
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
680 if (pat != NULL)
681 {
682 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
683 vim_free(pat);
684 }
685 if (pat == NULL || bp->dbg_prog == NULL)
686 vim_free(bp->dbg_name);
687 else
688 {
689 if (bp->dbg_lnum == 0) /* default line number is 1 */
690 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000691#ifdef FEAT_PROFILE
692 if (eap->cmdidx != CMD_profile)
693#endif
694 {
695 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
696 ++debug_tick;
697 }
698 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699 }
700 }
701}
702
703/*
704 * ":debuggreedy".
705 */
706 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100707ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000708{
709 if (eap->addr_count == 0 || eap->line2 != 0)
710 debug_greedy = TRUE;
711 else
712 debug_greedy = FALSE;
713}
714
715/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000716 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000717 */
718 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100719ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720{
721 struct debuggy *bp, *bpi;
722 int nr;
723 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000724 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725 int i;
726 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000727 garray_T *gap;
728
729 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000730 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200731 {
732#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000733 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200734#else
735 ex_ni(eap);
736 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000737#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200738 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739
740 if (vim_isdigit(*eap->arg))
741 {
742 /* ":breakdel {nr}" */
743 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000744 for (i = 0; i < gap->ga_len; ++i)
745 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746 {
747 todel = i;
748 break;
749 }
750 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000751 else if (*eap->arg == '*')
752 {
753 todel = 0;
754 del_all = TRUE;
755 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 else
757 {
758 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000759 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000761 bp = &DEBUGGY(gap, gap->ga_len);
762 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000764 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 if (bp->dbg_type == bpi->dbg_type
766 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
767 && (bp->dbg_lnum == bpi->dbg_lnum
768 || (bp->dbg_lnum == 0
769 && (best_lnum == 0
770 || bpi->dbg_lnum < best_lnum))))
771 {
772 todel = i;
773 best_lnum = bpi->dbg_lnum;
774 }
775 }
776 vim_free(bp->dbg_name);
777 }
778
779 if (todel < 0)
780 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
781 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000782 {
783 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000784 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000785 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200786 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000787 --gap->ga_len;
788 if (todel < gap->ga_len)
789 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
790 (gap->ga_len - todel) * sizeof(struct debuggy));
791#ifdef FEAT_PROFILE
792 if (eap->cmdidx == CMD_breakdel)
793#endif
794 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000795 if (!del_all)
796 break;
797 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000798
799 /* If all breakpoints were removed clear the array. */
800 if (gap->ga_len == 0)
801 ga_clear(gap);
802 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803}
804
805/*
806 * ":breaklist".
807 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100809ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810{
811 struct debuggy *bp;
812 int i;
813
814 if (dbg_breakp.ga_len == 0)
815 MSG(_("No breakpoints defined"));
816 else
817 for (i = 0; i < dbg_breakp.ga_len; ++i)
818 {
819 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200820 if (bp->dbg_type == DBG_FILE)
821 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 smsg((char_u *)_("%3d %s %s line %ld"),
823 bp->dbg_nr,
824 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200825 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826 (long)bp->dbg_lnum);
827 }
828}
829
830/*
831 * Find a breakpoint for a function or sourced file.
832 * Returns line number at which to break; zero when no matching breakpoint.
833 */
834 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100835dbg_find_breakpoint(
836 int file, /* TRUE for a file, FALSE for a function */
837 char_u *fname, /* file or function name */
838 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000840 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
841}
842
843#if defined(FEAT_PROFILE) || defined(PROTO)
844/*
845 * Return TRUE if profiling is on for a function or sourced file.
846 */
847 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100848has_profiling(
849 int file, /* TRUE for a file, FALSE for a function */
850 char_u *fname, /* file or function name */
851 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000852{
853 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
854 != (linenr_T)0);
855}
856#endif
857
858/*
859 * Common code for dbg_find_breakpoint() and has_profiling().
860 */
861 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100862debuggy_find(
863 int file, /* TRUE for a file, FALSE for a function */
864 char_u *fname, /* file or function name */
865 linenr_T after, /* after this line number */
866 garray_T *gap, /* either &dbg_breakp or &prof_ga */
867 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000868{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 struct debuggy *bp;
870 int i;
871 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 char_u *name = fname;
873 int prev_got_int;
874
Bram Moolenaar05159a02005-02-26 23:04:13 +0000875 /* Return quickly when there are no breakpoints. */
876 if (gap->ga_len == 0)
877 return (linenr_T)0;
878
Bram Moolenaar071d4272004-06-13 20:20:40 +0000879 /* Replace K_SNR in function name with "<SNR>". */
880 if (!file && fname[0] == K_SPECIAL)
881 {
882 name = alloc((unsigned)STRLEN(fname) + 3);
883 if (name == NULL)
884 name = fname;
885 else
886 {
887 STRCPY(name, "<SNR>");
888 STRCPY(name + 5, fname + 3);
889 }
890 }
891
Bram Moolenaar05159a02005-02-26 23:04:13 +0000892 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000894 /* Skip entries that are not useful or are for a line that is beyond
895 * an already found breakpoint. */
896 bp = &DEBUGGY(gap, i);
897 if (((bp->dbg_type == DBG_FILE) == file && (
898#ifdef FEAT_PROFILE
899 gap == &prof_ga ||
900#endif
901 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000904 * Save the value of got_int and reset it. We don't want a
905 * previous interruption cancel matching, only hitting CTRL-C
906 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907 */
908 prev_got_int = got_int;
909 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100910 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000911 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000912 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000913 if (fp != NULL)
914 *fp = bp->dbg_forceit;
915 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916 got_int |= prev_got_int;
917 }
918 }
919 if (name != fname)
920 vim_free(name);
921
922 return lnum;
923}
924
925/*
926 * Called when a breakpoint was encountered.
927 */
928 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100929dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930{
931 /* We need to check if this line is actually executed in do_one_cmd() */
932 debug_breakpoint_name = name;
933 debug_breakpoint_lnum = lnum;
934}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000935
936
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000937# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000938/*
939 * Store the current time in "tm".
940 */
941 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100942profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000943{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000944# ifdef WIN3264
945 QueryPerformanceCounter(tm);
946# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000947 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000948# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000949}
950
951/*
952 * Compute the elapsed time from "tm" till now and store in "tm".
953 */
954 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100955profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000956{
957 proftime_T now;
958
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000959# ifdef WIN3264
960 QueryPerformanceCounter(&now);
961 tm->QuadPart = now.QuadPart - tm->QuadPart;
962# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000963 gettimeofday(&now, NULL);
964 tm->tv_usec = now.tv_usec - tm->tv_usec;
965 tm->tv_sec = now.tv_sec - tm->tv_sec;
966 if (tm->tv_usec < 0)
967 {
968 tm->tv_usec += 1000000;
969 --tm->tv_sec;
970 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000971# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000972}
973
974/*
975 * Subtract the time "tm2" from "tm".
976 */
977 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100978profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000979{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000980# ifdef WIN3264
981 tm->QuadPart -= tm2->QuadPart;
982# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000983 tm->tv_usec -= tm2->tv_usec;
984 tm->tv_sec -= tm2->tv_sec;
985 if (tm->tv_usec < 0)
986 {
987 tm->tv_usec += 1000000;
988 --tm->tv_sec;
989 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000990# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000991}
992
993/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000994 * Return a string that represents the time in "tm".
995 * Uses a static buffer!
996 */
997 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100998profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000999{
1000 static char buf[50];
1001
1002# ifdef WIN3264
1003 LARGE_INTEGER fr;
1004
1005 QueryPerformanceFrequency(&fr);
1006 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1007# else
1008 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001009# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001010 return buf;
1011}
1012
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001013# if defined(FEAT_FLOAT) || defined(PROTO)
1014/*
1015 * Return a float that represents the time in "tm".
1016 */
1017 float_T
1018profile_float(proftime_T *tm)
1019{
1020# ifdef WIN3264
1021 LARGE_INTEGER fr;
1022
1023 QueryPerformanceFrequency(&fr);
1024 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
1025# else
1026 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
1027# endif
1028}
1029# endif
1030
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001031/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001032 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001033 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001034 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001035profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001036{
1037 if (msec <= 0) /* no limit */
1038 profile_zero(tm);
1039 else
1040 {
1041# ifdef WIN3264
1042 LARGE_INTEGER fr;
1043
1044 QueryPerformanceCounter(tm);
1045 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001046 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001047# else
1048 long usec;
1049
1050 gettimeofday(tm, NULL);
1051 usec = (long)tm->tv_usec + (long)msec * 1000;
1052 tm->tv_usec = usec % 1000000L;
1053 tm->tv_sec += usec / 1000000L;
1054# endif
1055 }
1056}
1057
1058/*
1059 * Return TRUE if the current time is past "tm".
1060 */
1061 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001062profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001063{
1064 proftime_T now;
1065
1066# ifdef WIN3264
1067 if (tm->QuadPart == 0) /* timer was not set */
1068 return FALSE;
1069 QueryPerformanceCounter(&now);
1070 return (now.QuadPart > tm->QuadPart);
1071# else
1072 if (tm->tv_sec == 0) /* timer was not set */
1073 return FALSE;
1074 gettimeofday(&now, NULL);
1075 return (now.tv_sec > tm->tv_sec
1076 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1077# endif
1078}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001079
1080/*
1081 * Set the time in "tm" to zero.
1082 */
1083 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001084profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001085{
1086# ifdef WIN3264
1087 tm->QuadPart = 0;
1088# else
1089 tm->tv_usec = 0;
1090 tm->tv_sec = 0;
1091# endif
1092}
1093
Bram Moolenaar76929292008-01-06 19:07:36 +00001094# endif /* FEAT_PROFILE || FEAT_RELTIME */
1095
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001096#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1097# if defined(HAVE_MATH_H)
1098# include <math.h>
1099# endif
1100
1101/*
1102 * Divide the time "tm" by "count" and store in "tm2".
1103 */
1104 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001105profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001106{
1107 if (count == 0)
1108 profile_zero(tm2);
1109 else
1110 {
1111# ifdef WIN3264
1112 tm2->QuadPart = tm->QuadPart / count;
1113# else
1114 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1115
1116 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001117 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001118# endif
1119 }
1120}
1121#endif
1122
Bram Moolenaar76929292008-01-06 19:07:36 +00001123# if defined(FEAT_PROFILE) || defined(PROTO)
1124/*
1125 * Functions for profiling.
1126 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001127static void script_do_profile(scriptitem_T *si);
1128static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001129static proftime_T prof_wait_time;
1130
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001131/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001132 * Add the time "tm2" to "tm".
1133 */
1134 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001135profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001136{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001137# ifdef WIN3264
1138 tm->QuadPart += tm2->QuadPart;
1139# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001140 tm->tv_usec += tm2->tv_usec;
1141 tm->tv_sec += tm2->tv_sec;
1142 if (tm->tv_usec >= 1000000)
1143 {
1144 tm->tv_usec -= 1000000;
1145 ++tm->tv_sec;
1146 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001147# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001148}
1149
1150/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001151 * Add the "self" time from the total time and the children's time.
1152 */
1153 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001154profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001155{
1156 /* Check that the result won't be negative. Can happen with recursive
1157 * calls. */
1158#ifdef WIN3264
1159 if (total->QuadPart <= children->QuadPart)
1160 return;
1161#else
1162 if (total->tv_sec < children->tv_sec
1163 || (total->tv_sec == children->tv_sec
1164 && total->tv_usec <= children->tv_usec))
1165 return;
1166#endif
1167 profile_add(self, total);
1168 profile_sub(self, children);
1169}
1170
1171/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001172 * Get the current waittime.
1173 */
1174 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001175profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001176{
1177 *tm = prof_wait_time;
1178}
1179
1180/*
1181 * Subtract the passed waittime since "tm" from "tma".
1182 */
1183 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001184profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001185{
1186 proftime_T tm3 = prof_wait_time;
1187
1188 profile_sub(&tm3, tm);
1189 profile_sub(tma, &tm3);
1190}
1191
1192/*
1193 * Return TRUE if "tm1" and "tm2" are equal.
1194 */
1195 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001196profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001197{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001198# ifdef WIN3264
1199 return (tm1->QuadPart == tm2->QuadPart);
1200# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001201 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001202# endif
1203}
1204
1205/*
1206 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1207 */
1208 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001209profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001210{
1211# ifdef WIN3264
1212 return (int)(tm2->QuadPart - tm1->QuadPart);
1213# else
1214 if (tm1->tv_sec == tm2->tv_sec)
1215 return tm2->tv_usec - tm1->tv_usec;
1216 return tm2->tv_sec - tm1->tv_sec;
1217# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001218}
1219
Bram Moolenaar05159a02005-02-26 23:04:13 +00001220static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001221static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001222
1223/*
1224 * ":profile cmd args"
1225 */
1226 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001227ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001228{
1229 char_u *e;
1230 int len;
1231
1232 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001233 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001234 e = skipwhite(e);
1235
1236 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1237 {
1238 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001239 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001240 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001241 profile_zero(&prof_wait_time);
1242 set_vim_var_nr(VV_PROFILING, 1L);
1243 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001244 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001245 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001246 else if (STRCMP(eap->arg, "pause") == 0)
1247 {
1248 if (do_profiling == PROF_YES)
1249 profile_start(&pause_time);
1250 do_profiling = PROF_PAUSED;
1251 }
1252 else if (STRCMP(eap->arg, "continue") == 0)
1253 {
1254 if (do_profiling == PROF_PAUSED)
1255 {
1256 profile_end(&pause_time);
1257 profile_add(&prof_wait_time, &pause_time);
1258 }
1259 do_profiling = PROF_YES;
1260 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001261 else
1262 {
1263 /* The rest is similar to ":breakadd". */
1264 ex_breakadd(eap);
1265 }
1266}
1267
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001268/* Command line expansion for :profile. */
1269static enum
1270{
1271 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001272 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001273} pexpand_what;
1274
1275static char *pexpand_cmds[] = {
1276 "start",
1277#define PROFCMD_START 0
1278 "pause",
1279#define PROFCMD_PAUSE 1
1280 "continue",
1281#define PROFCMD_CONTINUE 2
1282 "func",
1283#define PROFCMD_FUNC 3
1284 "file",
1285#define PROFCMD_FILE 4
1286 NULL
1287#define PROFCMD_LAST 5
1288};
1289
1290/*
1291 * Function given to ExpandGeneric() to obtain the profile command
1292 * specific expansion.
1293 */
1294 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001295get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001296{
1297 switch (pexpand_what)
1298 {
1299 case PEXP_SUBCMD:
1300 return (char_u *)pexpand_cmds[idx];
1301 /* case PEXP_FUNC: TODO */
1302 default:
1303 return NULL;
1304 }
1305}
1306
1307/*
1308 * Handle command line completion for :profile command.
1309 */
1310 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001311set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001312{
1313 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001314
1315 /* Default: expand subcommands. */
1316 xp->xp_context = EXPAND_PROFILE;
1317 pexpand_what = PEXP_SUBCMD;
1318 xp->xp_pattern = arg;
1319
1320 end_subcmd = skiptowhite(arg);
1321 if (*end_subcmd == NUL)
1322 return;
1323
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001324 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001325 {
1326 xp->xp_context = EXPAND_FILES;
1327 xp->xp_pattern = skipwhite(end_subcmd);
1328 return;
1329 }
1330
1331 /* TODO: expand function names after "func" */
1332 xp->xp_context = EXPAND_NOTHING;
1333}
1334
Bram Moolenaar05159a02005-02-26 23:04:13 +00001335/*
1336 * Dump the profiling info.
1337 */
1338 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001339profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001340{
1341 FILE *fd;
1342
1343 if (profile_fname != NULL)
1344 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001345 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001346 if (fd == NULL)
1347 EMSG2(_(e_notopen), profile_fname);
1348 else
1349 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001350 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001351 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001352 fclose(fd);
1353 }
1354 }
1355}
1356
1357/*
1358 * Start profiling script "fp".
1359 */
1360 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001361script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001362{
1363 si->sn_pr_count = 0;
1364 profile_zero(&si->sn_pr_total);
1365 profile_zero(&si->sn_pr_self);
1366
1367 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1368 si->sn_prl_idx = -1;
1369 si->sn_prof_on = TRUE;
1370 si->sn_pr_nest = 0;
1371}
1372
1373/*
1374 * save time when starting to invoke another script or function.
1375 */
1376 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001377script_prof_save(
1378 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001379{
1380 scriptitem_T *si;
1381
1382 if (current_SID > 0 && current_SID <= script_items.ga_len)
1383 {
1384 si = &SCRIPT_ITEM(current_SID);
1385 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1386 profile_start(&si->sn_pr_child);
1387 }
1388 profile_get_wait(tm);
1389}
1390
1391/*
1392 * Count time spent in children after invoking another script or function.
1393 */
1394 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001395script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001396{
1397 scriptitem_T *si;
1398
1399 if (current_SID > 0 && current_SID <= script_items.ga_len)
1400 {
1401 si = &SCRIPT_ITEM(current_SID);
1402 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1403 {
1404 profile_end(&si->sn_pr_child);
1405 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1406 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1407 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1408 }
1409 }
1410}
1411
1412static proftime_T inchar_time;
1413
1414/*
1415 * Called when starting to wait for the user to type a character.
1416 */
1417 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001418prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001419{
1420 profile_start(&inchar_time);
1421}
1422
1423/*
1424 * Called when finished waiting for the user to type a character.
1425 */
1426 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001427prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001428{
1429 profile_end(&inchar_time);
1430 profile_add(&prof_wait_time, &inchar_time);
1431}
1432
1433/*
1434 * Dump the profiling results for all scripts in file "fd".
1435 */
1436 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001437script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001438{
1439 int id;
1440 scriptitem_T *si;
1441 int i;
1442 FILE *sfd;
1443 sn_prl_T *pp;
1444
1445 for (id = 1; id <= script_items.ga_len; ++id)
1446 {
1447 si = &SCRIPT_ITEM(id);
1448 if (si->sn_prof_on)
1449 {
1450 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1451 if (si->sn_pr_count == 1)
1452 fprintf(fd, "Sourced 1 time\n");
1453 else
1454 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1455 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1456 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1457 fprintf(fd, "\n");
1458 fprintf(fd, "count total (s) self (s)\n");
1459
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001460 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001461 if (sfd == NULL)
1462 fprintf(fd, "Cannot open file!\n");
1463 else
1464 {
1465 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1466 {
1467 if (vim_fgets(IObuff, IOSIZE, sfd))
1468 break;
1469 pp = &PRL_ITEM(si, i);
1470 if (pp->snp_count > 0)
1471 {
1472 fprintf(fd, "%5d ", pp->snp_count);
1473 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1474 fprintf(fd, " ");
1475 else
1476 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1477 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1478 }
1479 else
1480 fprintf(fd, " ");
1481 fprintf(fd, "%s", IObuff);
1482 }
1483 fclose(sfd);
1484 }
1485 fprintf(fd, "\n");
1486 }
1487 }
1488}
1489
1490/*
1491 * Return TRUE when a function defined in the current script should be
1492 * profiled.
1493 */
1494 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001495prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001496{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001497 if (current_SID > 0)
1498 return SCRIPT_ITEM(current_SID).sn_pr_force;
1499 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001500}
1501
1502# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001503#endif
1504
1505/*
1506 * If 'autowrite' option set, try to write the file.
1507 * Careful: autocommands may make "buf" invalid!
1508 *
1509 * return FAIL for failure, OK otherwise
1510 */
1511 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001512autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001513{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001514 int r;
1515
Bram Moolenaar071d4272004-06-13 20:20:40 +00001516 if (!(p_aw || p_awa) || !p_write
1517#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001518 /* never autowrite a "nofile" or "nowrite" buffer */
1519 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001520#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001521 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001522 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001523 r = buf_write_all(buf, forceit);
1524
1525 /* Writing may succeed but the buffer still changed, e.g., when there is a
1526 * conversion error. We do want to return FAIL then. */
1527 if (buf_valid(buf) && bufIsChanged(buf))
1528 r = FAIL;
1529 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530}
1531
1532/*
1533 * flush all buffers, except the ones that are readonly
1534 */
1535 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001536autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001537{
1538 buf_T *buf;
1539
1540 if (!(p_aw || p_awa) || !p_write)
1541 return;
1542 for (buf = firstbuf; buf; buf = buf->b_next)
1543 if (bufIsChanged(buf) && !buf->b_p_ro)
1544 {
1545 (void)buf_write_all(buf, FALSE);
1546#ifdef FEAT_AUTOCMD
1547 /* an autocommand may have deleted the buffer */
1548 if (!buf_valid(buf))
1549 buf = firstbuf;
1550#endif
1551 }
1552}
1553
1554/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001555 * Return TRUE if buffer was changed and cannot be abandoned.
1556 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001557 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001559check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001561 int forceit = (flags & CCGD_FORCEIT);
1562
Bram Moolenaar071d4272004-06-13 20:20:40 +00001563 if ( !forceit
1564 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001565 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1566 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001567 {
1568#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1569 if ((p_confirm || cmdmod.confirm) && p_write)
1570 {
1571 buf_T *buf2;
1572 int count = 0;
1573
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001574 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001575 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1576 if (bufIsChanged(buf2)
1577 && (buf2->b_ffname != NULL
1578# ifdef FEAT_BROWSE
1579 || cmdmod.browse
1580# endif
1581 ))
1582 ++count;
1583# ifdef FEAT_AUTOCMD
1584 if (!buf_valid(buf))
1585 /* Autocommand deleted buffer, oops! It's not changed now. */
1586 return FALSE;
1587# endif
1588 dialog_changed(buf, count > 1);
1589# ifdef FEAT_AUTOCMD
1590 if (!buf_valid(buf))
1591 /* Autocommand deleted buffer, oops! It's not changed now. */
1592 return FALSE;
1593# endif
1594 return bufIsChanged(buf);
1595 }
1596#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001597 if (flags & CCGD_EXCMD)
1598 EMSG(_(e_nowrtmsg));
1599 else
1600 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601 return TRUE;
1602 }
1603 return FALSE;
1604}
1605
1606#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1607
1608#if defined(FEAT_BROWSE) || defined(PROTO)
1609/*
1610 * When wanting to write a file without a file name, ask the user for a name.
1611 */
1612 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001613browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614{
1615 if (buf->b_fname == NULL)
1616 {
1617 char_u *fname;
1618
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001619 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1620 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621 if (fname != NULL)
1622 {
1623 if (setfname(buf, fname, NULL, TRUE) == OK)
1624 buf->b_flags |= BF_NOTEDITED;
1625 vim_free(fname);
1626 }
1627 }
1628}
1629#endif
1630
1631/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001632 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633 * Must check 'write' option first!
1634 */
1635 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001636dialog_changed(
1637 buf_T *buf,
1638 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001640 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001641 int ret;
1642 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001643 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001644
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001645 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001646 (buf->b_fname != NULL) ?
1647 buf->b_fname : (char_u *)_("Untitled"));
1648 if (checkall)
1649 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1650 else
1651 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1652
Bram Moolenaar8218f602012-04-25 17:32:18 +02001653 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1654 * function. */
1655 ea.append = ea.forceit = FALSE;
1656
Bram Moolenaar071d4272004-06-13 20:20:40 +00001657 if (ret == VIM_YES)
1658 {
1659#ifdef FEAT_BROWSE
1660 /* May get file name, when there is none */
1661 browse_save_fname(buf);
1662#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001663 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1664 buf->b_fname, buf->b_ffname, FALSE) == OK)
1665 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001666 (void)buf_write_all(buf, FALSE);
1667 }
1668 else if (ret == VIM_NO)
1669 {
1670 unchanged(buf, TRUE);
1671 }
1672 else if (ret == VIM_ALL)
1673 {
1674 /*
1675 * Write all modified files that can be written.
1676 * Skip readonly buffers, these need to be confirmed
1677 * individually.
1678 */
1679 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1680 {
1681 if (bufIsChanged(buf2)
1682 && (buf2->b_ffname != NULL
1683#ifdef FEAT_BROWSE
1684 || cmdmod.browse
1685#endif
1686 )
1687 && !buf2->b_p_ro)
1688 {
1689#ifdef FEAT_BROWSE
1690 /* May get file name, when there is none */
1691 browse_save_fname(buf2);
1692#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001693 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1694 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1695 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696 (void)buf_write_all(buf2, FALSE);
1697#ifdef FEAT_AUTOCMD
1698 /* an autocommand may have deleted the buffer */
1699 if (!buf_valid(buf2))
1700 buf2 = firstbuf;
1701#endif
1702 }
1703 }
1704 }
1705 else if (ret == VIM_DISCARDALL)
1706 {
1707 /*
1708 * mark all buffers as unchanged
1709 */
1710 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1711 unchanged(buf2, TRUE);
1712 }
1713}
1714#endif
1715
1716/*
1717 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1718 * hidden, autowriting it or unloading it.
1719 */
1720 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001721can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722{
1723 return ( P_HID(buf)
1724 || !bufIsChanged(buf)
1725 || buf->b_nwindows > 1
1726 || autowrite(buf, forceit) == OK
1727 || forceit);
1728}
1729
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001730static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001731
1732/*
1733 * Add a buffer number to "bufnrs", unless it's already there.
1734 */
1735 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001736add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001737{
1738 int i;
1739
1740 for (i = 0; i < *bufnump; ++i)
1741 if (bufnrs[i] == nr)
1742 return;
1743 bufnrs[*bufnump] = nr;
1744 *bufnump = *bufnump + 1;
1745}
1746
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747/*
1748 * Return TRUE if any buffer was changed and cannot be abandoned.
1749 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001750 * When "unload" is true the current buffer is unloaded instead of making it
1751 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752 */
1753 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001754check_changed_any(
1755 int hidden, /* Only check hidden buffers */
1756 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001758 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 buf_T *buf;
1760 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001761 int i;
1762 int bufnum = 0;
1763 int bufcount = 0;
1764 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001766 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767 win_T *wp;
1768#endif
1769
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001770 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1771 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001773 if (bufcount == 0)
1774 return FALSE;
1775
1776 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1777 if (bufnrs == NULL)
1778 return FALSE;
1779
1780 /* curbuf */
1781 bufnrs[bufnum++] = curbuf->b_fnum;
1782#ifdef FEAT_WINDOWS
1783 /* buf in curtab */
1784 FOR_ALL_WINDOWS(wp)
1785 if (wp->w_buffer != curbuf)
1786 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1787
1788 /* buf in other tab */
1789 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1790 if (tp != curtab)
1791 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1792 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1793#endif
1794 /* any other buf */
1795 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1796 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1797
1798 for (i = 0; i < bufnum; ++i)
1799 {
1800 buf = buflist_findnr(bufnrs[i]);
1801 if (buf == NULL)
1802 continue;
1803 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1804 {
1805 /* Try auto-writing the buffer. If this fails but the buffer no
1806 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001807 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1808 | CCGD_MULTWIN
1809 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001810 break; /* didn't save - still changes */
1811 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812 }
1813
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001814 if (i >= bufnum)
1815 goto theend;
1816
1817 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818 exiting = FALSE;
1819#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1820 /*
1821 * When ":confirm" used, don't give an error message.
1822 */
1823 if (!(p_confirm || cmdmod.confirm))
1824#endif
1825 {
1826 /* There must be a wait_return for this message, do_buffer()
1827 * may cause a redraw. But wait_return() is a no-op when vgetc()
1828 * is busy (Quit used from window menu), then make sure we don't
1829 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001830 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831 {
1832 msg_row = cmdline_row;
1833 msg_col = 0;
1834 msg_didout = FALSE;
1835 }
1836 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001837 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 {
1839 save = no_wait_return;
1840 no_wait_return = FALSE;
1841 wait_return(FALSE);
1842 no_wait_return = save;
1843 }
1844 }
1845
1846#ifdef FEAT_WINDOWS
1847 /* Try to find a window that contains the buffer. */
1848 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001849 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 if (wp->w_buffer == buf)
1851 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001852 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853# ifdef FEAT_AUTOCMD
1854 /* Paranoia: did autocms wipe out the buffer with changes? */
1855 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001856 {
1857 goto theend;
1858 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001860 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001862buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001863#endif
1864
1865 /* Open the changed buffer in the current window. */
1866 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001867 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001868
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001869theend:
1870 vim_free(bufnrs);
1871 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872}
1873
1874/*
1875 * return FAIL if there is no file name, OK if there is one
1876 * give error message for FAIL
1877 */
1878 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001879check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880{
1881 if (curbuf->b_ffname == NULL)
1882 {
1883 EMSG(_(e_noname));
1884 return FAIL;
1885 }
1886 return OK;
1887}
1888
1889/*
1890 * flush the contents of a buffer, unless it has no file name
1891 *
1892 * return FAIL for failure, OK otherwise
1893 */
1894 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001895buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896{
1897 int retval;
1898#ifdef FEAT_AUTOCMD
1899 buf_T *old_curbuf = curbuf;
1900#endif
1901
1902 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1903 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1904 FALSE, forceit, TRUE, FALSE));
1905#ifdef FEAT_AUTOCMD
1906 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001907 {
1908 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001910 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911#endif
1912 return retval;
1913}
1914
1915/*
1916 * Code to handle the argument list.
1917 */
1918
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001919static char_u *do_one_arg(char_u *str);
1920static int do_arglist(char_u *str, int what, int after);
1921static void alist_check_arg_idx(void);
1922static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001923#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001924static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001925#endif
1926#define AL_SET 1
1927#define AL_ADD 2
1928#define AL_DEL 3
1929
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001931 * Isolate one argument, taking backticks.
1932 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 * Return a pointer to the start of the next argument.
1934 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001935 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001936do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937{
1938 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939 int inbacktick;
1940
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941 inbacktick = FALSE;
1942 for (p = str; *str; ++str)
1943 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001944 /* When the backslash is used for escaping the special meaning of a
1945 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001946 if (rem_backslash(str))
1947 {
1948 *p++ = *str++;
1949 *p++ = *str;
1950 }
1951 else
1952 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001953 /* An item ends at a space not in backticks */
1954 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001956 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001958 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 }
1960 }
1961 str = skipwhite(str);
1962 *p = NUL;
1963
1964 return str;
1965}
1966
Bram Moolenaar86b68352004-12-27 21:59:20 +00001967/*
1968 * Separate the arguments in "str" and return a list of pointers in the
1969 * growarray "gap".
1970 */
1971 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001972get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001973{
1974 ga_init2(gap, (int)sizeof(char_u *), 20);
1975 while (*str != NUL)
1976 {
1977 if (ga_grow(gap, 1) == FAIL)
1978 {
1979 ga_clear(gap);
1980 return FAIL;
1981 }
1982 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1983
1984 /* Isolate one argument, change it in-place, put a NUL after it. */
1985 str = do_one_arg(str);
1986 }
1987 return OK;
1988}
1989
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001990#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001991/*
1992 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001993 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001994 * Return FAIL or OK.
1995 */
1996 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001997get_arglist_exp(
1998 char_u *str,
1999 int *fcountp,
2000 char_u ***fnamesp,
2001 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002002{
2003 garray_T ga;
2004 int i;
2005
2006 if (get_arglist(&ga, str) == FAIL)
2007 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002008 if (wig == TRUE)
2009 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2010 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2011 else
2012 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2013 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2014
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002015 ga_clear(&ga);
2016 return i;
2017}
2018#endif
2019
Bram Moolenaar071d4272004-06-13 20:20:40 +00002020#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2021/*
2022 * Redefine the argument list.
2023 */
2024 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002025set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026{
2027 do_arglist(str, AL_SET, 0);
2028}
2029#endif
2030
2031/*
2032 * "what" == AL_SET: Redefine the argument list to 'str'.
2033 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2034 * "what" == AL_DEL: remove files in 'str' from the argument list.
2035 *
2036 * Return FAIL for failure, OK otherwise.
2037 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002038 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002039do_arglist(
2040 char_u *str,
2041 int what UNUSED,
2042 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043{
2044 garray_T new_ga;
2045 int exp_count;
2046 char_u **exp_files;
2047 int i;
2048#ifdef FEAT_LISTCMDS
2049 char_u *p;
2050 int match;
2051#endif
2052
2053 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002054 * Set default argument for ":argadd" command.
2055 */
2056 if (what == AL_ADD && *str == NUL)
2057 {
2058 if (curbuf->b_ffname == NULL)
2059 return FAIL;
2060 str = curbuf->b_fname;
2061 }
2062
2063 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002064 * Collect all file name arguments in "new_ga".
2065 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002066 if (get_arglist(&new_ga, str) == FAIL)
2067 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068
2069#ifdef FEAT_LISTCMDS
2070 if (what == AL_DEL)
2071 {
2072 regmatch_T regmatch;
2073 int didone;
2074
2075 /*
2076 * Delete the items: use each item as a regexp and find a match in the
2077 * argument list.
2078 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002079 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2081 {
2082 p = ((char_u **)new_ga.ga_data)[i];
2083 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2084 if (p == NULL)
2085 break;
2086 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2087 if (regmatch.regprog == NULL)
2088 {
2089 vim_free(p);
2090 break;
2091 }
2092
2093 didone = FALSE;
2094 for (match = 0; match < ARGCOUNT; ++match)
2095 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2096 (colnr_T)0))
2097 {
2098 didone = TRUE;
2099 vim_free(ARGLIST[match].ae_fname);
2100 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2101 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2102 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 if (curwin->w_arg_idx > match)
2104 --curwin->w_arg_idx;
2105 --match;
2106 }
2107
Bram Moolenaar473de612013-06-08 18:19:48 +02002108 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002109 vim_free(p);
2110 if (!didone)
2111 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2112 }
2113 ga_clear(&new_ga);
2114 }
2115 else
2116#endif
2117 {
2118 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2119 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2120 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002121 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122 {
2123 EMSG(_(e_nomatch));
2124 return FAIL;
2125 }
2126
2127#ifdef FEAT_LISTCMDS
2128 if (what == AL_ADD)
2129 {
2130 (void)alist_add_list(exp_count, exp_files, after);
2131 vim_free(exp_files);
2132 }
2133 else /* what == AL_SET */
2134#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002135 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136 }
2137
2138 alist_check_arg_idx();
2139
2140 return OK;
2141}
2142
2143/*
2144 * Check the validity of the arg_idx for each other window.
2145 */
2146 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002147alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148{
2149#ifdef FEAT_WINDOWS
2150 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002151 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152
Bram Moolenaarf740b292006-02-16 22:11:02 +00002153 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002154 if (win->w_alist == curwin->w_alist)
2155 check_arg_idx(win);
2156#else
2157 check_arg_idx(curwin);
2158#endif
2159}
2160
2161/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002162 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002163 * index.
2164 */
2165 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002166editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002167{
2168 return !(win->w_arg_idx >= WARGCOUNT(win)
2169 || (win->w_buffer->b_fnum
2170 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2171 && (win->w_buffer->b_ffname == NULL
2172 || !(fullpathcmp(
2173 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2174 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2175}
2176
2177/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178 * Check if window "win" is editing the w_arg_idx file in its argument list.
2179 */
2180 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002181check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002182{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002183 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002184 {
2185 /* We are not editing the current entry in the argument list.
2186 * Set "arg_had_last" if we are editing the last one. */
2187 win->w_arg_idx_invalid = TRUE;
2188 if (win->w_arg_idx != WARGCOUNT(win) - 1
2189 && arg_had_last == FALSE
2190#ifdef FEAT_WINDOWS
2191 && ALIST(win) == &global_alist
2192#endif
2193 && GARGCOUNT > 0
2194 && win->w_arg_idx < GARGCOUNT
2195 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2196 || (win->w_buffer->b_ffname != NULL
2197 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2198 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2199 arg_had_last = TRUE;
2200 }
2201 else
2202 {
2203 /* We are editing the current entry in the argument list.
2204 * Set "arg_had_last" if it's also the last one */
2205 win->w_arg_idx_invalid = FALSE;
2206 if (win->w_arg_idx == WARGCOUNT(win) - 1
2207#ifdef FEAT_WINDOWS
2208 && win->w_alist == &global_alist
2209#endif
2210 )
2211 arg_had_last = TRUE;
2212 }
2213}
2214
2215/*
2216 * ":args", ":argslocal" and ":argsglobal".
2217 */
2218 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002219ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220{
2221 int i;
2222
2223 if (eap->cmdidx != CMD_args)
2224 {
2225#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2226 alist_unlink(ALIST(curwin));
2227 if (eap->cmdidx == CMD_argglobal)
2228 ALIST(curwin) = &global_alist;
2229 else /* eap->cmdidx == CMD_arglocal */
2230 alist_new();
2231#else
2232 ex_ni(eap);
2233 return;
2234#endif
2235 }
2236
2237 if (!ends_excmd(*eap->arg))
2238 {
2239 /*
2240 * ":args file ..": define new argument list, handle like ":next"
2241 * Also for ":argslocal file .." and ":argsglobal file ..".
2242 */
2243 ex_next(eap);
2244 }
2245 else
2246#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2247 if (eap->cmdidx == CMD_args)
2248#endif
2249 {
2250 /*
2251 * ":args": list arguments.
2252 */
2253 if (ARGCOUNT > 0)
2254 {
2255 /* Overwrite the command, for a short list there is no scrolling
2256 * required and no wait_return(). */
2257 gotocmdline(TRUE);
2258 for (i = 0; i < ARGCOUNT; ++i)
2259 {
2260 if (i == curwin->w_arg_idx)
2261 msg_putchar('[');
2262 msg_outtrans(alist_name(&ARGLIST[i]));
2263 if (i == curwin->w_arg_idx)
2264 msg_putchar(']');
2265 msg_putchar(' ');
2266 }
2267 }
2268 }
2269#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2270 else if (eap->cmdidx == CMD_arglocal)
2271 {
2272 garray_T *gap = &curwin->w_alist->al_ga;
2273
2274 /*
2275 * ":argslocal": make a local copy of the global argument list.
2276 */
2277 if (ga_grow(gap, GARGCOUNT) == OK)
2278 for (i = 0; i < GARGCOUNT; ++i)
2279 if (GARGLIST[i].ae_fname != NULL)
2280 {
2281 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2282 vim_strsave(GARGLIST[i].ae_fname);
2283 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2284 GARGLIST[i].ae_fnum;
2285 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 }
2287 }
2288#endif
2289}
2290
2291/*
2292 * ":previous", ":sprevious", ":Next" and ":sNext".
2293 */
2294 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002295ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296{
2297 /* If past the last one already, go to the last one. */
2298 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2299 do_argfile(eap, ARGCOUNT - 1);
2300 else
2301 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2302}
2303
2304/*
2305 * ":rewind", ":first", ":sfirst" and ":srewind".
2306 */
2307 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002308ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309{
2310 do_argfile(eap, 0);
2311}
2312
2313/*
2314 * ":last" and ":slast".
2315 */
2316 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002317ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002318{
2319 do_argfile(eap, ARGCOUNT - 1);
2320}
2321
2322/*
2323 * ":argument" and ":sargument".
2324 */
2325 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002326ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327{
2328 int i;
2329
2330 if (eap->addr_count > 0)
2331 i = eap->line2 - 1;
2332 else
2333 i = curwin->w_arg_idx;
2334 do_argfile(eap, i);
2335}
2336
2337/*
2338 * Edit file "argn" of the argument lists.
2339 */
2340 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002341do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342{
2343 int other;
2344 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002345 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346
2347 if (argn < 0 || argn >= ARGCOUNT)
2348 {
2349 if (ARGCOUNT <= 1)
2350 EMSG(_("E163: There is only one file to edit"));
2351 else if (argn < 0)
2352 EMSG(_("E164: Cannot go before first file"));
2353 else
2354 EMSG(_("E165: Cannot go beyond last file"));
2355 }
2356 else
2357 {
2358 setpcmark();
2359#ifdef FEAT_GUI
2360 need_mouse_correct = TRUE;
2361#endif
2362
2363#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002364 /* split window or create new tab page first */
2365 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 {
2367 if (win_split(0, 0) == FAIL)
2368 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002369 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 }
2371 else
2372#endif
2373 {
2374 /*
2375 * if 'hidden' set, only check for changed file when re-editing
2376 * the same buffer
2377 */
2378 other = TRUE;
2379 if (P_HID(curbuf))
2380 {
2381 p = fix_fname(alist_name(&ARGLIST[argn]));
2382 other = otherfile(p);
2383 vim_free(p);
2384 }
2385 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002386 && check_changed(curbuf, CCGD_AW
2387 | (other ? 0 : CCGD_MULTWIN)
2388 | (eap->forceit ? CCGD_FORCEIT : 0)
2389 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 return;
2391 }
2392
2393 curwin->w_arg_idx = argn;
2394 if (argn == ARGCOUNT - 1
2395#ifdef FEAT_WINDOWS
2396 && curwin->w_alist == &global_alist
2397#endif
2398 )
2399 arg_had_last = TRUE;
2400
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002401 /* Edit the file; always use the last known line number.
2402 * When it fails (e.g. Abort for already edited file) restore the
2403 * argument index. */
2404 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002406 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2407 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002408 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002410 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002411 setmark('\'');
2412 }
2413}
2414
2415/*
2416 * ":next", and commands that behave like it.
2417 */
2418 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002419ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420{
2421 int i;
2422
2423 /*
2424 * check for changed buffer now, if this fails the argument list is not
2425 * redefined.
2426 */
2427 if ( P_HID(curbuf)
2428 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002429 || !check_changed(curbuf, CCGD_AW
2430 | (eap->forceit ? CCGD_FORCEIT : 0)
2431 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432 {
2433 if (*eap->arg != NUL) /* redefine file list */
2434 {
2435 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2436 return;
2437 i = 0;
2438 }
2439 else
2440 i = curwin->w_arg_idx + (int)eap->line2;
2441 do_argfile(eap, i);
2442 }
2443}
2444
2445#ifdef FEAT_LISTCMDS
2446/*
2447 * ":argedit"
2448 */
2449 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002450ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451{
2452 int fnum;
2453 int i;
2454 char_u *s;
2455
2456 /* Add the argument to the buffer list and get the buffer number. */
2457 fnum = buflist_add(eap->arg, BLN_LISTED);
2458
2459 /* Check if this argument is already in the argument list. */
2460 for (i = 0; i < ARGCOUNT; ++i)
2461 if (ARGLIST[i].ae_fnum == fnum)
2462 break;
2463 if (i == ARGCOUNT)
2464 {
2465 /* Can't find it, add it to the argument list. */
2466 s = vim_strsave(eap->arg);
2467 if (s == NULL)
2468 return;
2469 i = alist_add_list(1, &s,
2470 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2471 if (i < 0)
2472 return;
2473 curwin->w_arg_idx = i;
2474 }
2475
2476 alist_check_arg_idx();
2477
2478 /* Edit the argument. */
2479 do_argfile(eap, i);
2480}
2481
2482/*
2483 * ":argadd"
2484 */
2485 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002486ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487{
2488 do_arglist(eap->arg, AL_ADD,
2489 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2490#ifdef FEAT_TITLE
2491 maketitle();
2492#endif
2493}
2494
2495/*
2496 * ":argdelete"
2497 */
2498 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002499ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500{
2501 int i;
2502 int n;
2503
2504 if (eap->addr_count > 0)
2505 {
2506 /* ":1,4argdel": Delete all arguments in the range. */
2507 if (eap->line2 > ARGCOUNT)
2508 eap->line2 = ARGCOUNT;
2509 n = eap->line2 - eap->line1 + 1;
2510 if (*eap->arg != NUL || n <= 0)
2511 EMSG(_(e_invarg));
2512 else
2513 {
2514 for (i = eap->line1; i <= eap->line2; ++i)
2515 vim_free(ARGLIST[i - 1].ae_fname);
2516 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2517 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2518 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 if (curwin->w_arg_idx >= eap->line2)
2520 curwin->w_arg_idx -= n;
2521 else if (curwin->w_arg_idx > eap->line1)
2522 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002523 if (ARGCOUNT == 0)
2524 curwin->w_arg_idx = 0;
2525 else if (curwin->w_arg_idx >= ARGCOUNT)
2526 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527 }
2528 }
2529 else if (*eap->arg == NUL)
2530 EMSG(_(e_argreq));
2531 else
2532 do_arglist(eap->arg, AL_DEL, 0);
2533#ifdef FEAT_TITLE
2534 maketitle();
2535#endif
2536}
2537
2538/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002539 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002540 */
2541 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002542ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543{
2544 int i;
2545#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002546 win_T *wp;
2547 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002549 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550 int next_fnum = 0;
2551#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2552 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002553#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002554 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002555#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002556 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002557 int qf_idx;
2558#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559
2560#ifndef FEAT_WINDOWS
2561 if (eap->cmdidx == CMD_windo)
2562 {
2563 ex_ni(eap);
2564 return;
2565 }
2566#endif
2567
2568#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002569 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002570 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2571 * great speed improvement. */
2572 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002574#ifdef FEAT_CLIPBOARD
2575 start_global_changes();
2576#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577
2578 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002579 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002581 || !check_changed(curbuf, CCGD_AW
2582 | (eap->forceit ? CCGD_FORCEIT : 0)
2583 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002585 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002586 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002588 wp = firstwin;
2589 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002590#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002591 switch (eap->cmdidx)
2592 {
2593#ifdef FEAT_WINDOWS
2594 case CMD_windo:
2595 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2596 i++;
2597 break;
2598 case CMD_tabdo:
2599 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2600 i++;
2601 break;
2602#endif
2603 case CMD_argdo:
2604 i = eap->line1 - 1;
2605 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002606 default:
2607 break;
2608 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002609 /* set pcmark now */
2610 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002611 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002612 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002613 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002614 || !buf->b_p_bl); buf = buf->b_next)
2615 if (buf->b_fnum > eap->line2)
2616 {
2617 buf = NULL;
2618 break;
2619 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002620 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002621 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002622 }
2623#ifdef FEAT_QUICKFIX
2624 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2625 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2626 {
2627 qf_size = qf_get_size(eap);
2628 if (qf_size <= 0 || eap->line1 > qf_size)
2629 buf = NULL;
2630 else
2631 {
2632 ex_cc(eap);
2633
2634 buf = curbuf;
2635 i = eap->line1 - 1;
2636 if (eap->addr_count <= 0)
2637 /* default is all the quickfix/location list entries */
2638 eap->line2 = qf_size;
2639 }
2640 }
2641#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642 else
2643 setpcmark();
2644 listcmd_busy = TRUE; /* avoids setting pcmark below */
2645
Bram Moolenaare25bb902015-02-27 20:33:37 +01002646 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647 {
2648 if (eap->cmdidx == CMD_argdo)
2649 {
2650 /* go to argument "i" */
2651 if (i == ARGCOUNT)
2652 break;
2653 /* Don't call do_argfile() when already there, it will try
2654 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002655 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002656 {
2657 /* Clear 'shm' to avoid that the file message overwrites
2658 * any output from the command. */
2659 p_shm_save = vim_strsave(p_shm);
2660 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002662 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2663 vim_free(p_shm_save);
2664 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665 if (curwin->w_arg_idx != i)
2666 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667 }
2668#ifdef FEAT_WINDOWS
2669 else if (eap->cmdidx == CMD_windo)
2670 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002671 /* go to window "wp" */
2672 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002674 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002675 if (curwin != wp)
2676 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002677 wp = curwin->w_next;
2678 }
2679 else if (eap->cmdidx == CMD_tabdo)
2680 {
2681 /* go to window "tp" */
2682 if (!valid_tabpage(tp))
2683 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002684 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002685 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686 }
2687#endif
2688 else if (eap->cmdidx == CMD_bufdo)
2689 {
2690 /* Remember the number of the next listed buffer, in case
2691 * ":bwipe" is used or autocommands do something strange. */
2692 next_fnum = -1;
2693 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2694 if (buf->b_p_bl)
2695 {
2696 next_fnum = buf->b_fnum;
2697 break;
2698 }
2699 }
2700
Bram Moolenaara162bc52015-01-07 16:54:21 +01002701 ++i;
2702
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 /* execute the command */
2704 do_cmdline(eap->arg, eap->getline, eap->cookie,
2705 DOCMD_VERBOSE + DOCMD_NOWAIT);
2706
2707 if (eap->cmdidx == CMD_bufdo)
2708 {
2709 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002710 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711 break;
2712 /* Check if the buffer still exists. */
2713 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2714 if (buf->b_fnum == next_fnum)
2715 break;
2716 if (buf == NULL)
2717 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002718
2719 /* Go to the next buffer. Clear 'shm' to avoid that the file
2720 * message overwrites any output from the command. */
2721 p_shm_save = vim_strsave(p_shm);
2722 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002724 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2725 vim_free(p_shm_save);
2726
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002727 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002728 if (curbuf->b_fnum != next_fnum)
2729 break;
2730 }
2731
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002732#ifdef FEAT_QUICKFIX
2733 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2734 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2735 {
2736 if (i >= qf_size || i >= eap->line2)
2737 break;
2738
2739 qf_idx = qf_get_cur_idx(eap);
2740
2741 ex_cnext(eap);
2742
2743 /* If jumping to the next quickfix entry fails, quit here */
2744 if (qf_get_cur_idx(eap) == qf_idx)
2745 break;
2746 }
2747#endif
2748
Bram Moolenaar071d4272004-06-13 20:20:40 +00002749 if (eap->cmdidx == CMD_windo)
2750 {
2751 validate_cursor(); /* cursor may have moved */
2752#ifdef FEAT_SCROLLBIND
2753 /* required when 'scrollbind' has been set */
2754 if (curwin->w_p_scb)
2755 do_check_scrollbind(TRUE);
2756#endif
2757 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002758
2759#ifdef FEAT_WINDOWS
2760 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2761 if (i+1 > eap->line2)
2762 break;
2763#endif
2764 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2765 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766 }
2767 listcmd_busy = FALSE;
2768 }
2769
2770#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002771 if (save_ei != NULL)
2772 {
2773 au_event_restore(save_ei);
2774 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2775 curbuf->b_fname, TRUE, curbuf);
2776 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002777#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002778#ifdef FEAT_CLIPBOARD
2779 end_global_changes();
2780#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002781}
2782
2783/*
2784 * Add files[count] to the arglist of the current window after arg "after".
2785 * The file names in files[count] must have been allocated and are taken over.
2786 * Files[] itself is not taken over.
2787 * Returns index of first added argument. Returns -1 when failed (out of mem).
2788 */
2789 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002790alist_add_list(
2791 int count,
2792 char_u **files,
2793 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794{
2795 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002796 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002797
2798 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2799 {
2800 if (after < 0)
2801 after = 0;
2802 if (after > ARGCOUNT)
2803 after = ARGCOUNT;
2804 if (after < ARGCOUNT)
2805 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2806 (ARGCOUNT - after) * sizeof(aentry_T));
2807 for (i = 0; i < count; ++i)
2808 {
2809 ARGLIST[after + i].ae_fname = files[i];
2810 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2811 }
2812 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002813 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2814 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002815 return after;
2816 }
2817
2818 for (i = 0; i < count; ++i)
2819 vim_free(files[i]);
2820 return -1;
2821}
2822
2823#endif /* FEAT_LISTCMDS */
2824
2825#ifdef FEAT_EVAL
2826/*
2827 * ":compiler[!] {name}"
2828 */
2829 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002830ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002831{
2832 char_u *buf;
2833 char_u *old_cur_comp = NULL;
2834 char_u *p;
2835
2836 if (*eap->arg == NUL)
2837 {
2838 /* List all compiler scripts. */
2839 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2840 /* ) keep the indenter happy... */
2841 }
2842 else
2843 {
2844 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2845 if (buf != NULL)
2846 {
2847 if (eap->forceit)
2848 {
2849 /* ":compiler! {name}" sets global options */
2850 do_cmdline_cmd((char_u *)
2851 "command -nargs=* CompilerSet set <args>");
2852 }
2853 else
2854 {
2855 /* ":compiler! {name}" sets local options.
2856 * To remain backwards compatible "current_compiler" is always
2857 * used. A user's compiler plugin may set it, the distributed
2858 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002859 * "b:current_compiler" and restore "current_compiler".
2860 * Explicitly prepend "g:" to make it work in a function. */
2861 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862 if (old_cur_comp != NULL)
2863 old_cur_comp = vim_strsave(old_cur_comp);
2864 do_cmdline_cmd((char_u *)
2865 "command -nargs=* CompilerSet setlocal <args>");
2866 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002867 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002868 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869
2870 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002871 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2873 vim_free(buf);
2874
2875 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2876
2877 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002878 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879 if (p != NULL)
2880 set_internal_string_var((char_u *)"b:current_compiler", p);
2881
2882 /* Restore "current_compiler" for ":compiler {name}". */
2883 if (!eap->forceit)
2884 {
2885 if (old_cur_comp != NULL)
2886 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002887 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888 old_cur_comp);
2889 vim_free(old_cur_comp);
2890 }
2891 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002892 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893 }
2894 }
2895 }
2896}
2897#endif
2898
2899/*
2900 * ":runtime {name}"
2901 */
2902 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002903ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002905 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906}
2907
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002908static void source_callback(char_u *fname, void *cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002909
2910 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002911source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002913 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914}
2915
2916/*
2917 * Source the file "name" from all directories in 'runtimepath'.
2918 * "name" can contain wildcards.
2919 * When "all" is TRUE, source all files, otherwise only the first one.
2920 * return FAIL when no file could be sourced, OK otherwise.
2921 */
2922 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002923source_runtime(char_u *name, int all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002925 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926}
2927
2928/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002929 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2930 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2932 * used.
2933 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002934 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002935 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2936 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002937 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 */
2939 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002940do_in_runtimepath(
2941 char_u *name,
2942 int all,
2943 void (*callback)(char_u *fname, void *ck),
2944 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945{
2946 char_u *rtp;
2947 char_u *np;
2948 char_u *buf;
2949 char_u *rtp_copy;
2950 char_u *tail;
2951 int num_files;
2952 char_u **files;
2953 int i;
2954 int did_one = FALSE;
2955#ifdef AMIGA
2956 struct Process *proc = (struct Process *)FindTask(0L);
2957 APTR save_winptr = proc->pr_WindowPtr;
2958
2959 /* Avoid a requester here for a volume that doesn't exist. */
2960 proc->pr_WindowPtr = (APTR)-1L;
2961#endif
2962
2963 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2964 * value. */
2965 rtp_copy = vim_strsave(p_rtp);
2966 buf = alloc(MAXPATHL);
2967 if (buf != NULL && rtp_copy != NULL)
2968 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002969 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002970 {
2971 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002972 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002973 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002974 verbose_leave();
2975 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002976
Bram Moolenaar071d4272004-06-13 20:20:40 +00002977 /* Loop over all entries in 'runtimepath'. */
2978 rtp = rtp_copy;
2979 while (*rtp != NUL && (all || !did_one))
2980 {
2981 /* Copy the path from 'runtimepath' to buf[]. */
2982 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002983 if (name == NULL)
2984 {
2985 (*callback)(buf, (void *) &cookie);
2986 if (!did_one)
2987 did_one = (cookie == NULL);
2988 }
2989 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990 {
2991 add_pathsep(buf);
2992 tail = buf + STRLEN(buf);
2993
2994 /* Loop over all patterns in "name" */
2995 np = name;
2996 while (*np != NUL && (all || !did_one))
2997 {
2998 /* Append the pattern from "name" to buf[]. */
2999 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3000 "\t ");
3001
3002 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003003 {
3004 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003005 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003006 verbose_leave();
3007 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008
3009 /* Expand wildcards, invoke the callback for each match. */
3010 if (gen_expand_wildcards(1, &buf, &num_files, &files,
3011 EW_FILE) == OK)
3012 {
3013 for (i = 0; i < num_files; ++i)
3014 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003015 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 did_one = TRUE;
3017 if (!all)
3018 break;
3019 }
3020 FreeWild(num_files, files);
3021 }
3022 }
3023 }
3024 }
3025 }
3026 vim_free(buf);
3027 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003028 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003029 {
3030 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003031 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003032 verbose_leave();
3033 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034
3035#ifdef AMIGA
3036 proc->pr_WindowPtr = save_winptr;
3037#endif
3038
3039 return did_one ? OK : FAIL;
3040}
3041
3042#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3043/*
3044 * ":options"
3045 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003046 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003047ex_options(
3048 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049{
3050 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3051}
3052#endif
3053
3054/*
3055 * ":source {fname}"
3056 */
3057 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003058ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059{
3060#ifdef FEAT_BROWSE
3061 if (cmdmod.browse)
3062 {
3063 char_u *fname = NULL;
3064
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003065 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3067 if (fname != NULL)
3068 {
3069 cmd_source(fname, eap);
3070 vim_free(fname);
3071 }
3072 }
3073 else
3074#endif
3075 cmd_source(eap->arg, eap);
3076}
3077
3078 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003079cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003080{
3081 if (*fname == NUL)
3082 EMSG(_(e_argreq));
3083
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003085 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003086 * Need to execute the commands directly. This is required at least
3087 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088 * - ":g" command busy
3089 * - after ":argdo", ":windo" or ":bufdo"
3090 * - another command follows
3091 * - inside a loop
3092 */
3093 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3094#ifdef FEAT_EVAL
3095 || eap->cstack->cs_idx >= 0
3096#endif
3097 );
3098
3099 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003100 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101 EMSG2(_(e_notopen), fname);
3102}
3103
3104/*
3105 * ":source" and associated commands.
3106 */
3107/*
3108 * Structure used to store info for each sourced file.
3109 * It is shared between do_source() and getsourceline().
3110 * This is required, because it needs to be handed to do_cmdline() and
3111 * sourcing can be done recursively.
3112 */
3113struct source_cookie
3114{
3115 FILE *fp; /* opened file for sourcing */
3116 char_u *nextline; /* if not NULL: line that was read ahead */
3117 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003118#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003119 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3120 int error; /* TRUE if LF found after CR-LF */
3121#endif
3122#ifdef FEAT_EVAL
3123 linenr_T breakpoint; /* next line with breakpoint or zero */
3124 char_u *fname; /* name of sourced file */
3125 int dbg_tick; /* debug_tick when breakpoint was set */
3126 int level; /* top nesting level of sourced file */
3127#endif
3128#ifdef FEAT_MBYTE
3129 vimconv_T conv; /* type of conversion */
3130#endif
3131};
3132
3133#ifdef FEAT_EVAL
3134/*
3135 * Return the address holding the next breakpoint line for a source cookie.
3136 */
3137 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003138source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139{
3140 return &((struct source_cookie *)cookie)->breakpoint;
3141}
3142
3143/*
3144 * Return the address holding the debug tick for a source cookie.
3145 */
3146 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003147source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148{
3149 return &((struct source_cookie *)cookie)->dbg_tick;
3150}
3151
3152/*
3153 * Return the nesting level for a source cookie.
3154 */
3155 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003156source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003157{
3158 return ((struct source_cookie *)cookie)->level;
3159}
3160#endif
3161
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003162static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003164#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3165# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003166static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003167
3168/*
3169 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003170 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003171 */
3172 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003173fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003175# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003176 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3177# else
3178 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003179# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180
3181 if (fd_tmp == -1)
3182 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003183
3184# ifdef HAVE_FD_CLOEXEC
3185 {
3186 int fdflags = fcntl(fd_tmp, F_GETFD);
3187 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003188 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003189 }
3190# endif
3191
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192 return fdopen(fd_tmp, READBIN);
3193}
3194#endif
3195
3196
3197/*
3198 * do_source: Read the file "fname" and execute its lines as EX commands.
3199 *
3200 * This function may be called recursively!
3201 *
3202 * return FAIL if file could not be opened, OK otherwise
3203 */
3204 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003205do_source(
3206 char_u *fname,
3207 int check_other, /* check for .vimrc and _vimrc */
3208 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003209{
3210 struct source_cookie cookie;
3211 char_u *save_sourcing_name;
3212 linenr_T save_sourcing_lnum;
3213 char_u *p;
3214 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003215 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 int retval = FAIL;
3217#ifdef FEAT_EVAL
3218 scid_T save_current_SID;
3219 static scid_T last_current_SID = 0;
3220 void *save_funccalp;
3221 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003222 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223# ifdef UNIX
3224 struct stat st;
3225 int stat_ok;
3226# endif
3227#endif
3228#ifdef STARTUPTIME
3229 struct timeval tv_rel;
3230 struct timeval tv_start;
3231#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003232#ifdef FEAT_PROFILE
3233 proftime_T wait_start;
3234#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003235
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237 if (p == NULL)
3238 return retval;
3239 fname_exp = fix_fname(p);
3240 vim_free(p);
3241 if (fname_exp == NULL)
3242 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003243 if (mch_isdir(fname_exp))
3244 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003245 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003246 goto theend;
3247 }
3248
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003249#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003250 /* Apply SourceCmd autocommands, they should get the file and source it. */
3251 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3252 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3253 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003254 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003255# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003256 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003257# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003258 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003259# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003260 goto theend;
3261 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003262
3263 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003264 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3265#endif
3266
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003267#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3269#else
3270 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3271#endif
3272 if (cookie.fp == NULL && check_other)
3273 {
3274 /*
3275 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3276 * and ".exrc" by "_exrc" or vice versa.
3277 */
3278 p = gettail(fname_exp);
3279 if ((*p == '.' || *p == '_')
3280 && (STRICMP(p + 1, "vimrc") == 0
3281 || STRICMP(p + 1, "gvimrc") == 0
3282 || STRICMP(p + 1, "exrc") == 0))
3283 {
3284 if (*p == '_')
3285 *p = '.';
3286 else
3287 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003288#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3290#else
3291 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3292#endif
3293 }
3294 }
3295
3296 if (cookie.fp == NULL)
3297 {
3298 if (p_verbose > 0)
3299 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003300 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003302 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303 else
3304 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003305 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003306 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307 }
3308 goto theend;
3309 }
3310
3311 /*
3312 * The file exists.
3313 * - In verbose mode, give a message.
3314 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3315 */
3316 if (p_verbose > 1)
3317 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003318 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003320 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321 else
3322 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003323 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003324 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003326 if (is_vimrc == DOSO_VIMRC)
3327 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3328 else if (is_vimrc == DOSO_GVIMRC)
3329 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003330
3331#ifdef USE_CRNL
3332 /* If no automatic file format: Set default to CR-NL. */
3333 if (*p_ffs == NUL)
3334 cookie.fileformat = EOL_DOS;
3335 else
3336 cookie.fileformat = EOL_UNKNOWN;
3337 cookie.error = FALSE;
3338#endif
3339
3340#ifdef USE_CR
3341 /* If no automatic file format: Set default to CR. */
3342 if (*p_ffs == NUL)
3343 cookie.fileformat = EOL_MAC;
3344 else
3345 cookie.fileformat = EOL_UNKNOWN;
3346 cookie.error = FALSE;
3347#endif
3348
3349 cookie.nextline = NULL;
3350 cookie.finished = FALSE;
3351
3352#ifdef FEAT_EVAL
3353 /*
3354 * Check if this script has a breakpoint.
3355 */
3356 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3357 cookie.fname = fname_exp;
3358 cookie.dbg_tick = debug_tick;
3359
3360 cookie.level = ex_nesting_level;
3361#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003362
3363 /*
3364 * Keep the sourcing name/lnum, for recursive calls.
3365 */
3366 save_sourcing_name = sourcing_name;
3367 sourcing_name = fname_exp;
3368 save_sourcing_lnum = sourcing_lnum;
3369 sourcing_lnum = 0;
3370
Bram Moolenaar73881402009-02-04 16:50:47 +00003371#ifdef FEAT_MBYTE
3372 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3373
3374 /* Read the first line so we can check for a UTF-8 BOM. */
3375 firstline = getsourceline(0, (void *)&cookie, 0);
3376 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3377 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3378 {
3379 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3380 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3381 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003382 if (p == NULL)
3383 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003384 if (p != NULL)
3385 {
3386 vim_free(firstline);
3387 firstline = p;
3388 }
3389 }
3390#endif
3391
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003393 if (time_fd != NULL)
3394 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395#endif
3396
3397#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003398# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003399 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003400 prof_child_enter(&wait_start); /* entering a child now */
3401# endif
3402
3403 /* Don't use local function variables, if called from a function.
3404 * Also starts profiling timer for nested script. */
3405 save_funccalp = save_funccal();
3406
Bram Moolenaar071d4272004-06-13 20:20:40 +00003407 /*
3408 * Check if this script was sourced before to finds its SID.
3409 * If it's new, generate a new SID.
3410 */
3411 save_current_SID = current_SID;
3412# ifdef UNIX
3413 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3414# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003415 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3416 {
3417 si = &SCRIPT_ITEM(current_SID);
3418 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003419 && (
3420# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003421 /* Compare dev/ino when possible, it catches symbolic
3422 * links. Also compare file names, the inode may change
3423 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003424 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003425 && (si->sn_dev == st.st_dev
3426 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003428 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003430 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003431 if (current_SID == 0)
3432 {
3433 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003434 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3435 == FAIL)
3436 goto almosttheend;
3437 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003439 ++script_items.ga_len;
3440 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3441# ifdef FEAT_PROFILE
3442 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003443# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003444 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003445 si = &SCRIPT_ITEM(current_SID);
3446 si->sn_name = fname_exp;
3447 fname_exp = NULL;
3448# ifdef UNIX
3449 if (stat_ok)
3450 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003451 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003452 si->sn_dev = st.st_dev;
3453 si->sn_ino = st.st_ino;
3454 }
3455 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003456 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003457# endif
3458
Bram Moolenaar071d4272004-06-13 20:20:40 +00003459 /* Allocate the local script variables to use for this script. */
3460 new_script_vars(current_SID);
3461 }
3462
Bram Moolenaar05159a02005-02-26 23:04:13 +00003463# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003464 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003465 {
3466 int forceit;
3467
3468 /* Check if we do profiling for this script. */
3469 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3470 {
3471 script_do_profile(si);
3472 si->sn_pr_force = forceit;
3473 }
3474 if (si->sn_prof_on)
3475 {
3476 ++si->sn_pr_count;
3477 profile_start(&si->sn_pr_start);
3478 profile_zero(&si->sn_pr_children);
3479 }
3480 }
3481# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482#endif
3483
3484 /*
3485 * Call do_cmdline, which will call getsourceline() to get the lines.
3486 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003487 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003488 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003489 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003490
3491#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003492 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003493 {
3494 /* Get "si" again, "script_items" may have been reallocated. */
3495 si = &SCRIPT_ITEM(current_SID);
3496 if (si->sn_prof_on)
3497 {
3498 profile_end(&si->sn_pr_start);
3499 profile_sub_wait(&wait_start, &si->sn_pr_start);
3500 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003501 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3502 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003503 }
3504 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003505#endif
3506
3507 if (got_int)
3508 EMSG(_(e_interr));
3509 sourcing_name = save_sourcing_name;
3510 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511 if (p_verbose > 1)
3512 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003513 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003514 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003515 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003516 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003517 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518 }
3519#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003520 if (time_fd != NULL)
3521 {
3522 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3523 time_msg((char *)IObuff, &tv_start);
3524 time_pop(&tv_rel);
3525 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526#endif
3527
3528#ifdef FEAT_EVAL
3529 /*
3530 * After a "finish" in debug mode, need to break at first command of next
3531 * sourced file.
3532 */
3533 if (save_debug_break_level > ex_nesting_level
3534 && debug_break_level == ex_nesting_level)
3535 ++debug_break_level;
3536#endif
3537
Bram Moolenaar05159a02005-02-26 23:04:13 +00003538#ifdef FEAT_EVAL
3539almosttheend:
3540 current_SID = save_current_SID;
3541 restore_funccal(save_funccalp);
3542# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003543 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003544 prof_child_exit(&wait_start); /* leaving a child now */
3545# endif
3546#endif
3547 fclose(cookie.fp);
3548 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003549 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003550#ifdef FEAT_MBYTE
3551 convert_setup(&cookie.conv, NULL, NULL);
3552#endif
3553
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554theend:
3555 vim_free(fname_exp);
3556 return retval;
3557}
3558
3559#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003560
Bram Moolenaar071d4272004-06-13 20:20:40 +00003561/*
3562 * ":scriptnames"
3563 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003564 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003565ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003566{
3567 int i;
3568
Bram Moolenaar05159a02005-02-26 23:04:13 +00003569 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3570 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003571 {
3572 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3573 NameBuff, MAXPATHL, TRUE);
3574 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003575 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003576}
3577
3578# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3579/*
3580 * Fix slashes in the list of script names for 'shellslash'.
3581 */
3582 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003583scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584{
3585 int i;
3586
Bram Moolenaar05159a02005-02-26 23:04:13 +00003587 for (i = 1; i <= script_items.ga_len; ++i)
3588 if (SCRIPT_ITEM(i).sn_name != NULL)
3589 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590}
3591# endif
3592
3593/*
3594 * Get a pointer to a script name. Used for ":verbose set".
3595 */
3596 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003597get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598{
3599 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003600 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003601 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003602 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003603 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003604 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003605 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003606 return (char_u *)_("environment variable");
3607 if (id == SID_ERROR)
3608 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003609 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003610}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003611
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003612# if defined(EXITFREE) || defined(PROTO)
3613 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003614free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003615{
3616 int i;
3617
3618 for (i = script_items.ga_len; i > 0; --i)
3619 vim_free(SCRIPT_ITEM(i).sn_name);
3620 ga_clear(&script_items);
3621}
3622# endif
3623
Bram Moolenaar071d4272004-06-13 20:20:40 +00003624#endif
3625
3626#if defined(USE_CR) || defined(PROTO)
3627
3628# if defined(__MSL__) && (__MSL__ >= 22)
3629/*
3630 * Newer version of the Metrowerks library handle DOS and UNIX files
3631 * without help.
3632 * Test with earlier versions, MSL 2.2 is the library supplied with
3633 * Codewarrior Pro 2.
3634 */
3635 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003636fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637{
3638 return fgets(s, n, stream);
3639}
3640# else
3641/*
3642 * Version of fgets() which also works for lines ending in a <CR> only
3643 * (Macintosh format).
3644 * For older versions of the Metrowerks library.
3645 * At least CodeWarrior 9 needed this code.
3646 */
3647 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01003648fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003649{
3650 int c = 0;
3651 int char_read = 0;
3652
3653 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3654 {
3655 c = fgetc(stream);
3656 s[char_read++] = c;
3657 /* If the file is in DOS format, we need to skip a NL after a CR. I
3658 * thought it was the other way around, but this appears to work... */
3659 if (c == '\n')
3660 {
3661 c = fgetc(stream);
3662 if (c != '\r')
3663 ungetc(c, stream);
3664 }
3665 }
3666
3667 s[char_read] = 0;
3668 if (char_read == 0)
3669 return NULL;
3670
3671 if (feof(stream) && char_read == 1)
3672 return NULL;
3673
3674 return s;
3675}
3676# endif
3677#endif
3678
3679/*
3680 * Get one full line from a sourced file.
3681 * Called by do_cmdline() when it's called from do_source().
3682 *
3683 * Return a pointer to the line in allocated memory.
3684 * Return NULL for end-of-file or some error.
3685 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003686 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003687getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003688{
3689 struct source_cookie *sp = (struct source_cookie *)cookie;
3690 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003691 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003692
3693#ifdef FEAT_EVAL
3694 /* If breakpoints have been added/deleted need to check for it. */
3695 if (sp->dbg_tick < debug_tick)
3696 {
3697 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3698 sp->dbg_tick = debug_tick;
3699 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003700# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003701 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003702 script_line_end();
3703# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003704#endif
3705 /*
3706 * Get current line. If there is a read-ahead line, use it, otherwise get
3707 * one now.
3708 */
3709 if (sp->finished)
3710 line = NULL;
3711 else if (sp->nextline == NULL)
3712 line = get_one_sourceline(sp);
3713 else
3714 {
3715 line = sp->nextline;
3716 sp->nextline = NULL;
3717 ++sourcing_lnum;
3718 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003719#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003720 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003721 script_line_start();
3722#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723
3724 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3725 * contain the 'C' flag. */
3726 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3727 {
3728 /* compensate for the one line read-ahead */
3729 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003730
3731 /* Get the next line and concatenate it when it starts with a
3732 * backslash. We always need to read the next line, keep it in
3733 * sp->nextline. */
3734 sp->nextline = get_one_sourceline(sp);
3735 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003737 garray_T ga;
3738
Bram Moolenaarb549a732012-02-22 18:29:33 +01003739 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003740 ga_concat(&ga, line);
3741 ga_concat(&ga, p + 1);
3742 for (;;)
3743 {
3744 vim_free(sp->nextline);
3745 sp->nextline = get_one_sourceline(sp);
3746 if (sp->nextline == NULL)
3747 break;
3748 p = skipwhite(sp->nextline);
3749 if (*p != '\\')
3750 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003751 /* Adjust the growsize to the current length to speed up
3752 * concatenating many lines. */
3753 if (ga.ga_len > 400)
3754 {
3755 if (ga.ga_len > 8000)
3756 ga.ga_growsize = 8000;
3757 else
3758 ga.ga_growsize = ga.ga_len;
3759 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003760 ga_concat(&ga, p + 1);
3761 }
3762 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003763 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003764 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765 }
3766 }
3767
3768#ifdef FEAT_MBYTE
3769 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3770 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003771 char_u *s;
3772
Bram Moolenaar071d4272004-06-13 20:20:40 +00003773 /* Convert the encoding of the script line. */
3774 s = string_convert(&sp->conv, line, NULL);
3775 if (s != NULL)
3776 {
3777 vim_free(line);
3778 line = s;
3779 }
3780 }
3781#endif
3782
3783#ifdef FEAT_EVAL
3784 /* Did we encounter a breakpoint? */
3785 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3786 {
3787 dbg_breakpoint(sp->fname, sourcing_lnum);
3788 /* Find next breakpoint. */
3789 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3790 sp->dbg_tick = debug_tick;
3791 }
3792#endif
3793
3794 return line;
3795}
3796
3797 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003798get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799{
3800 garray_T ga;
3801 int len;
3802 int c;
3803 char_u *buf;
3804#ifdef USE_CRNL
3805 int has_cr; /* CR-LF found */
3806#endif
3807#ifdef USE_CR
3808 char_u *scan;
3809#endif
3810 int have_read = FALSE;
3811
3812 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003813 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814
3815 /*
3816 * Loop until there is a finished line (or end-of-file).
3817 */
3818 sourcing_lnum++;
3819 for (;;)
3820 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003821 /* make room to read at least 120 (more) characters */
3822 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003823 break;
3824 buf = (char_u *)ga.ga_data;
3825
3826#ifdef USE_CR
3827 if (sp->fileformat == EOL_MAC)
3828 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003829 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3830 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003831 break;
3832 }
3833 else
3834#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003835 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3836 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003838 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839#ifdef USE_CRNL
3840 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3841 * CTRL-Z by its own, or after a NL. */
3842 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3843 && sp->fileformat == EOL_DOS
3844 && buf[len - 1] == Ctrl_Z)
3845 {
3846 buf[len - 1] = NUL;
3847 break;
3848 }
3849#endif
3850
3851#ifdef USE_CR
3852 /* If the read doesn't stop on a new line, and there's
3853 * some CR then we assume a Mac format */
3854 if (sp->fileformat == EOL_UNKNOWN)
3855 {
3856 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3857 sp->fileformat = EOL_MAC;
3858 else
3859 sp->fileformat = EOL_UNIX;
3860 }
3861
3862 if (sp->fileformat == EOL_MAC)
3863 {
3864 scan = vim_strchr(buf, '\r');
3865
3866 if (scan != NULL)
3867 {
3868 *scan = '\n';
3869 if (*(scan + 1) != 0)
3870 {
3871 *(scan + 1) = 0;
3872 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3873 }
3874 }
3875 len = STRLEN(buf);
3876 }
3877#endif
3878
3879 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003880 ga.ga_len = len;
3881
3882 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003883 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003884 continue;
3885
3886 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3887 {
3888#ifdef USE_CRNL
3889 has_cr = (len >= 2 && buf[len - 2] == '\r');
3890 if (sp->fileformat == EOL_UNKNOWN)
3891 {
3892 if (has_cr)
3893 sp->fileformat = EOL_DOS;
3894 else
3895 sp->fileformat = EOL_UNIX;
3896 }
3897
3898 if (sp->fileformat == EOL_DOS)
3899 {
3900 if (has_cr) /* replace trailing CR */
3901 {
3902 buf[len - 2] = '\n';
3903 --len;
3904 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905 }
3906 else /* lines like ":map xx yy^M" will have failed */
3907 {
3908 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003909 {
3910 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003911 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003912 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003913 sp->error = TRUE;
3914 sp->fileformat = EOL_UNIX;
3915 }
3916 }
3917#endif
3918 /* The '\n' is escaped if there is an odd number of ^V's just
3919 * before it, first set "c" just before the 'V's and then check
3920 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3921 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3922 ;
3923 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3924 {
3925 sourcing_lnum++;
3926 continue;
3927 }
3928
3929 buf[len - 1] = NUL; /* remove the NL */
3930 }
3931
3932 /*
3933 * Check for ^C here now and then, so recursive :so can be broken.
3934 */
3935 line_breakcheck();
3936 break;
3937 }
3938
3939 if (have_read)
3940 return (char_u *)ga.ga_data;
3941
3942 vim_free(ga.ga_data);
3943 return NULL;
3944}
3945
Bram Moolenaar05159a02005-02-26 23:04:13 +00003946#if defined(FEAT_PROFILE) || defined(PROTO)
3947/*
3948 * Called when starting to read a script line.
3949 * "sourcing_lnum" must be correct!
3950 * When skipping lines it may not actually be executed, but we won't find out
3951 * until later and we need to store the time now.
3952 */
3953 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003954script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003955{
3956 scriptitem_T *si;
3957 sn_prl_T *pp;
3958
3959 if (current_SID <= 0 || current_SID > script_items.ga_len)
3960 return;
3961 si = &SCRIPT_ITEM(current_SID);
3962 if (si->sn_prof_on && sourcing_lnum >= 1)
3963 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003964 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003965 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02003966 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00003967 si->sn_prl_idx = sourcing_lnum - 1;
3968 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3969 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3970 {
3971 /* Zero counters for a line that was not used before. */
3972 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3973 pp->snp_count = 0;
3974 profile_zero(&pp->sn_prl_total);
3975 profile_zero(&pp->sn_prl_self);
3976 ++si->sn_prl_ga.ga_len;
3977 }
3978 si->sn_prl_execed = FALSE;
3979 profile_start(&si->sn_prl_start);
3980 profile_zero(&si->sn_prl_children);
3981 profile_get_wait(&si->sn_prl_wait);
3982 }
3983}
3984
3985/*
3986 * Called when actually executing a function line.
3987 */
3988 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003989script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003990{
3991 scriptitem_T *si;
3992
3993 if (current_SID <= 0 || current_SID > script_items.ga_len)
3994 return;
3995 si = &SCRIPT_ITEM(current_SID);
3996 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3997 si->sn_prl_execed = TRUE;
3998}
3999
4000/*
4001 * Called when done with a function line.
4002 */
4003 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004004script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004005{
4006 scriptitem_T *si;
4007 sn_prl_T *pp;
4008
4009 if (current_SID <= 0 || current_SID > script_items.ga_len)
4010 return;
4011 si = &SCRIPT_ITEM(current_SID);
4012 if (si->sn_prof_on && si->sn_prl_idx >= 0
4013 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4014 {
4015 if (si->sn_prl_execed)
4016 {
4017 pp = &PRL_ITEM(si, si->sn_prl_idx);
4018 ++pp->snp_count;
4019 profile_end(&si->sn_prl_start);
4020 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004021 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004022 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4023 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004024 }
4025 si->sn_prl_idx = -1;
4026 }
4027}
4028#endif
4029
Bram Moolenaar071d4272004-06-13 20:20:40 +00004030/*
4031 * ":scriptencoding": Set encoding conversion for a sourced script.
4032 * Without the multi-byte feature it's simply ignored.
4033 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004034 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004035ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004036{
4037#ifdef FEAT_MBYTE
4038 struct source_cookie *sp;
4039 char_u *name;
4040
4041 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4042 {
4043 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4044 return;
4045 }
4046
4047 if (*eap->arg != NUL)
4048 {
4049 name = enc_canonize(eap->arg);
4050 if (name == NULL) /* out of memory */
4051 return;
4052 }
4053 else
4054 name = eap->arg;
4055
4056 /* Setup for conversion from the specified encoding to 'encoding'. */
4057 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4058 convert_setup(&sp->conv, name, p_enc);
4059
4060 if (name != eap->arg)
4061 vim_free(name);
4062#endif
4063}
4064
4065#if defined(FEAT_EVAL) || defined(PROTO)
4066/*
4067 * ":finish": Mark a sourced file as finished.
4068 */
4069 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004070ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004071{
4072 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4073 do_finish(eap, FALSE);
4074 else
4075 EMSG(_("E168: :finish used outside of a sourced file"));
4076}
4077
4078/*
4079 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4080 * Also called for a pending finish at the ":endtry" or after returning from
4081 * an extra do_cmdline(). "reanimate" is used in the latter case.
4082 */
4083 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004084do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085{
4086 int idx;
4087
4088 if (reanimate)
4089 ((struct source_cookie *)getline_cookie(eap->getline,
4090 eap->cookie))->finished = FALSE;
4091
4092 /*
4093 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4094 * not in its finally clause (which then is to be executed next) is found.
4095 * In this case, make the ":finish" pending for execution at the ":endtry".
4096 * Otherwise, finish normally.
4097 */
4098 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4099 if (idx >= 0)
4100 {
4101 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4102 report_make_pending(CSTP_FINISH, NULL);
4103 }
4104 else
4105 ((struct source_cookie *)getline_cookie(eap->getline,
4106 eap->cookie))->finished = TRUE;
4107}
4108
4109
4110/*
4111 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4112 * message for missing ":endif".
4113 * Return FALSE when not sourcing a file.
4114 */
4115 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004116source_finished(
4117 char_u *(*fgetline)(int, void *, int),
4118 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004120 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004122 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123}
4124#endif
4125
4126#if defined(FEAT_LISTCMDS) || defined(PROTO)
4127/*
4128 * ":checktime [buffer]"
4129 */
4130 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004131ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004132{
4133 buf_T *buf;
4134 int save_no_check_timestamps = no_check_timestamps;
4135
4136 no_check_timestamps = 0;
4137 if (eap->addr_count == 0) /* default is all buffers */
4138 check_timestamps(FALSE);
4139 else
4140 {
4141 buf = buflist_findnr((int)eap->line2);
4142 if (buf != NULL) /* cannot happen? */
4143 (void)buf_check_timestamp(buf, FALSE);
4144 }
4145 no_check_timestamps = save_no_check_timestamps;
4146}
4147#endif
4148
Bram Moolenaar071d4272004-06-13 20:20:40 +00004149#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4150 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004151# define HAVE_GET_LOCALE_VAL
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004152static char *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004153
4154 static char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004155get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004156{
4157 char *loc;
4158
4159 /* Obtain the locale value from the libraries. For DJGPP this is
4160 * redefined and it doesn't use the arguments. */
4161 loc = setlocale(what, NULL);
4162
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004163# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004164 if (loc != NULL)
4165 {
4166 char_u *p;
4167
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004168 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4169 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004170 p = vim_strchr(loc, '=');
4171 if (p != NULL)
4172 {
4173 loc = ++p;
4174 while (*p != NUL) /* remove trailing newline */
4175 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004176 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177 {
4178 *p = NUL;
4179 break;
4180 }
4181 ++p;
4182 }
4183 }
4184 }
4185# endif
4186
4187 return loc;
4188}
4189#endif
4190
4191
4192#ifdef WIN32
4193/*
4194 * On MS-Windows locale names are strings like "German_Germany.1252", but
4195 * gettext expects "de". Try to translate one into another here for a few
4196 * supported languages.
4197 */
4198 static char_u *
4199gettext_lang(char_u *name)
4200{
4201 int i;
4202 static char *(mtable[]) = {
4203 "afrikaans", "af",
4204 "czech", "cs",
4205 "dutch", "nl",
4206 "german", "de",
4207 "english_united kingdom", "en_GB",
4208 "spanish", "es",
4209 "french", "fr",
4210 "italian", "it",
4211 "japanese", "ja",
4212 "korean", "ko",
4213 "norwegian", "no",
4214 "polish", "pl",
4215 "russian", "ru",
4216 "slovak", "sk",
4217 "swedish", "sv",
4218 "ukrainian", "uk",
4219 "chinese_china", "zh_CN",
4220 "chinese_taiwan", "zh_TW",
4221 NULL};
4222
4223 for (i = 0; mtable[i] != NULL; i += 2)
4224 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4225 return mtable[i + 1];
4226 return name;
4227}
4228#endif
4229
4230#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4231/*
4232 * Obtain the current messages language. Used to set the default for
4233 * 'helplang'. May return NULL or an empty string.
4234 */
4235 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004236get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237{
4238 char_u *p;
4239
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004240# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241# if defined(LC_MESSAGES)
4242 p = (char_u *)get_locale_val(LC_MESSAGES);
4243# else
4244 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004245 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4246 * and LC_MONETARY may be set differently for a Japanese working in the
4247 * US. */
4248 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004249# endif
4250# else
4251 p = mch_getenv((char_u *)"LC_ALL");
4252 if (p == NULL || *p == NUL)
4253 {
4254 p = mch_getenv((char_u *)"LC_MESSAGES");
4255 if (p == NULL || *p == NUL)
4256 p = mch_getenv((char_u *)"LANG");
4257 }
4258# endif
4259# ifdef WIN32
4260 p = gettext_lang(p);
4261# endif
4262 return p;
4263}
4264#endif
4265
Bram Moolenaardef9e822004-12-31 20:58:58 +00004266/* Complicated #if; matches with where get_mess_env() is used below. */
4267#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4268 && defined(LC_MESSAGES))) \
4269 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4270 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4271 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004272static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004273
4274/*
4275 * Get the language used for messages from the environment.
4276 */
4277 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004278get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004279{
4280 char_u *p;
4281
4282 p = mch_getenv((char_u *)"LC_ALL");
4283 if (p == NULL || *p == NUL)
4284 {
4285 p = mch_getenv((char_u *)"LC_MESSAGES");
4286 if (p == NULL || *p == NUL)
4287 {
4288 p = mch_getenv((char_u *)"LANG");
4289 if (p != NULL && VIM_ISDIGIT(*p))
4290 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004291# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292 if (p == NULL || *p == NUL)
4293 p = (char_u *)get_locale_val(LC_CTYPE);
4294# endif
4295 }
4296 }
4297 return p;
4298}
4299#endif
4300
4301#if defined(FEAT_EVAL) || defined(PROTO)
4302
4303/*
4304 * Set the "v:lang" variable according to the current locale setting.
4305 * Also do "v:lc_time"and "v:ctype".
4306 */
4307 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004308set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309{
4310 char_u *loc;
4311
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004312# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004313 loc = (char_u *)get_locale_val(LC_CTYPE);
4314# else
4315 /* setlocale() not supported: use the default value */
4316 loc = (char_u *)"C";
4317# endif
4318 set_vim_var_string(VV_CTYPE, loc, -1);
4319
4320 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4321 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004322# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323 loc = (char_u *)get_locale_val(LC_MESSAGES);
4324# else
4325 loc = get_mess_env();
4326# endif
4327 set_vim_var_string(VV_LANG, loc, -1);
4328
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004329# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004330 loc = (char_u *)get_locale_val(LC_TIME);
4331# endif
4332 set_vim_var_string(VV_LC_TIME, loc, -1);
4333}
4334#endif
4335
4336#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4337 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4338/*
4339 * ":language": Set the language (locale).
4340 */
4341 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004342ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004343{
4344 char *loc;
4345 char_u *p;
4346 char_u *name;
4347 int what = LC_ALL;
4348 char *whatstr = "";
4349#ifdef LC_MESSAGES
4350# define VIM_LC_MESSAGES LC_MESSAGES
4351#else
4352# define VIM_LC_MESSAGES 6789
4353#endif
4354
4355 name = eap->arg;
4356
4357 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4358 * Allow abbreviation, but require at least 3 characters to avoid
4359 * confusion with a two letter language name "me" or "ct". */
4360 p = skiptowhite(eap->arg);
4361 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4362 {
4363 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4364 {
4365 what = VIM_LC_MESSAGES;
4366 name = skipwhite(p);
4367 whatstr = "messages ";
4368 }
4369 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4370 {
4371 what = LC_CTYPE;
4372 name = skipwhite(p);
4373 whatstr = "ctype ";
4374 }
4375 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4376 {
4377 what = LC_TIME;
4378 name = skipwhite(p);
4379 whatstr = "time ";
4380 }
4381 }
4382
4383 if (*name == NUL)
4384 {
4385#ifndef LC_MESSAGES
4386 if (what == VIM_LC_MESSAGES)
4387 p = get_mess_env();
4388 else
4389#endif
4390 p = (char_u *)setlocale(what, NULL);
4391 if (p == NULL || *p == NUL)
4392 p = (char_u *)"Unknown";
4393 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4394 }
4395 else
4396 {
4397#ifndef LC_MESSAGES
4398 if (what == VIM_LC_MESSAGES)
4399 loc = "";
4400 else
4401#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004402 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004403 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004404#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4405 /* Make sure strtod() uses a decimal point, not a comma. */
4406 setlocale(LC_NUMERIC, "C");
4407#endif
4408 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004409 if (loc == NULL)
4410 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4411 else
4412 {
4413#ifdef HAVE_NL_MSG_CAT_CNTR
4414 /* Need to do this for GNU gettext, otherwise cached translations
4415 * will be used again. */
4416 extern int _nl_msg_cat_cntr;
4417
4418 ++_nl_msg_cat_cntr;
4419#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004420 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004421 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4422
4423 if (what != LC_TIME)
4424 {
4425 /* Tell gettext() what to translate to. It apparently doesn't
4426 * use the currently effective locale. Also do this when
4427 * FEAT_GETTEXT isn't defined, so that shell commands use this
4428 * value. */
4429 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004430 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004431 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004432
4433 /* Clear $LANGUAGE because GNU gettext uses it. */
4434 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004435# ifdef WIN32
4436 /* Apparently MS-Windows printf() may cause a crash when
4437 * we give it 8-bit text while it's expecting text in the
4438 * current locale. This call avoids that. */
4439 setlocale(LC_CTYPE, "C");
4440# endif
4441 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004442 if (what != LC_CTYPE)
4443 {
4444 char_u *mname;
4445#ifdef WIN32
4446 mname = gettext_lang(name);
4447#else
4448 mname = name;
4449#endif
4450 vim_setenv((char_u *)"LC_MESSAGES", mname);
4451#ifdef FEAT_MULTI_LANG
4452 set_helplang_default(mname);
4453#endif
4454 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455 }
4456
4457# ifdef FEAT_EVAL
4458 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4459 set_lang_var();
4460# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004461# ifdef FEAT_TITLE
4462 maketitle();
4463# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004464 }
4465 }
4466}
4467
4468# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004469
4470static char_u **locales = NULL; /* Array of all available locales */
4471static int did_init_locales = FALSE;
4472
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004473static void init_locales(void);
4474static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004475
4476/*
4477 * Lazy initialization of all available locales.
4478 */
4479 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004480init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004481{
4482 if (!did_init_locales)
4483 {
4484 did_init_locales = TRUE;
4485 locales = find_locales();
4486 }
4487}
4488
4489/* Return an array of strings for all available locales + NULL for the
4490 * last element. Return NULL in case of error. */
4491 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004492find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004493{
4494 garray_T locales_ga;
4495 char_u *loc;
4496
4497 /* Find all available locales by running command "locale -a". If this
4498 * doesn't work we won't have completion. */
4499 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004500 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004501 if (locale_a == NULL)
4502 return NULL;
4503 ga_init2(&locales_ga, sizeof(char_u *), 20);
4504
4505 /* Transform locale_a string where each locale is separated by "\n"
4506 * into an array of locale strings. */
4507 loc = (char_u *)strtok((char *)locale_a, "\n");
4508
4509 while (loc != NULL)
4510 {
4511 if (ga_grow(&locales_ga, 1) == FAIL)
4512 break;
4513 loc = vim_strsave(loc);
4514 if (loc == NULL)
4515 break;
4516
4517 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4518 loc = (char_u *)strtok(NULL, "\n");
4519 }
4520 vim_free(locale_a);
4521 if (ga_grow(&locales_ga, 1) == FAIL)
4522 {
4523 ga_clear(&locales_ga);
4524 return NULL;
4525 }
4526 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4527 return (char_u **)locales_ga.ga_data;
4528}
4529
4530# if defined(EXITFREE) || defined(PROTO)
4531 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004532free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004533{
4534 int i;
4535 if (locales != NULL)
4536 {
4537 for (i = 0; locales[i] != NULL; i++)
4538 vim_free(locales[i]);
4539 vim_free(locales);
4540 locales = NULL;
4541 }
4542}
4543# endif
4544
Bram Moolenaar071d4272004-06-13 20:20:40 +00004545/*
4546 * Function given to ExpandGeneric() to obtain the possible arguments of the
4547 * ":language" command.
4548 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004550get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551{
4552 if (idx == 0)
4553 return (char_u *)"messages";
4554 if (idx == 1)
4555 return (char_u *)"ctype";
4556 if (idx == 2)
4557 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004558
4559 init_locales();
4560 if (locales == NULL)
4561 return NULL;
4562 return locales[idx - 3];
4563}
4564
4565/*
4566 * Function given to ExpandGeneric() to obtain the available locales.
4567 */
4568 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004569get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004570{
4571 init_locales();
4572 if (locales == NULL)
4573 return NULL;
4574 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004575}
4576# endif
4577
4578#endif