blob: 98b8c8fbb53d99f76aacb0ae65cac178bdce4564 [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 Moolenaar433f7c82006-03-21 21:29:36 +00001013/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001014 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001015 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001016 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001017profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001018{
1019 if (msec <= 0) /* no limit */
1020 profile_zero(tm);
1021 else
1022 {
1023# ifdef WIN3264
1024 LARGE_INTEGER fr;
1025
1026 QueryPerformanceCounter(tm);
1027 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001028 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001029# else
1030 long usec;
1031
1032 gettimeofday(tm, NULL);
1033 usec = (long)tm->tv_usec + (long)msec * 1000;
1034 tm->tv_usec = usec % 1000000L;
1035 tm->tv_sec += usec / 1000000L;
1036# endif
1037 }
1038}
1039
1040/*
1041 * Return TRUE if the current time is past "tm".
1042 */
1043 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001044profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001045{
1046 proftime_T now;
1047
1048# ifdef WIN3264
1049 if (tm->QuadPart == 0) /* timer was not set */
1050 return FALSE;
1051 QueryPerformanceCounter(&now);
1052 return (now.QuadPart > tm->QuadPart);
1053# else
1054 if (tm->tv_sec == 0) /* timer was not set */
1055 return FALSE;
1056 gettimeofday(&now, NULL);
1057 return (now.tv_sec > tm->tv_sec
1058 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1059# endif
1060}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001061
1062/*
1063 * Set the time in "tm" to zero.
1064 */
1065 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001066profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001067{
1068# ifdef WIN3264
1069 tm->QuadPart = 0;
1070# else
1071 tm->tv_usec = 0;
1072 tm->tv_sec = 0;
1073# endif
1074}
1075
Bram Moolenaar76929292008-01-06 19:07:36 +00001076# endif /* FEAT_PROFILE || FEAT_RELTIME */
1077
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001078#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1079# if defined(HAVE_MATH_H)
1080# include <math.h>
1081# endif
1082
1083/*
1084 * Divide the time "tm" by "count" and store in "tm2".
1085 */
1086 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001087profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001088{
1089 if (count == 0)
1090 profile_zero(tm2);
1091 else
1092 {
1093# ifdef WIN3264
1094 tm2->QuadPart = tm->QuadPart / count;
1095# else
1096 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1097
1098 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001099 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001100# endif
1101 }
1102}
1103#endif
1104
Bram Moolenaar76929292008-01-06 19:07:36 +00001105# if defined(FEAT_PROFILE) || defined(PROTO)
1106/*
1107 * Functions for profiling.
1108 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001109static void script_do_profile(scriptitem_T *si);
1110static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001111static proftime_T prof_wait_time;
1112
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001113/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001114 * Add the time "tm2" to "tm".
1115 */
1116 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001117profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001118{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001119# ifdef WIN3264
1120 tm->QuadPart += tm2->QuadPart;
1121# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001122 tm->tv_usec += tm2->tv_usec;
1123 tm->tv_sec += tm2->tv_sec;
1124 if (tm->tv_usec >= 1000000)
1125 {
1126 tm->tv_usec -= 1000000;
1127 ++tm->tv_sec;
1128 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001129# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001130}
1131
1132/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001133 * Add the "self" time from the total time and the children's time.
1134 */
1135 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001136profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001137{
1138 /* Check that the result won't be negative. Can happen with recursive
1139 * calls. */
1140#ifdef WIN3264
1141 if (total->QuadPart <= children->QuadPart)
1142 return;
1143#else
1144 if (total->tv_sec < children->tv_sec
1145 || (total->tv_sec == children->tv_sec
1146 && total->tv_usec <= children->tv_usec))
1147 return;
1148#endif
1149 profile_add(self, total);
1150 profile_sub(self, children);
1151}
1152
1153/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001154 * Get the current waittime.
1155 */
1156 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001157profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001158{
1159 *tm = prof_wait_time;
1160}
1161
1162/*
1163 * Subtract the passed waittime since "tm" from "tma".
1164 */
1165 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001166profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001167{
1168 proftime_T tm3 = prof_wait_time;
1169
1170 profile_sub(&tm3, tm);
1171 profile_sub(tma, &tm3);
1172}
1173
1174/*
1175 * Return TRUE if "tm1" and "tm2" are equal.
1176 */
1177 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001178profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001179{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001180# ifdef WIN3264
1181 return (tm1->QuadPart == tm2->QuadPart);
1182# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001183 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001184# endif
1185}
1186
1187/*
1188 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1189 */
1190 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001191profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001192{
1193# ifdef WIN3264
1194 return (int)(tm2->QuadPart - tm1->QuadPart);
1195# else
1196 if (tm1->tv_sec == tm2->tv_sec)
1197 return tm2->tv_usec - tm1->tv_usec;
1198 return tm2->tv_sec - tm1->tv_sec;
1199# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001200}
1201
Bram Moolenaar05159a02005-02-26 23:04:13 +00001202static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001203static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001204
1205/*
1206 * ":profile cmd args"
1207 */
1208 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001209ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001210{
1211 char_u *e;
1212 int len;
1213
1214 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001215 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001216 e = skipwhite(e);
1217
1218 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1219 {
1220 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001221 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001222 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001223 profile_zero(&prof_wait_time);
1224 set_vim_var_nr(VV_PROFILING, 1L);
1225 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001226 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001227 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001228 else if (STRCMP(eap->arg, "pause") == 0)
1229 {
1230 if (do_profiling == PROF_YES)
1231 profile_start(&pause_time);
1232 do_profiling = PROF_PAUSED;
1233 }
1234 else if (STRCMP(eap->arg, "continue") == 0)
1235 {
1236 if (do_profiling == PROF_PAUSED)
1237 {
1238 profile_end(&pause_time);
1239 profile_add(&prof_wait_time, &pause_time);
1240 }
1241 do_profiling = PROF_YES;
1242 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001243 else
1244 {
1245 /* The rest is similar to ":breakadd". */
1246 ex_breakadd(eap);
1247 }
1248}
1249
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001250/* Command line expansion for :profile. */
1251static enum
1252{
1253 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001254 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001255} pexpand_what;
1256
1257static char *pexpand_cmds[] = {
1258 "start",
1259#define PROFCMD_START 0
1260 "pause",
1261#define PROFCMD_PAUSE 1
1262 "continue",
1263#define PROFCMD_CONTINUE 2
1264 "func",
1265#define PROFCMD_FUNC 3
1266 "file",
1267#define PROFCMD_FILE 4
1268 NULL
1269#define PROFCMD_LAST 5
1270};
1271
1272/*
1273 * Function given to ExpandGeneric() to obtain the profile command
1274 * specific expansion.
1275 */
1276 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001277get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001278{
1279 switch (pexpand_what)
1280 {
1281 case PEXP_SUBCMD:
1282 return (char_u *)pexpand_cmds[idx];
1283 /* case PEXP_FUNC: TODO */
1284 default:
1285 return NULL;
1286 }
1287}
1288
1289/*
1290 * Handle command line completion for :profile command.
1291 */
1292 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001293set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001294{
1295 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001296
1297 /* Default: expand subcommands. */
1298 xp->xp_context = EXPAND_PROFILE;
1299 pexpand_what = PEXP_SUBCMD;
1300 xp->xp_pattern = arg;
1301
1302 end_subcmd = skiptowhite(arg);
1303 if (*end_subcmd == NUL)
1304 return;
1305
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001306 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001307 {
1308 xp->xp_context = EXPAND_FILES;
1309 xp->xp_pattern = skipwhite(end_subcmd);
1310 return;
1311 }
1312
1313 /* TODO: expand function names after "func" */
1314 xp->xp_context = EXPAND_NOTHING;
1315}
1316
Bram Moolenaar05159a02005-02-26 23:04:13 +00001317/*
1318 * Dump the profiling info.
1319 */
1320 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001321profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001322{
1323 FILE *fd;
1324
1325 if (profile_fname != NULL)
1326 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001327 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001328 if (fd == NULL)
1329 EMSG2(_(e_notopen), profile_fname);
1330 else
1331 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001332 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001333 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001334 fclose(fd);
1335 }
1336 }
1337}
1338
1339/*
1340 * Start profiling script "fp".
1341 */
1342 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001343script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001344{
1345 si->sn_pr_count = 0;
1346 profile_zero(&si->sn_pr_total);
1347 profile_zero(&si->sn_pr_self);
1348
1349 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1350 si->sn_prl_idx = -1;
1351 si->sn_prof_on = TRUE;
1352 si->sn_pr_nest = 0;
1353}
1354
1355/*
1356 * save time when starting to invoke another script or function.
1357 */
1358 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001359script_prof_save(
1360 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001361{
1362 scriptitem_T *si;
1363
1364 if (current_SID > 0 && current_SID <= script_items.ga_len)
1365 {
1366 si = &SCRIPT_ITEM(current_SID);
1367 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1368 profile_start(&si->sn_pr_child);
1369 }
1370 profile_get_wait(tm);
1371}
1372
1373/*
1374 * Count time spent in children after invoking another script or function.
1375 */
1376 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001377script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001378{
1379 scriptitem_T *si;
1380
1381 if (current_SID > 0 && current_SID <= script_items.ga_len)
1382 {
1383 si = &SCRIPT_ITEM(current_SID);
1384 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1385 {
1386 profile_end(&si->sn_pr_child);
1387 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1388 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1389 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1390 }
1391 }
1392}
1393
1394static proftime_T inchar_time;
1395
1396/*
1397 * Called when starting to wait for the user to type a character.
1398 */
1399 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001400prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001401{
1402 profile_start(&inchar_time);
1403}
1404
1405/*
1406 * Called when finished waiting for the user to type a character.
1407 */
1408 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001409prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001410{
1411 profile_end(&inchar_time);
1412 profile_add(&prof_wait_time, &inchar_time);
1413}
1414
1415/*
1416 * Dump the profiling results for all scripts in file "fd".
1417 */
1418 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001419script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001420{
1421 int id;
1422 scriptitem_T *si;
1423 int i;
1424 FILE *sfd;
1425 sn_prl_T *pp;
1426
1427 for (id = 1; id <= script_items.ga_len; ++id)
1428 {
1429 si = &SCRIPT_ITEM(id);
1430 if (si->sn_prof_on)
1431 {
1432 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1433 if (si->sn_pr_count == 1)
1434 fprintf(fd, "Sourced 1 time\n");
1435 else
1436 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1437 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1438 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1439 fprintf(fd, "\n");
1440 fprintf(fd, "count total (s) self (s)\n");
1441
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001442 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001443 if (sfd == NULL)
1444 fprintf(fd, "Cannot open file!\n");
1445 else
1446 {
1447 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1448 {
1449 if (vim_fgets(IObuff, IOSIZE, sfd))
1450 break;
1451 pp = &PRL_ITEM(si, i);
1452 if (pp->snp_count > 0)
1453 {
1454 fprintf(fd, "%5d ", pp->snp_count);
1455 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1456 fprintf(fd, " ");
1457 else
1458 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1459 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1460 }
1461 else
1462 fprintf(fd, " ");
1463 fprintf(fd, "%s", IObuff);
1464 }
1465 fclose(sfd);
1466 }
1467 fprintf(fd, "\n");
1468 }
1469 }
1470}
1471
1472/*
1473 * Return TRUE when a function defined in the current script should be
1474 * profiled.
1475 */
1476 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001477prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001478{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001479 if (current_SID > 0)
1480 return SCRIPT_ITEM(current_SID).sn_pr_force;
1481 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001482}
1483
1484# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001485#endif
1486
1487/*
1488 * If 'autowrite' option set, try to write the file.
1489 * Careful: autocommands may make "buf" invalid!
1490 *
1491 * return FAIL for failure, OK otherwise
1492 */
1493 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001494autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001495{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001496 int r;
1497
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498 if (!(p_aw || p_awa) || !p_write
1499#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001500 /* never autowrite a "nofile" or "nowrite" buffer */
1501 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001502#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001503 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001505 r = buf_write_all(buf, forceit);
1506
1507 /* Writing may succeed but the buffer still changed, e.g., when there is a
1508 * conversion error. We do want to return FAIL then. */
1509 if (buf_valid(buf) && bufIsChanged(buf))
1510 r = FAIL;
1511 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001512}
1513
1514/*
1515 * flush all buffers, except the ones that are readonly
1516 */
1517 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001518autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001519{
1520 buf_T *buf;
1521
1522 if (!(p_aw || p_awa) || !p_write)
1523 return;
1524 for (buf = firstbuf; buf; buf = buf->b_next)
1525 if (bufIsChanged(buf) && !buf->b_p_ro)
1526 {
1527 (void)buf_write_all(buf, FALSE);
1528#ifdef FEAT_AUTOCMD
1529 /* an autocommand may have deleted the buffer */
1530 if (!buf_valid(buf))
1531 buf = firstbuf;
1532#endif
1533 }
1534}
1535
1536/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001537 * Return TRUE if buffer was changed and cannot be abandoned.
1538 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001539 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001540 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001541check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001542{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001543 int forceit = (flags & CCGD_FORCEIT);
1544
Bram Moolenaar071d4272004-06-13 20:20:40 +00001545 if ( !forceit
1546 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001547 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1548 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001549 {
1550#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1551 if ((p_confirm || cmdmod.confirm) && p_write)
1552 {
1553 buf_T *buf2;
1554 int count = 0;
1555
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001556 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001557 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1558 if (bufIsChanged(buf2)
1559 && (buf2->b_ffname != NULL
1560# ifdef FEAT_BROWSE
1561 || cmdmod.browse
1562# endif
1563 ))
1564 ++count;
1565# ifdef FEAT_AUTOCMD
1566 if (!buf_valid(buf))
1567 /* Autocommand deleted buffer, oops! It's not changed now. */
1568 return FALSE;
1569# endif
1570 dialog_changed(buf, count > 1);
1571# ifdef FEAT_AUTOCMD
1572 if (!buf_valid(buf))
1573 /* Autocommand deleted buffer, oops! It's not changed now. */
1574 return FALSE;
1575# endif
1576 return bufIsChanged(buf);
1577 }
1578#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001579 if (flags & CCGD_EXCMD)
1580 EMSG(_(e_nowrtmsg));
1581 else
1582 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583 return TRUE;
1584 }
1585 return FALSE;
1586}
1587
1588#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1589
1590#if defined(FEAT_BROWSE) || defined(PROTO)
1591/*
1592 * When wanting to write a file without a file name, ask the user for a name.
1593 */
1594 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001595browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596{
1597 if (buf->b_fname == NULL)
1598 {
1599 char_u *fname;
1600
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001601 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1602 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001603 if (fname != NULL)
1604 {
1605 if (setfname(buf, fname, NULL, TRUE) == OK)
1606 buf->b_flags |= BF_NOTEDITED;
1607 vim_free(fname);
1608 }
1609 }
1610}
1611#endif
1612
1613/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001614 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 * Must check 'write' option first!
1616 */
1617 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001618dialog_changed(
1619 buf_T *buf,
1620 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001622 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001623 int ret;
1624 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001625 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001626
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001627 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001628 (buf->b_fname != NULL) ?
1629 buf->b_fname : (char_u *)_("Untitled"));
1630 if (checkall)
1631 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1632 else
1633 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1634
Bram Moolenaar8218f602012-04-25 17:32:18 +02001635 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1636 * function. */
1637 ea.append = ea.forceit = FALSE;
1638
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639 if (ret == VIM_YES)
1640 {
1641#ifdef FEAT_BROWSE
1642 /* May get file name, when there is none */
1643 browse_save_fname(buf);
1644#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001645 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1646 buf->b_fname, buf->b_ffname, FALSE) == OK)
1647 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648 (void)buf_write_all(buf, FALSE);
1649 }
1650 else if (ret == VIM_NO)
1651 {
1652 unchanged(buf, TRUE);
1653 }
1654 else if (ret == VIM_ALL)
1655 {
1656 /*
1657 * Write all modified files that can be written.
1658 * Skip readonly buffers, these need to be confirmed
1659 * individually.
1660 */
1661 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1662 {
1663 if (bufIsChanged(buf2)
1664 && (buf2->b_ffname != NULL
1665#ifdef FEAT_BROWSE
1666 || cmdmod.browse
1667#endif
1668 )
1669 && !buf2->b_p_ro)
1670 {
1671#ifdef FEAT_BROWSE
1672 /* May get file name, when there is none */
1673 browse_save_fname(buf2);
1674#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001675 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1676 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1677 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678 (void)buf_write_all(buf2, FALSE);
1679#ifdef FEAT_AUTOCMD
1680 /* an autocommand may have deleted the buffer */
1681 if (!buf_valid(buf2))
1682 buf2 = firstbuf;
1683#endif
1684 }
1685 }
1686 }
1687 else if (ret == VIM_DISCARDALL)
1688 {
1689 /*
1690 * mark all buffers as unchanged
1691 */
1692 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1693 unchanged(buf2, TRUE);
1694 }
1695}
1696#endif
1697
1698/*
1699 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1700 * hidden, autowriting it or unloading it.
1701 */
1702 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001703can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001704{
1705 return ( P_HID(buf)
1706 || !bufIsChanged(buf)
1707 || buf->b_nwindows > 1
1708 || autowrite(buf, forceit) == OK
1709 || forceit);
1710}
1711
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001712static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001713
1714/*
1715 * Add a buffer number to "bufnrs", unless it's already there.
1716 */
1717 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001718add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001719{
1720 int i;
1721
1722 for (i = 0; i < *bufnump; ++i)
1723 if (bufnrs[i] == nr)
1724 return;
1725 bufnrs[*bufnump] = nr;
1726 *bufnump = *bufnump + 1;
1727}
1728
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729/*
1730 * Return TRUE if any buffer was changed and cannot be abandoned.
1731 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001732 * When "unload" is true the current buffer is unloaded instead of making it
1733 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 */
1735 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001736check_changed_any(
1737 int hidden, /* Only check hidden buffers */
1738 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001740 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741 buf_T *buf;
1742 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001743 int i;
1744 int bufnum = 0;
1745 int bufcount = 0;
1746 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001748 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749 win_T *wp;
1750#endif
1751
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001752 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1753 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001754
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001755 if (bufcount == 0)
1756 return FALSE;
1757
1758 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1759 if (bufnrs == NULL)
1760 return FALSE;
1761
1762 /* curbuf */
1763 bufnrs[bufnum++] = curbuf->b_fnum;
1764#ifdef FEAT_WINDOWS
1765 /* buf in curtab */
1766 FOR_ALL_WINDOWS(wp)
1767 if (wp->w_buffer != curbuf)
1768 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1769
1770 /* buf in other tab */
1771 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1772 if (tp != curtab)
1773 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1774 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1775#endif
1776 /* any other buf */
1777 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1778 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1779
1780 for (i = 0; i < bufnum; ++i)
1781 {
1782 buf = buflist_findnr(bufnrs[i]);
1783 if (buf == NULL)
1784 continue;
1785 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1786 {
1787 /* Try auto-writing the buffer. If this fails but the buffer no
1788 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001789 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1790 | CCGD_MULTWIN
1791 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001792 break; /* didn't save - still changes */
1793 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 }
1795
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001796 if (i >= bufnum)
1797 goto theend;
1798
1799 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 exiting = FALSE;
1801#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1802 /*
1803 * When ":confirm" used, don't give an error message.
1804 */
1805 if (!(p_confirm || cmdmod.confirm))
1806#endif
1807 {
1808 /* There must be a wait_return for this message, do_buffer()
1809 * may cause a redraw. But wait_return() is a no-op when vgetc()
1810 * is busy (Quit used from window menu), then make sure we don't
1811 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001812 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813 {
1814 msg_row = cmdline_row;
1815 msg_col = 0;
1816 msg_didout = FALSE;
1817 }
1818 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001819 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820 {
1821 save = no_wait_return;
1822 no_wait_return = FALSE;
1823 wait_return(FALSE);
1824 no_wait_return = save;
1825 }
1826 }
1827
1828#ifdef FEAT_WINDOWS
1829 /* Try to find a window that contains the buffer. */
1830 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001831 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832 if (wp->w_buffer == buf)
1833 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001834 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835# ifdef FEAT_AUTOCMD
1836 /* Paranoia: did autocms wipe out the buffer with changes? */
1837 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001838 {
1839 goto theend;
1840 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001841# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001842 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001843 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001844buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001845#endif
1846
1847 /* Open the changed buffer in the current window. */
1848 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001849 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001851theend:
1852 vim_free(bufnrs);
1853 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854}
1855
1856/*
1857 * return FAIL if there is no file name, OK if there is one
1858 * give error message for FAIL
1859 */
1860 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001861check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862{
1863 if (curbuf->b_ffname == NULL)
1864 {
1865 EMSG(_(e_noname));
1866 return FAIL;
1867 }
1868 return OK;
1869}
1870
1871/*
1872 * flush the contents of a buffer, unless it has no file name
1873 *
1874 * return FAIL for failure, OK otherwise
1875 */
1876 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001877buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001878{
1879 int retval;
1880#ifdef FEAT_AUTOCMD
1881 buf_T *old_curbuf = curbuf;
1882#endif
1883
1884 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1885 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1886 FALSE, forceit, TRUE, FALSE));
1887#ifdef FEAT_AUTOCMD
1888 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001889 {
1890 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001892 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893#endif
1894 return retval;
1895}
1896
1897/*
1898 * Code to handle the argument list.
1899 */
1900
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001901static char_u *do_one_arg(char_u *str);
1902static int do_arglist(char_u *str, int what, int after);
1903static void alist_check_arg_idx(void);
1904static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001905#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001906static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001907#endif
1908#define AL_SET 1
1909#define AL_ADD 2
1910#define AL_DEL 3
1911
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001913 * Isolate one argument, taking backticks.
1914 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915 * Return a pointer to the start of the next argument.
1916 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001917 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001918do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919{
1920 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 int inbacktick;
1922
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923 inbacktick = FALSE;
1924 for (p = str; *str; ++str)
1925 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001926 /* When the backslash is used for escaping the special meaning of a
1927 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 if (rem_backslash(str))
1929 {
1930 *p++ = *str++;
1931 *p++ = *str;
1932 }
1933 else
1934 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001935 /* An item ends at a space not in backticks */
1936 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001938 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001940 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941 }
1942 }
1943 str = skipwhite(str);
1944 *p = NUL;
1945
1946 return str;
1947}
1948
Bram Moolenaar86b68352004-12-27 21:59:20 +00001949/*
1950 * Separate the arguments in "str" and return a list of pointers in the
1951 * growarray "gap".
1952 */
1953 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001954get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001955{
1956 ga_init2(gap, (int)sizeof(char_u *), 20);
1957 while (*str != NUL)
1958 {
1959 if (ga_grow(gap, 1) == FAIL)
1960 {
1961 ga_clear(gap);
1962 return FAIL;
1963 }
1964 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1965
1966 /* Isolate one argument, change it in-place, put a NUL after it. */
1967 str = do_one_arg(str);
1968 }
1969 return OK;
1970}
1971
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001972#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001973/*
1974 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001975 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001976 * Return FAIL or OK.
1977 */
1978 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001979get_arglist_exp(
1980 char_u *str,
1981 int *fcountp,
1982 char_u ***fnamesp,
1983 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001984{
1985 garray_T ga;
1986 int i;
1987
1988 if (get_arglist(&ga, str) == FAIL)
1989 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001990 if (wig == TRUE)
1991 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1992 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1993 else
1994 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1995 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1996
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001997 ga_clear(&ga);
1998 return i;
1999}
2000#endif
2001
Bram Moolenaar071d4272004-06-13 20:20:40 +00002002#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2003/*
2004 * Redefine the argument list.
2005 */
2006 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002007set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002008{
2009 do_arglist(str, AL_SET, 0);
2010}
2011#endif
2012
2013/*
2014 * "what" == AL_SET: Redefine the argument list to 'str'.
2015 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2016 * "what" == AL_DEL: remove files in 'str' from the argument list.
2017 *
2018 * Return FAIL for failure, OK otherwise.
2019 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002020 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002021do_arglist(
2022 char_u *str,
2023 int what UNUSED,
2024 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025{
2026 garray_T new_ga;
2027 int exp_count;
2028 char_u **exp_files;
2029 int i;
2030#ifdef FEAT_LISTCMDS
2031 char_u *p;
2032 int match;
2033#endif
2034
2035 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002036 * Set default argument for ":argadd" command.
2037 */
2038 if (what == AL_ADD && *str == NUL)
2039 {
2040 if (curbuf->b_ffname == NULL)
2041 return FAIL;
2042 str = curbuf->b_fname;
2043 }
2044
2045 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002046 * Collect all file name arguments in "new_ga".
2047 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002048 if (get_arglist(&new_ga, str) == FAIL)
2049 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002050
2051#ifdef FEAT_LISTCMDS
2052 if (what == AL_DEL)
2053 {
2054 regmatch_T regmatch;
2055 int didone;
2056
2057 /*
2058 * Delete the items: use each item as a regexp and find a match in the
2059 * argument list.
2060 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002061 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2063 {
2064 p = ((char_u **)new_ga.ga_data)[i];
2065 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2066 if (p == NULL)
2067 break;
2068 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2069 if (regmatch.regprog == NULL)
2070 {
2071 vim_free(p);
2072 break;
2073 }
2074
2075 didone = FALSE;
2076 for (match = 0; match < ARGCOUNT; ++match)
2077 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2078 (colnr_T)0))
2079 {
2080 didone = TRUE;
2081 vim_free(ARGLIST[match].ae_fname);
2082 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2083 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2084 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002085 if (curwin->w_arg_idx > match)
2086 --curwin->w_arg_idx;
2087 --match;
2088 }
2089
Bram Moolenaar473de612013-06-08 18:19:48 +02002090 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 vim_free(p);
2092 if (!didone)
2093 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2094 }
2095 ga_clear(&new_ga);
2096 }
2097 else
2098#endif
2099 {
2100 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2101 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2102 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002103 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002104 {
2105 EMSG(_(e_nomatch));
2106 return FAIL;
2107 }
2108
2109#ifdef FEAT_LISTCMDS
2110 if (what == AL_ADD)
2111 {
2112 (void)alist_add_list(exp_count, exp_files, after);
2113 vim_free(exp_files);
2114 }
2115 else /* what == AL_SET */
2116#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002117 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002118 }
2119
2120 alist_check_arg_idx();
2121
2122 return OK;
2123}
2124
2125/*
2126 * Check the validity of the arg_idx for each other window.
2127 */
2128 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002129alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002130{
2131#ifdef FEAT_WINDOWS
2132 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002133 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002134
Bram Moolenaarf740b292006-02-16 22:11:02 +00002135 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136 if (win->w_alist == curwin->w_alist)
2137 check_arg_idx(win);
2138#else
2139 check_arg_idx(curwin);
2140#endif
2141}
2142
2143/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002144 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002145 * index.
2146 */
2147 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002148editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002149{
2150 return !(win->w_arg_idx >= WARGCOUNT(win)
2151 || (win->w_buffer->b_fnum
2152 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2153 && (win->w_buffer->b_ffname == NULL
2154 || !(fullpathcmp(
2155 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2156 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2157}
2158
2159/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002160 * Check if window "win" is editing the w_arg_idx file in its argument list.
2161 */
2162 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002163check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002165 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002166 {
2167 /* We are not editing the current entry in the argument list.
2168 * Set "arg_had_last" if we are editing the last one. */
2169 win->w_arg_idx_invalid = TRUE;
2170 if (win->w_arg_idx != WARGCOUNT(win) - 1
2171 && arg_had_last == FALSE
2172#ifdef FEAT_WINDOWS
2173 && ALIST(win) == &global_alist
2174#endif
2175 && GARGCOUNT > 0
2176 && win->w_arg_idx < GARGCOUNT
2177 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2178 || (win->w_buffer->b_ffname != NULL
2179 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2180 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2181 arg_had_last = TRUE;
2182 }
2183 else
2184 {
2185 /* We are editing the current entry in the argument list.
2186 * Set "arg_had_last" if it's also the last one */
2187 win->w_arg_idx_invalid = FALSE;
2188 if (win->w_arg_idx == WARGCOUNT(win) - 1
2189#ifdef FEAT_WINDOWS
2190 && win->w_alist == &global_alist
2191#endif
2192 )
2193 arg_had_last = TRUE;
2194 }
2195}
2196
2197/*
2198 * ":args", ":argslocal" and ":argsglobal".
2199 */
2200 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002201ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002202{
2203 int i;
2204
2205 if (eap->cmdidx != CMD_args)
2206 {
2207#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2208 alist_unlink(ALIST(curwin));
2209 if (eap->cmdidx == CMD_argglobal)
2210 ALIST(curwin) = &global_alist;
2211 else /* eap->cmdidx == CMD_arglocal */
2212 alist_new();
2213#else
2214 ex_ni(eap);
2215 return;
2216#endif
2217 }
2218
2219 if (!ends_excmd(*eap->arg))
2220 {
2221 /*
2222 * ":args file ..": define new argument list, handle like ":next"
2223 * Also for ":argslocal file .." and ":argsglobal file ..".
2224 */
2225 ex_next(eap);
2226 }
2227 else
2228#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2229 if (eap->cmdidx == CMD_args)
2230#endif
2231 {
2232 /*
2233 * ":args": list arguments.
2234 */
2235 if (ARGCOUNT > 0)
2236 {
2237 /* Overwrite the command, for a short list there is no scrolling
2238 * required and no wait_return(). */
2239 gotocmdline(TRUE);
2240 for (i = 0; i < ARGCOUNT; ++i)
2241 {
2242 if (i == curwin->w_arg_idx)
2243 msg_putchar('[');
2244 msg_outtrans(alist_name(&ARGLIST[i]));
2245 if (i == curwin->w_arg_idx)
2246 msg_putchar(']');
2247 msg_putchar(' ');
2248 }
2249 }
2250 }
2251#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2252 else if (eap->cmdidx == CMD_arglocal)
2253 {
2254 garray_T *gap = &curwin->w_alist->al_ga;
2255
2256 /*
2257 * ":argslocal": make a local copy of the global argument list.
2258 */
2259 if (ga_grow(gap, GARGCOUNT) == OK)
2260 for (i = 0; i < GARGCOUNT; ++i)
2261 if (GARGLIST[i].ae_fname != NULL)
2262 {
2263 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2264 vim_strsave(GARGLIST[i].ae_fname);
2265 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2266 GARGLIST[i].ae_fnum;
2267 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002268 }
2269 }
2270#endif
2271}
2272
2273/*
2274 * ":previous", ":sprevious", ":Next" and ":sNext".
2275 */
2276 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002277ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278{
2279 /* If past the last one already, go to the last one. */
2280 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2281 do_argfile(eap, ARGCOUNT - 1);
2282 else
2283 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2284}
2285
2286/*
2287 * ":rewind", ":first", ":sfirst" and ":srewind".
2288 */
2289 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002290ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002291{
2292 do_argfile(eap, 0);
2293}
2294
2295/*
2296 * ":last" and ":slast".
2297 */
2298 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002299ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300{
2301 do_argfile(eap, ARGCOUNT - 1);
2302}
2303
2304/*
2305 * ":argument" and ":sargument".
2306 */
2307 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002308ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309{
2310 int i;
2311
2312 if (eap->addr_count > 0)
2313 i = eap->line2 - 1;
2314 else
2315 i = curwin->w_arg_idx;
2316 do_argfile(eap, i);
2317}
2318
2319/*
2320 * Edit file "argn" of the argument lists.
2321 */
2322 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002323do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324{
2325 int other;
2326 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002327 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328
2329 if (argn < 0 || argn >= ARGCOUNT)
2330 {
2331 if (ARGCOUNT <= 1)
2332 EMSG(_("E163: There is only one file to edit"));
2333 else if (argn < 0)
2334 EMSG(_("E164: Cannot go before first file"));
2335 else
2336 EMSG(_("E165: Cannot go beyond last file"));
2337 }
2338 else
2339 {
2340 setpcmark();
2341#ifdef FEAT_GUI
2342 need_mouse_correct = TRUE;
2343#endif
2344
2345#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002346 /* split window or create new tab page first */
2347 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348 {
2349 if (win_split(0, 0) == FAIL)
2350 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002351 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352 }
2353 else
2354#endif
2355 {
2356 /*
2357 * if 'hidden' set, only check for changed file when re-editing
2358 * the same buffer
2359 */
2360 other = TRUE;
2361 if (P_HID(curbuf))
2362 {
2363 p = fix_fname(alist_name(&ARGLIST[argn]));
2364 other = otherfile(p);
2365 vim_free(p);
2366 }
2367 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002368 && check_changed(curbuf, CCGD_AW
2369 | (other ? 0 : CCGD_MULTWIN)
2370 | (eap->forceit ? CCGD_FORCEIT : 0)
2371 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 return;
2373 }
2374
2375 curwin->w_arg_idx = argn;
2376 if (argn == ARGCOUNT - 1
2377#ifdef FEAT_WINDOWS
2378 && curwin->w_alist == &global_alist
2379#endif
2380 )
2381 arg_had_last = TRUE;
2382
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002383 /* Edit the file; always use the last known line number.
2384 * When it fails (e.g. Abort for already edited file) restore the
2385 * argument index. */
2386 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002387 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002388 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2389 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002390 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002391 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002392 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393 setmark('\'');
2394 }
2395}
2396
2397/*
2398 * ":next", and commands that behave like it.
2399 */
2400 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002401ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402{
2403 int i;
2404
2405 /*
2406 * check for changed buffer now, if this fails the argument list is not
2407 * redefined.
2408 */
2409 if ( P_HID(curbuf)
2410 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002411 || !check_changed(curbuf, CCGD_AW
2412 | (eap->forceit ? CCGD_FORCEIT : 0)
2413 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 {
2415 if (*eap->arg != NUL) /* redefine file list */
2416 {
2417 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2418 return;
2419 i = 0;
2420 }
2421 else
2422 i = curwin->w_arg_idx + (int)eap->line2;
2423 do_argfile(eap, i);
2424 }
2425}
2426
2427#ifdef FEAT_LISTCMDS
2428/*
2429 * ":argedit"
2430 */
2431 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002432ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433{
2434 int fnum;
2435 int i;
2436 char_u *s;
2437
2438 /* Add the argument to the buffer list and get the buffer number. */
2439 fnum = buflist_add(eap->arg, BLN_LISTED);
2440
2441 /* Check if this argument is already in the argument list. */
2442 for (i = 0; i < ARGCOUNT; ++i)
2443 if (ARGLIST[i].ae_fnum == fnum)
2444 break;
2445 if (i == ARGCOUNT)
2446 {
2447 /* Can't find it, add it to the argument list. */
2448 s = vim_strsave(eap->arg);
2449 if (s == NULL)
2450 return;
2451 i = alist_add_list(1, &s,
2452 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2453 if (i < 0)
2454 return;
2455 curwin->w_arg_idx = i;
2456 }
2457
2458 alist_check_arg_idx();
2459
2460 /* Edit the argument. */
2461 do_argfile(eap, i);
2462}
2463
2464/*
2465 * ":argadd"
2466 */
2467 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002468ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002469{
2470 do_arglist(eap->arg, AL_ADD,
2471 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2472#ifdef FEAT_TITLE
2473 maketitle();
2474#endif
2475}
2476
2477/*
2478 * ":argdelete"
2479 */
2480 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002481ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482{
2483 int i;
2484 int n;
2485
2486 if (eap->addr_count > 0)
2487 {
2488 /* ":1,4argdel": Delete all arguments in the range. */
2489 if (eap->line2 > ARGCOUNT)
2490 eap->line2 = ARGCOUNT;
2491 n = eap->line2 - eap->line1 + 1;
2492 if (*eap->arg != NUL || n <= 0)
2493 EMSG(_(e_invarg));
2494 else
2495 {
2496 for (i = eap->line1; i <= eap->line2; ++i)
2497 vim_free(ARGLIST[i - 1].ae_fname);
2498 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2499 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2500 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002501 if (curwin->w_arg_idx >= eap->line2)
2502 curwin->w_arg_idx -= n;
2503 else if (curwin->w_arg_idx > eap->line1)
2504 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002505 if (ARGCOUNT == 0)
2506 curwin->w_arg_idx = 0;
2507 else if (curwin->w_arg_idx >= ARGCOUNT)
2508 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509 }
2510 }
2511 else if (*eap->arg == NUL)
2512 EMSG(_(e_argreq));
2513 else
2514 do_arglist(eap->arg, AL_DEL, 0);
2515#ifdef FEAT_TITLE
2516 maketitle();
2517#endif
2518}
2519
2520/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002521 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002522 */
2523 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002524ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525{
2526 int i;
2527#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002528 win_T *wp;
2529 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002530#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002531 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 int next_fnum = 0;
2533#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2534 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002535#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002536 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002537#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002538 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002539 int qf_idx;
2540#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541
2542#ifndef FEAT_WINDOWS
2543 if (eap->cmdidx == CMD_windo)
2544 {
2545 ex_ni(eap);
2546 return;
2547 }
2548#endif
2549
2550#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002551 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002552 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2553 * great speed improvement. */
2554 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002556#ifdef FEAT_CLIPBOARD
2557 start_global_changes();
2558#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559
2560 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002561 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002563 || !check_changed(curbuf, CCGD_AW
2564 | (eap->forceit ? CCGD_FORCEIT : 0)
2565 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002566 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002567 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002568 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002569#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002570 wp = firstwin;
2571 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002573 switch (eap->cmdidx)
2574 {
2575#ifdef FEAT_WINDOWS
2576 case CMD_windo:
2577 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2578 i++;
2579 break;
2580 case CMD_tabdo:
2581 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2582 i++;
2583 break;
2584#endif
2585 case CMD_argdo:
2586 i = eap->line1 - 1;
2587 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002588 default:
2589 break;
2590 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002591 /* set pcmark now */
2592 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002593 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002594 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002595 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002596 || !buf->b_p_bl); buf = buf->b_next)
2597 if (buf->b_fnum > eap->line2)
2598 {
2599 buf = NULL;
2600 break;
2601 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002602 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002603 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002604 }
2605#ifdef FEAT_QUICKFIX
2606 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2607 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2608 {
2609 qf_size = qf_get_size(eap);
2610 if (qf_size <= 0 || eap->line1 > qf_size)
2611 buf = NULL;
2612 else
2613 {
2614 ex_cc(eap);
2615
2616 buf = curbuf;
2617 i = eap->line1 - 1;
2618 if (eap->addr_count <= 0)
2619 /* default is all the quickfix/location list entries */
2620 eap->line2 = qf_size;
2621 }
2622 }
2623#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624 else
2625 setpcmark();
2626 listcmd_busy = TRUE; /* avoids setting pcmark below */
2627
Bram Moolenaare25bb902015-02-27 20:33:37 +01002628 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002629 {
2630 if (eap->cmdidx == CMD_argdo)
2631 {
2632 /* go to argument "i" */
2633 if (i == ARGCOUNT)
2634 break;
2635 /* Don't call do_argfile() when already there, it will try
2636 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002637 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002638 {
2639 /* Clear 'shm' to avoid that the file message overwrites
2640 * any output from the command. */
2641 p_shm_save = vim_strsave(p_shm);
2642 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002644 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2645 vim_free(p_shm_save);
2646 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647 if (curwin->w_arg_idx != i)
2648 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649 }
2650#ifdef FEAT_WINDOWS
2651 else if (eap->cmdidx == CMD_windo)
2652 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002653 /* go to window "wp" */
2654 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002655 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002656 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002657 if (curwin != wp)
2658 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002659 wp = curwin->w_next;
2660 }
2661 else if (eap->cmdidx == CMD_tabdo)
2662 {
2663 /* go to window "tp" */
2664 if (!valid_tabpage(tp))
2665 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002666 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002667 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002668 }
2669#endif
2670 else if (eap->cmdidx == CMD_bufdo)
2671 {
2672 /* Remember the number of the next listed buffer, in case
2673 * ":bwipe" is used or autocommands do something strange. */
2674 next_fnum = -1;
2675 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2676 if (buf->b_p_bl)
2677 {
2678 next_fnum = buf->b_fnum;
2679 break;
2680 }
2681 }
2682
Bram Moolenaara162bc52015-01-07 16:54:21 +01002683 ++i;
2684
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685 /* execute the command */
2686 do_cmdline(eap->arg, eap->getline, eap->cookie,
2687 DOCMD_VERBOSE + DOCMD_NOWAIT);
2688
2689 if (eap->cmdidx == CMD_bufdo)
2690 {
2691 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002692 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 break;
2694 /* Check if the buffer still exists. */
2695 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2696 if (buf->b_fnum == next_fnum)
2697 break;
2698 if (buf == NULL)
2699 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002700
2701 /* Go to the next buffer. Clear 'shm' to avoid that the file
2702 * message overwrites any output from the command. */
2703 p_shm_save = vim_strsave(p_shm);
2704 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002705 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002706 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2707 vim_free(p_shm_save);
2708
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002709 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710 if (curbuf->b_fnum != next_fnum)
2711 break;
2712 }
2713
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002714#ifdef FEAT_QUICKFIX
2715 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2716 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2717 {
2718 if (i >= qf_size || i >= eap->line2)
2719 break;
2720
2721 qf_idx = qf_get_cur_idx(eap);
2722
2723 ex_cnext(eap);
2724
2725 /* If jumping to the next quickfix entry fails, quit here */
2726 if (qf_get_cur_idx(eap) == qf_idx)
2727 break;
2728 }
2729#endif
2730
Bram Moolenaar071d4272004-06-13 20:20:40 +00002731 if (eap->cmdidx == CMD_windo)
2732 {
2733 validate_cursor(); /* cursor may have moved */
2734#ifdef FEAT_SCROLLBIND
2735 /* required when 'scrollbind' has been set */
2736 if (curwin->w_p_scb)
2737 do_check_scrollbind(TRUE);
2738#endif
2739 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002740
2741#ifdef FEAT_WINDOWS
2742 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2743 if (i+1 > eap->line2)
2744 break;
2745#endif
2746 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2747 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748 }
2749 listcmd_busy = FALSE;
2750 }
2751
2752#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002753 if (save_ei != NULL)
2754 {
2755 au_event_restore(save_ei);
2756 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2757 curbuf->b_fname, TRUE, curbuf);
2758 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002760#ifdef FEAT_CLIPBOARD
2761 end_global_changes();
2762#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002763}
2764
2765/*
2766 * Add files[count] to the arglist of the current window after arg "after".
2767 * The file names in files[count] must have been allocated and are taken over.
2768 * Files[] itself is not taken over.
2769 * Returns index of first added argument. Returns -1 when failed (out of mem).
2770 */
2771 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002772alist_add_list(
2773 int count,
2774 char_u **files,
2775 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776{
2777 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002778 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779
2780 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2781 {
2782 if (after < 0)
2783 after = 0;
2784 if (after > ARGCOUNT)
2785 after = ARGCOUNT;
2786 if (after < ARGCOUNT)
2787 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2788 (ARGCOUNT - after) * sizeof(aentry_T));
2789 for (i = 0; i < count; ++i)
2790 {
2791 ARGLIST[after + i].ae_fname = files[i];
2792 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2793 }
2794 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002795 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2796 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002797 return after;
2798 }
2799
2800 for (i = 0; i < count; ++i)
2801 vim_free(files[i]);
2802 return -1;
2803}
2804
2805#endif /* FEAT_LISTCMDS */
2806
2807#ifdef FEAT_EVAL
2808/*
2809 * ":compiler[!] {name}"
2810 */
2811 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002812ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813{
2814 char_u *buf;
2815 char_u *old_cur_comp = NULL;
2816 char_u *p;
2817
2818 if (*eap->arg == NUL)
2819 {
2820 /* List all compiler scripts. */
2821 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2822 /* ) keep the indenter happy... */
2823 }
2824 else
2825 {
2826 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2827 if (buf != NULL)
2828 {
2829 if (eap->forceit)
2830 {
2831 /* ":compiler! {name}" sets global options */
2832 do_cmdline_cmd((char_u *)
2833 "command -nargs=* CompilerSet set <args>");
2834 }
2835 else
2836 {
2837 /* ":compiler! {name}" sets local options.
2838 * To remain backwards compatible "current_compiler" is always
2839 * used. A user's compiler plugin may set it, the distributed
2840 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002841 * "b:current_compiler" and restore "current_compiler".
2842 * Explicitly prepend "g:" to make it work in a function. */
2843 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844 if (old_cur_comp != NULL)
2845 old_cur_comp = vim_strsave(old_cur_comp);
2846 do_cmdline_cmd((char_u *)
2847 "command -nargs=* CompilerSet setlocal <args>");
2848 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002849 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002850 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851
2852 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002853 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002854 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2855 vim_free(buf);
2856
2857 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2858
2859 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002860 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861 if (p != NULL)
2862 set_internal_string_var((char_u *)"b:current_compiler", p);
2863
2864 /* Restore "current_compiler" for ":compiler {name}". */
2865 if (!eap->forceit)
2866 {
2867 if (old_cur_comp != NULL)
2868 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002869 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870 old_cur_comp);
2871 vim_free(old_cur_comp);
2872 }
2873 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002874 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002875 }
2876 }
2877 }
2878}
2879#endif
2880
2881/*
2882 * ":runtime {name}"
2883 */
2884 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002885ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002886{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002887 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888}
2889
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002890static void source_callback(char_u *fname, void *cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891
2892 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002893source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002895 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896}
2897
2898/*
2899 * Source the file "name" from all directories in 'runtimepath'.
2900 * "name" can contain wildcards.
2901 * When "all" is TRUE, source all files, otherwise only the first one.
2902 * return FAIL when no file could be sourced, OK otherwise.
2903 */
2904 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002905source_runtime(char_u *name, int all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002907 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908}
2909
2910/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002911 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2912 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2914 * used.
2915 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002916 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002917 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2918 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002919 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920 */
2921 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002922do_in_runtimepath(
2923 char_u *name,
2924 int all,
2925 void (*callback)(char_u *fname, void *ck),
2926 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002927{
2928 char_u *rtp;
2929 char_u *np;
2930 char_u *buf;
2931 char_u *rtp_copy;
2932 char_u *tail;
2933 int num_files;
2934 char_u **files;
2935 int i;
2936 int did_one = FALSE;
2937#ifdef AMIGA
2938 struct Process *proc = (struct Process *)FindTask(0L);
2939 APTR save_winptr = proc->pr_WindowPtr;
2940
2941 /* Avoid a requester here for a volume that doesn't exist. */
2942 proc->pr_WindowPtr = (APTR)-1L;
2943#endif
2944
2945 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2946 * value. */
2947 rtp_copy = vim_strsave(p_rtp);
2948 buf = alloc(MAXPATHL);
2949 if (buf != NULL && rtp_copy != NULL)
2950 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002951 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002952 {
2953 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002954 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002956 verbose_leave();
2957 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002958
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959 /* Loop over all entries in 'runtimepath'. */
2960 rtp = rtp_copy;
2961 while (*rtp != NUL && (all || !did_one))
2962 {
2963 /* Copy the path from 'runtimepath' to buf[]. */
2964 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002965 if (name == NULL)
2966 {
2967 (*callback)(buf, (void *) &cookie);
2968 if (!did_one)
2969 did_one = (cookie == NULL);
2970 }
2971 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002972 {
2973 add_pathsep(buf);
2974 tail = buf + STRLEN(buf);
2975
2976 /* Loop over all patterns in "name" */
2977 np = name;
2978 while (*np != NUL && (all || !did_one))
2979 {
2980 /* Append the pattern from "name" to buf[]. */
2981 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2982 "\t ");
2983
2984 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002985 {
2986 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002987 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002988 verbose_leave();
2989 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990
2991 /* Expand wildcards, invoke the callback for each match. */
2992 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2993 EW_FILE) == OK)
2994 {
2995 for (i = 0; i < num_files; ++i)
2996 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002997 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002998 did_one = TRUE;
2999 if (!all)
3000 break;
3001 }
3002 FreeWild(num_files, files);
3003 }
3004 }
3005 }
3006 }
3007 }
3008 vim_free(buf);
3009 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003010 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003011 {
3012 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003013 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003014 verbose_leave();
3015 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016
3017#ifdef AMIGA
3018 proc->pr_WindowPtr = save_winptr;
3019#endif
3020
3021 return did_one ? OK : FAIL;
3022}
3023
3024#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3025/*
3026 * ":options"
3027 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003028 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003029ex_options(
3030 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031{
3032 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3033}
3034#endif
3035
3036/*
3037 * ":source {fname}"
3038 */
3039 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003040ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041{
3042#ifdef FEAT_BROWSE
3043 if (cmdmod.browse)
3044 {
3045 char_u *fname = NULL;
3046
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003047 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3049 if (fname != NULL)
3050 {
3051 cmd_source(fname, eap);
3052 vim_free(fname);
3053 }
3054 }
3055 else
3056#endif
3057 cmd_source(eap->arg, eap);
3058}
3059
3060 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003061cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062{
3063 if (*fname == NUL)
3064 EMSG(_(e_argreq));
3065
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003067 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003068 * Need to execute the commands directly. This is required at least
3069 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070 * - ":g" command busy
3071 * - after ":argdo", ":windo" or ":bufdo"
3072 * - another command follows
3073 * - inside a loop
3074 */
3075 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3076#ifdef FEAT_EVAL
3077 || eap->cstack->cs_idx >= 0
3078#endif
3079 );
3080
3081 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003082 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083 EMSG2(_(e_notopen), fname);
3084}
3085
3086/*
3087 * ":source" and associated commands.
3088 */
3089/*
3090 * Structure used to store info for each sourced file.
3091 * It is shared between do_source() and getsourceline().
3092 * This is required, because it needs to be handed to do_cmdline() and
3093 * sourcing can be done recursively.
3094 */
3095struct source_cookie
3096{
3097 FILE *fp; /* opened file for sourcing */
3098 char_u *nextline; /* if not NULL: line that was read ahead */
3099 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003100#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3102 int error; /* TRUE if LF found after CR-LF */
3103#endif
3104#ifdef FEAT_EVAL
3105 linenr_T breakpoint; /* next line with breakpoint or zero */
3106 char_u *fname; /* name of sourced file */
3107 int dbg_tick; /* debug_tick when breakpoint was set */
3108 int level; /* top nesting level of sourced file */
3109#endif
3110#ifdef FEAT_MBYTE
3111 vimconv_T conv; /* type of conversion */
3112#endif
3113};
3114
3115#ifdef FEAT_EVAL
3116/*
3117 * Return the address holding the next breakpoint line for a source cookie.
3118 */
3119 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003120source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003121{
3122 return &((struct source_cookie *)cookie)->breakpoint;
3123}
3124
3125/*
3126 * Return the address holding the debug tick for a source cookie.
3127 */
3128 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003129source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130{
3131 return &((struct source_cookie *)cookie)->dbg_tick;
3132}
3133
3134/*
3135 * Return the nesting level for a source cookie.
3136 */
3137 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003138source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139{
3140 return ((struct source_cookie *)cookie)->level;
3141}
3142#endif
3143
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003144static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003146#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3147# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003148static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149
3150/*
3151 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003152 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153 */
3154 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003155fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003156{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003157# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003158 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3159# else
3160 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003161# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162
3163 if (fd_tmp == -1)
3164 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003165
3166# ifdef HAVE_FD_CLOEXEC
3167 {
3168 int fdflags = fcntl(fd_tmp, F_GETFD);
3169 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003170 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003171 }
3172# endif
3173
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174 return fdopen(fd_tmp, READBIN);
3175}
3176#endif
3177
3178
3179/*
3180 * do_source: Read the file "fname" and execute its lines as EX commands.
3181 *
3182 * This function may be called recursively!
3183 *
3184 * return FAIL if file could not be opened, OK otherwise
3185 */
3186 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003187do_source(
3188 char_u *fname,
3189 int check_other, /* check for .vimrc and _vimrc */
3190 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003191{
3192 struct source_cookie cookie;
3193 char_u *save_sourcing_name;
3194 linenr_T save_sourcing_lnum;
3195 char_u *p;
3196 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003197 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198 int retval = FAIL;
3199#ifdef FEAT_EVAL
3200 scid_T save_current_SID;
3201 static scid_T last_current_SID = 0;
3202 void *save_funccalp;
3203 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003204 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003205# ifdef UNIX
3206 struct stat st;
3207 int stat_ok;
3208# endif
3209#endif
3210#ifdef STARTUPTIME
3211 struct timeval tv_rel;
3212 struct timeval tv_start;
3213#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003214#ifdef FEAT_PROFILE
3215 proftime_T wait_start;
3216#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003217
Bram Moolenaar071d4272004-06-13 20:20:40 +00003218 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003219 if (p == NULL)
3220 return retval;
3221 fname_exp = fix_fname(p);
3222 vim_free(p);
3223 if (fname_exp == NULL)
3224 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 if (mch_isdir(fname_exp))
3226 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003227 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 goto theend;
3229 }
3230
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003231#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003232 /* Apply SourceCmd autocommands, they should get the file and source it. */
3233 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3234 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3235 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003236 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003237# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003238 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003239# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003240 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003241# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003242 goto theend;
3243 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003244
3245 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003246 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3247#endif
3248
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003249#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003250 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3251#else
3252 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3253#endif
3254 if (cookie.fp == NULL && check_other)
3255 {
3256 /*
3257 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3258 * and ".exrc" by "_exrc" or vice versa.
3259 */
3260 p = gettail(fname_exp);
3261 if ((*p == '.' || *p == '_')
3262 && (STRICMP(p + 1, "vimrc") == 0
3263 || STRICMP(p + 1, "gvimrc") == 0
3264 || STRICMP(p + 1, "exrc") == 0))
3265 {
3266 if (*p == '_')
3267 *p = '.';
3268 else
3269 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003270#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3272#else
3273 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3274#endif
3275 }
3276 }
3277
3278 if (cookie.fp == NULL)
3279 {
3280 if (p_verbose > 0)
3281 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003282 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003283 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003284 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285 else
3286 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003287 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003288 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 }
3290 goto theend;
3291 }
3292
3293 /*
3294 * The file exists.
3295 * - In verbose mode, give a message.
3296 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3297 */
3298 if (p_verbose > 1)
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 *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303 else
3304 smsg((char_u *)_("line %ld: sourcing \"%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 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003308 if (is_vimrc == DOSO_VIMRC)
3309 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3310 else if (is_vimrc == DOSO_GVIMRC)
3311 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312
3313#ifdef USE_CRNL
3314 /* If no automatic file format: Set default to CR-NL. */
3315 if (*p_ffs == NUL)
3316 cookie.fileformat = EOL_DOS;
3317 else
3318 cookie.fileformat = EOL_UNKNOWN;
3319 cookie.error = FALSE;
3320#endif
3321
3322#ifdef USE_CR
3323 /* If no automatic file format: Set default to CR. */
3324 if (*p_ffs == NUL)
3325 cookie.fileformat = EOL_MAC;
3326 else
3327 cookie.fileformat = EOL_UNKNOWN;
3328 cookie.error = FALSE;
3329#endif
3330
3331 cookie.nextline = NULL;
3332 cookie.finished = FALSE;
3333
3334#ifdef FEAT_EVAL
3335 /*
3336 * Check if this script has a breakpoint.
3337 */
3338 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3339 cookie.fname = fname_exp;
3340 cookie.dbg_tick = debug_tick;
3341
3342 cookie.level = ex_nesting_level;
3343#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344
3345 /*
3346 * Keep the sourcing name/lnum, for recursive calls.
3347 */
3348 save_sourcing_name = sourcing_name;
3349 sourcing_name = fname_exp;
3350 save_sourcing_lnum = sourcing_lnum;
3351 sourcing_lnum = 0;
3352
Bram Moolenaar73881402009-02-04 16:50:47 +00003353#ifdef FEAT_MBYTE
3354 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3355
3356 /* Read the first line so we can check for a UTF-8 BOM. */
3357 firstline = getsourceline(0, (void *)&cookie, 0);
3358 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3359 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3360 {
3361 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3362 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3363 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003364 if (p == NULL)
3365 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003366 if (p != NULL)
3367 {
3368 vim_free(firstline);
3369 firstline = p;
3370 }
3371 }
3372#endif
3373
Bram Moolenaar071d4272004-06-13 20:20:40 +00003374#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003375 if (time_fd != NULL)
3376 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377#endif
3378
3379#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003380# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003381 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003382 prof_child_enter(&wait_start); /* entering a child now */
3383# endif
3384
3385 /* Don't use local function variables, if called from a function.
3386 * Also starts profiling timer for nested script. */
3387 save_funccalp = save_funccal();
3388
Bram Moolenaar071d4272004-06-13 20:20:40 +00003389 /*
3390 * Check if this script was sourced before to finds its SID.
3391 * If it's new, generate a new SID.
3392 */
3393 save_current_SID = current_SID;
3394# ifdef UNIX
3395 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3396# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003397 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3398 {
3399 si = &SCRIPT_ITEM(current_SID);
3400 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003401 && (
3402# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003403 /* Compare dev/ino when possible, it catches symbolic
3404 * links. Also compare file names, the inode may change
3405 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003406 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003407 && (si->sn_dev == st.st_dev
3408 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003409# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003410 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003411 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003412 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003413 if (current_SID == 0)
3414 {
3415 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003416 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3417 == FAIL)
3418 goto almosttheend;
3419 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003420 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003421 ++script_items.ga_len;
3422 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3423# ifdef FEAT_PROFILE
3424 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003426 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003427 si = &SCRIPT_ITEM(current_SID);
3428 si->sn_name = fname_exp;
3429 fname_exp = NULL;
3430# ifdef UNIX
3431 if (stat_ok)
3432 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003433 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003434 si->sn_dev = st.st_dev;
3435 si->sn_ino = st.st_ino;
3436 }
3437 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003438 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003439# endif
3440
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441 /* Allocate the local script variables to use for this script. */
3442 new_script_vars(current_SID);
3443 }
3444
Bram Moolenaar05159a02005-02-26 23:04:13 +00003445# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003446 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003447 {
3448 int forceit;
3449
3450 /* Check if we do profiling for this script. */
3451 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3452 {
3453 script_do_profile(si);
3454 si->sn_pr_force = forceit;
3455 }
3456 if (si->sn_prof_on)
3457 {
3458 ++si->sn_pr_count;
3459 profile_start(&si->sn_pr_start);
3460 profile_zero(&si->sn_pr_children);
3461 }
3462 }
3463# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464#endif
3465
3466 /*
3467 * Call do_cmdline, which will call getsourceline() to get the lines.
3468 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003469 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003472
3473#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003474 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003475 {
3476 /* Get "si" again, "script_items" may have been reallocated. */
3477 si = &SCRIPT_ITEM(current_SID);
3478 if (si->sn_prof_on)
3479 {
3480 profile_end(&si->sn_pr_start);
3481 profile_sub_wait(&wait_start, &si->sn_pr_start);
3482 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003483 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3484 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003485 }
3486 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003487#endif
3488
3489 if (got_int)
3490 EMSG(_(e_interr));
3491 sourcing_name = save_sourcing_name;
3492 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493 if (p_verbose > 1)
3494 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003495 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003496 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003497 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003498 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003499 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003500 }
3501#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003502 if (time_fd != NULL)
3503 {
3504 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3505 time_msg((char *)IObuff, &tv_start);
3506 time_pop(&tv_rel);
3507 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003508#endif
3509
3510#ifdef FEAT_EVAL
3511 /*
3512 * After a "finish" in debug mode, need to break at first command of next
3513 * sourced file.
3514 */
3515 if (save_debug_break_level > ex_nesting_level
3516 && debug_break_level == ex_nesting_level)
3517 ++debug_break_level;
3518#endif
3519
Bram Moolenaar05159a02005-02-26 23:04:13 +00003520#ifdef FEAT_EVAL
3521almosttheend:
3522 current_SID = save_current_SID;
3523 restore_funccal(save_funccalp);
3524# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003525 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003526 prof_child_exit(&wait_start); /* leaving a child now */
3527# endif
3528#endif
3529 fclose(cookie.fp);
3530 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003531 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003532#ifdef FEAT_MBYTE
3533 convert_setup(&cookie.conv, NULL, NULL);
3534#endif
3535
Bram Moolenaar071d4272004-06-13 20:20:40 +00003536theend:
3537 vim_free(fname_exp);
3538 return retval;
3539}
3540
3541#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003542
Bram Moolenaar071d4272004-06-13 20:20:40 +00003543/*
3544 * ":scriptnames"
3545 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003547ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548{
3549 int i;
3550
Bram Moolenaar05159a02005-02-26 23:04:13 +00003551 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3552 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003553 {
3554 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3555 NameBuff, MAXPATHL, TRUE);
3556 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003557 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003558}
3559
3560# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3561/*
3562 * Fix slashes in the list of script names for 'shellslash'.
3563 */
3564 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003565scriptnames_slash_adjust(void)
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; ++i)
3570 if (SCRIPT_ITEM(i).sn_name != NULL)
3571 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003572}
3573# endif
3574
3575/*
3576 * Get a pointer to a script name. Used for ":verbose set".
3577 */
3578 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003579get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003580{
3581 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003582 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003583 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003584 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003585 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003586 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003587 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003588 return (char_u *)_("environment variable");
3589 if (id == SID_ERROR)
3590 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003591 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003593
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003594# if defined(EXITFREE) || defined(PROTO)
3595 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003596free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003597{
3598 int i;
3599
3600 for (i = script_items.ga_len; i > 0; --i)
3601 vim_free(SCRIPT_ITEM(i).sn_name);
3602 ga_clear(&script_items);
3603}
3604# endif
3605
Bram Moolenaar071d4272004-06-13 20:20:40 +00003606#endif
3607
3608#if defined(USE_CR) || defined(PROTO)
3609
3610# if defined(__MSL__) && (__MSL__ >= 22)
3611/*
3612 * Newer version of the Metrowerks library handle DOS and UNIX files
3613 * without help.
3614 * Test with earlier versions, MSL 2.2 is the library supplied with
3615 * Codewarrior Pro 2.
3616 */
3617 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003618fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003619{
3620 return fgets(s, n, stream);
3621}
3622# else
3623/*
3624 * Version of fgets() which also works for lines ending in a <CR> only
3625 * (Macintosh format).
3626 * For older versions of the Metrowerks library.
3627 * At least CodeWarrior 9 needed this code.
3628 */
3629 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01003630fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003631{
3632 int c = 0;
3633 int char_read = 0;
3634
3635 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3636 {
3637 c = fgetc(stream);
3638 s[char_read++] = c;
3639 /* If the file is in DOS format, we need to skip a NL after a CR. I
3640 * thought it was the other way around, but this appears to work... */
3641 if (c == '\n')
3642 {
3643 c = fgetc(stream);
3644 if (c != '\r')
3645 ungetc(c, stream);
3646 }
3647 }
3648
3649 s[char_read] = 0;
3650 if (char_read == 0)
3651 return NULL;
3652
3653 if (feof(stream) && char_read == 1)
3654 return NULL;
3655
3656 return s;
3657}
3658# endif
3659#endif
3660
3661/*
3662 * Get one full line from a sourced file.
3663 * Called by do_cmdline() when it's called from do_source().
3664 *
3665 * Return a pointer to the line in allocated memory.
3666 * Return NULL for end-of-file or some error.
3667 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003669getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670{
3671 struct source_cookie *sp = (struct source_cookie *)cookie;
3672 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003673 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003674
3675#ifdef FEAT_EVAL
3676 /* If breakpoints have been added/deleted need to check for it. */
3677 if (sp->dbg_tick < debug_tick)
3678 {
3679 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3680 sp->dbg_tick = debug_tick;
3681 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003682# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003683 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003684 script_line_end();
3685# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003686#endif
3687 /*
3688 * Get current line. If there is a read-ahead line, use it, otherwise get
3689 * one now.
3690 */
3691 if (sp->finished)
3692 line = NULL;
3693 else if (sp->nextline == NULL)
3694 line = get_one_sourceline(sp);
3695 else
3696 {
3697 line = sp->nextline;
3698 sp->nextline = NULL;
3699 ++sourcing_lnum;
3700 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003701#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003702 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003703 script_line_start();
3704#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705
3706 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3707 * contain the 'C' flag. */
3708 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3709 {
3710 /* compensate for the one line read-ahead */
3711 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003712
3713 /* Get the next line and concatenate it when it starts with a
3714 * backslash. We always need to read the next line, keep it in
3715 * sp->nextline. */
3716 sp->nextline = get_one_sourceline(sp);
3717 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003718 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003719 garray_T ga;
3720
Bram Moolenaarb549a732012-02-22 18:29:33 +01003721 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003722 ga_concat(&ga, line);
3723 ga_concat(&ga, p + 1);
3724 for (;;)
3725 {
3726 vim_free(sp->nextline);
3727 sp->nextline = get_one_sourceline(sp);
3728 if (sp->nextline == NULL)
3729 break;
3730 p = skipwhite(sp->nextline);
3731 if (*p != '\\')
3732 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003733 /* Adjust the growsize to the current length to speed up
3734 * concatenating many lines. */
3735 if (ga.ga_len > 400)
3736 {
3737 if (ga.ga_len > 8000)
3738 ga.ga_growsize = 8000;
3739 else
3740 ga.ga_growsize = ga.ga_len;
3741 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003742 ga_concat(&ga, p + 1);
3743 }
3744 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003746 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003747 }
3748 }
3749
3750#ifdef FEAT_MBYTE
3751 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3752 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003753 char_u *s;
3754
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755 /* Convert the encoding of the script line. */
3756 s = string_convert(&sp->conv, line, NULL);
3757 if (s != NULL)
3758 {
3759 vim_free(line);
3760 line = s;
3761 }
3762 }
3763#endif
3764
3765#ifdef FEAT_EVAL
3766 /* Did we encounter a breakpoint? */
3767 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3768 {
3769 dbg_breakpoint(sp->fname, sourcing_lnum);
3770 /* Find next breakpoint. */
3771 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3772 sp->dbg_tick = debug_tick;
3773 }
3774#endif
3775
3776 return line;
3777}
3778
3779 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003780get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003781{
3782 garray_T ga;
3783 int len;
3784 int c;
3785 char_u *buf;
3786#ifdef USE_CRNL
3787 int has_cr; /* CR-LF found */
3788#endif
3789#ifdef USE_CR
3790 char_u *scan;
3791#endif
3792 int have_read = FALSE;
3793
3794 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003795 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003796
3797 /*
3798 * Loop until there is a finished line (or end-of-file).
3799 */
3800 sourcing_lnum++;
3801 for (;;)
3802 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003803 /* make room to read at least 120 (more) characters */
3804 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003805 break;
3806 buf = (char_u *)ga.ga_data;
3807
3808#ifdef USE_CR
3809 if (sp->fileformat == EOL_MAC)
3810 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003811 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3812 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813 break;
3814 }
3815 else
3816#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003817 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3818 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003820 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003821#ifdef USE_CRNL
3822 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3823 * CTRL-Z by its own, or after a NL. */
3824 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3825 && sp->fileformat == EOL_DOS
3826 && buf[len - 1] == Ctrl_Z)
3827 {
3828 buf[len - 1] = NUL;
3829 break;
3830 }
3831#endif
3832
3833#ifdef USE_CR
3834 /* If the read doesn't stop on a new line, and there's
3835 * some CR then we assume a Mac format */
3836 if (sp->fileformat == EOL_UNKNOWN)
3837 {
3838 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3839 sp->fileformat = EOL_MAC;
3840 else
3841 sp->fileformat = EOL_UNIX;
3842 }
3843
3844 if (sp->fileformat == EOL_MAC)
3845 {
3846 scan = vim_strchr(buf, '\r');
3847
3848 if (scan != NULL)
3849 {
3850 *scan = '\n';
3851 if (*(scan + 1) != 0)
3852 {
3853 *(scan + 1) = 0;
3854 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3855 }
3856 }
3857 len = STRLEN(buf);
3858 }
3859#endif
3860
3861 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003862 ga.ga_len = len;
3863
3864 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003865 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003866 continue;
3867
3868 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3869 {
3870#ifdef USE_CRNL
3871 has_cr = (len >= 2 && buf[len - 2] == '\r');
3872 if (sp->fileformat == EOL_UNKNOWN)
3873 {
3874 if (has_cr)
3875 sp->fileformat = EOL_DOS;
3876 else
3877 sp->fileformat = EOL_UNIX;
3878 }
3879
3880 if (sp->fileformat == EOL_DOS)
3881 {
3882 if (has_cr) /* replace trailing CR */
3883 {
3884 buf[len - 2] = '\n';
3885 --len;
3886 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003887 }
3888 else /* lines like ":map xx yy^M" will have failed */
3889 {
3890 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003891 {
3892 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003894 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895 sp->error = TRUE;
3896 sp->fileformat = EOL_UNIX;
3897 }
3898 }
3899#endif
3900 /* The '\n' is escaped if there is an odd number of ^V's just
3901 * before it, first set "c" just before the 'V's and then check
3902 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3903 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3904 ;
3905 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3906 {
3907 sourcing_lnum++;
3908 continue;
3909 }
3910
3911 buf[len - 1] = NUL; /* remove the NL */
3912 }
3913
3914 /*
3915 * Check for ^C here now and then, so recursive :so can be broken.
3916 */
3917 line_breakcheck();
3918 break;
3919 }
3920
3921 if (have_read)
3922 return (char_u *)ga.ga_data;
3923
3924 vim_free(ga.ga_data);
3925 return NULL;
3926}
3927
Bram Moolenaar05159a02005-02-26 23:04:13 +00003928#if defined(FEAT_PROFILE) || defined(PROTO)
3929/*
3930 * Called when starting to read a script line.
3931 * "sourcing_lnum" must be correct!
3932 * When skipping lines it may not actually be executed, but we won't find out
3933 * until later and we need to store the time now.
3934 */
3935 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003936script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003937{
3938 scriptitem_T *si;
3939 sn_prl_T *pp;
3940
3941 if (current_SID <= 0 || current_SID > script_items.ga_len)
3942 return;
3943 si = &SCRIPT_ITEM(current_SID);
3944 if (si->sn_prof_on && sourcing_lnum >= 1)
3945 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003946 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003947 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02003948 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00003949 si->sn_prl_idx = sourcing_lnum - 1;
3950 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3951 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3952 {
3953 /* Zero counters for a line that was not used before. */
3954 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3955 pp->snp_count = 0;
3956 profile_zero(&pp->sn_prl_total);
3957 profile_zero(&pp->sn_prl_self);
3958 ++si->sn_prl_ga.ga_len;
3959 }
3960 si->sn_prl_execed = FALSE;
3961 profile_start(&si->sn_prl_start);
3962 profile_zero(&si->sn_prl_children);
3963 profile_get_wait(&si->sn_prl_wait);
3964 }
3965}
3966
3967/*
3968 * Called when actually executing a function line.
3969 */
3970 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003971script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003972{
3973 scriptitem_T *si;
3974
3975 if (current_SID <= 0 || current_SID > script_items.ga_len)
3976 return;
3977 si = &SCRIPT_ITEM(current_SID);
3978 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3979 si->sn_prl_execed = TRUE;
3980}
3981
3982/*
3983 * Called when done with a function line.
3984 */
3985 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003986script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003987{
3988 scriptitem_T *si;
3989 sn_prl_T *pp;
3990
3991 if (current_SID <= 0 || current_SID > script_items.ga_len)
3992 return;
3993 si = &SCRIPT_ITEM(current_SID);
3994 if (si->sn_prof_on && si->sn_prl_idx >= 0
3995 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3996 {
3997 if (si->sn_prl_execed)
3998 {
3999 pp = &PRL_ITEM(si, si->sn_prl_idx);
4000 ++pp->snp_count;
4001 profile_end(&si->sn_prl_start);
4002 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004003 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004004 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4005 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004006 }
4007 si->sn_prl_idx = -1;
4008 }
4009}
4010#endif
4011
Bram Moolenaar071d4272004-06-13 20:20:40 +00004012/*
4013 * ":scriptencoding": Set encoding conversion for a sourced script.
4014 * Without the multi-byte feature it's simply ignored.
4015 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004017ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004018{
4019#ifdef FEAT_MBYTE
4020 struct source_cookie *sp;
4021 char_u *name;
4022
4023 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4024 {
4025 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4026 return;
4027 }
4028
4029 if (*eap->arg != NUL)
4030 {
4031 name = enc_canonize(eap->arg);
4032 if (name == NULL) /* out of memory */
4033 return;
4034 }
4035 else
4036 name = eap->arg;
4037
4038 /* Setup for conversion from the specified encoding to 'encoding'. */
4039 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4040 convert_setup(&sp->conv, name, p_enc);
4041
4042 if (name != eap->arg)
4043 vim_free(name);
4044#endif
4045}
4046
4047#if defined(FEAT_EVAL) || defined(PROTO)
4048/*
4049 * ":finish": Mark a sourced file as finished.
4050 */
4051 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004052ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004053{
4054 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4055 do_finish(eap, FALSE);
4056 else
4057 EMSG(_("E168: :finish used outside of a sourced file"));
4058}
4059
4060/*
4061 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4062 * Also called for a pending finish at the ":endtry" or after returning from
4063 * an extra do_cmdline(). "reanimate" is used in the latter case.
4064 */
4065 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004066do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004067{
4068 int idx;
4069
4070 if (reanimate)
4071 ((struct source_cookie *)getline_cookie(eap->getline,
4072 eap->cookie))->finished = FALSE;
4073
4074 /*
4075 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4076 * not in its finally clause (which then is to be executed next) is found.
4077 * In this case, make the ":finish" pending for execution at the ":endtry".
4078 * Otherwise, finish normally.
4079 */
4080 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4081 if (idx >= 0)
4082 {
4083 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4084 report_make_pending(CSTP_FINISH, NULL);
4085 }
4086 else
4087 ((struct source_cookie *)getline_cookie(eap->getline,
4088 eap->cookie))->finished = TRUE;
4089}
4090
4091
4092/*
4093 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4094 * message for missing ":endif".
4095 * Return FALSE when not sourcing a file.
4096 */
4097 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004098source_finished(
4099 char_u *(*fgetline)(int, void *, int),
4100 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004102 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004103 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004104 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004105}
4106#endif
4107
4108#if defined(FEAT_LISTCMDS) || defined(PROTO)
4109/*
4110 * ":checktime [buffer]"
4111 */
4112 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004113ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114{
4115 buf_T *buf;
4116 int save_no_check_timestamps = no_check_timestamps;
4117
4118 no_check_timestamps = 0;
4119 if (eap->addr_count == 0) /* default is all buffers */
4120 check_timestamps(FALSE);
4121 else
4122 {
4123 buf = buflist_findnr((int)eap->line2);
4124 if (buf != NULL) /* cannot happen? */
4125 (void)buf_check_timestamp(buf, FALSE);
4126 }
4127 no_check_timestamps = save_no_check_timestamps;
4128}
4129#endif
4130
Bram Moolenaar071d4272004-06-13 20:20:40 +00004131#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4132 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004133# define HAVE_GET_LOCALE_VAL
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004134static char *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135
4136 static char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004137get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138{
4139 char *loc;
4140
4141 /* Obtain the locale value from the libraries. For DJGPP this is
4142 * redefined and it doesn't use the arguments. */
4143 loc = setlocale(what, NULL);
4144
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004145# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146 if (loc != NULL)
4147 {
4148 char_u *p;
4149
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004150 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4151 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004152 p = vim_strchr(loc, '=');
4153 if (p != NULL)
4154 {
4155 loc = ++p;
4156 while (*p != NUL) /* remove trailing newline */
4157 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004158 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 {
4160 *p = NUL;
4161 break;
4162 }
4163 ++p;
4164 }
4165 }
4166 }
4167# endif
4168
4169 return loc;
4170}
4171#endif
4172
4173
4174#ifdef WIN32
4175/*
4176 * On MS-Windows locale names are strings like "German_Germany.1252", but
4177 * gettext expects "de". Try to translate one into another here for a few
4178 * supported languages.
4179 */
4180 static char_u *
4181gettext_lang(char_u *name)
4182{
4183 int i;
4184 static char *(mtable[]) = {
4185 "afrikaans", "af",
4186 "czech", "cs",
4187 "dutch", "nl",
4188 "german", "de",
4189 "english_united kingdom", "en_GB",
4190 "spanish", "es",
4191 "french", "fr",
4192 "italian", "it",
4193 "japanese", "ja",
4194 "korean", "ko",
4195 "norwegian", "no",
4196 "polish", "pl",
4197 "russian", "ru",
4198 "slovak", "sk",
4199 "swedish", "sv",
4200 "ukrainian", "uk",
4201 "chinese_china", "zh_CN",
4202 "chinese_taiwan", "zh_TW",
4203 NULL};
4204
4205 for (i = 0; mtable[i] != NULL; i += 2)
4206 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4207 return mtable[i + 1];
4208 return name;
4209}
4210#endif
4211
4212#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4213/*
4214 * Obtain the current messages language. Used to set the default for
4215 * 'helplang'. May return NULL or an empty string.
4216 */
4217 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004218get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219{
4220 char_u *p;
4221
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004222# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223# if defined(LC_MESSAGES)
4224 p = (char_u *)get_locale_val(LC_MESSAGES);
4225# else
4226 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004227 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4228 * and LC_MONETARY may be set differently for a Japanese working in the
4229 * US. */
4230 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004231# endif
4232# else
4233 p = mch_getenv((char_u *)"LC_ALL");
4234 if (p == NULL || *p == NUL)
4235 {
4236 p = mch_getenv((char_u *)"LC_MESSAGES");
4237 if (p == NULL || *p == NUL)
4238 p = mch_getenv((char_u *)"LANG");
4239 }
4240# endif
4241# ifdef WIN32
4242 p = gettext_lang(p);
4243# endif
4244 return p;
4245}
4246#endif
4247
Bram Moolenaardef9e822004-12-31 20:58:58 +00004248/* Complicated #if; matches with where get_mess_env() is used below. */
4249#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4250 && defined(LC_MESSAGES))) \
4251 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4252 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4253 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004254static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255
4256/*
4257 * Get the language used for messages from the environment.
4258 */
4259 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004260get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261{
4262 char_u *p;
4263
4264 p = mch_getenv((char_u *)"LC_ALL");
4265 if (p == NULL || *p == NUL)
4266 {
4267 p = mch_getenv((char_u *)"LC_MESSAGES");
4268 if (p == NULL || *p == NUL)
4269 {
4270 p = mch_getenv((char_u *)"LANG");
4271 if (p != NULL && VIM_ISDIGIT(*p))
4272 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004273# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274 if (p == NULL || *p == NUL)
4275 p = (char_u *)get_locale_val(LC_CTYPE);
4276# endif
4277 }
4278 }
4279 return p;
4280}
4281#endif
4282
4283#if defined(FEAT_EVAL) || defined(PROTO)
4284
4285/*
4286 * Set the "v:lang" variable according to the current locale setting.
4287 * Also do "v:lc_time"and "v:ctype".
4288 */
4289 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004290set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004291{
4292 char_u *loc;
4293
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004294# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004295 loc = (char_u *)get_locale_val(LC_CTYPE);
4296# else
4297 /* setlocale() not supported: use the default value */
4298 loc = (char_u *)"C";
4299# endif
4300 set_vim_var_string(VV_CTYPE, loc, -1);
4301
4302 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4303 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004304# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004305 loc = (char_u *)get_locale_val(LC_MESSAGES);
4306# else
4307 loc = get_mess_env();
4308# endif
4309 set_vim_var_string(VV_LANG, loc, -1);
4310
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004311# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312 loc = (char_u *)get_locale_val(LC_TIME);
4313# endif
4314 set_vim_var_string(VV_LC_TIME, loc, -1);
4315}
4316#endif
4317
4318#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4319 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4320/*
4321 * ":language": Set the language (locale).
4322 */
4323 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004324ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004325{
4326 char *loc;
4327 char_u *p;
4328 char_u *name;
4329 int what = LC_ALL;
4330 char *whatstr = "";
4331#ifdef LC_MESSAGES
4332# define VIM_LC_MESSAGES LC_MESSAGES
4333#else
4334# define VIM_LC_MESSAGES 6789
4335#endif
4336
4337 name = eap->arg;
4338
4339 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4340 * Allow abbreviation, but require at least 3 characters to avoid
4341 * confusion with a two letter language name "me" or "ct". */
4342 p = skiptowhite(eap->arg);
4343 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4344 {
4345 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4346 {
4347 what = VIM_LC_MESSAGES;
4348 name = skipwhite(p);
4349 whatstr = "messages ";
4350 }
4351 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4352 {
4353 what = LC_CTYPE;
4354 name = skipwhite(p);
4355 whatstr = "ctype ";
4356 }
4357 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4358 {
4359 what = LC_TIME;
4360 name = skipwhite(p);
4361 whatstr = "time ";
4362 }
4363 }
4364
4365 if (*name == NUL)
4366 {
4367#ifndef LC_MESSAGES
4368 if (what == VIM_LC_MESSAGES)
4369 p = get_mess_env();
4370 else
4371#endif
4372 p = (char_u *)setlocale(what, NULL);
4373 if (p == NULL || *p == NUL)
4374 p = (char_u *)"Unknown";
4375 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4376 }
4377 else
4378 {
4379#ifndef LC_MESSAGES
4380 if (what == VIM_LC_MESSAGES)
4381 loc = "";
4382 else
4383#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004384 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004385 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004386#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4387 /* Make sure strtod() uses a decimal point, not a comma. */
4388 setlocale(LC_NUMERIC, "C");
4389#endif
4390 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004391 if (loc == NULL)
4392 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4393 else
4394 {
4395#ifdef HAVE_NL_MSG_CAT_CNTR
4396 /* Need to do this for GNU gettext, otherwise cached translations
4397 * will be used again. */
4398 extern int _nl_msg_cat_cntr;
4399
4400 ++_nl_msg_cat_cntr;
4401#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004402 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004403 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4404
4405 if (what != LC_TIME)
4406 {
4407 /* Tell gettext() what to translate to. It apparently doesn't
4408 * use the currently effective locale. Also do this when
4409 * FEAT_GETTEXT isn't defined, so that shell commands use this
4410 * value. */
4411 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004412 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004413 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004414
4415 /* Clear $LANGUAGE because GNU gettext uses it. */
4416 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004417# ifdef WIN32
4418 /* Apparently MS-Windows printf() may cause a crash when
4419 * we give it 8-bit text while it's expecting text in the
4420 * current locale. This call avoids that. */
4421 setlocale(LC_CTYPE, "C");
4422# endif
4423 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424 if (what != LC_CTYPE)
4425 {
4426 char_u *mname;
4427#ifdef WIN32
4428 mname = gettext_lang(name);
4429#else
4430 mname = name;
4431#endif
4432 vim_setenv((char_u *)"LC_MESSAGES", mname);
4433#ifdef FEAT_MULTI_LANG
4434 set_helplang_default(mname);
4435#endif
4436 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437 }
4438
4439# ifdef FEAT_EVAL
4440 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4441 set_lang_var();
4442# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004443# ifdef FEAT_TITLE
4444 maketitle();
4445# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446 }
4447 }
4448}
4449
4450# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004451
4452static char_u **locales = NULL; /* Array of all available locales */
4453static int did_init_locales = FALSE;
4454
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004455static void init_locales(void);
4456static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004457
4458/*
4459 * Lazy initialization of all available locales.
4460 */
4461 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004462init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004463{
4464 if (!did_init_locales)
4465 {
4466 did_init_locales = TRUE;
4467 locales = find_locales();
4468 }
4469}
4470
4471/* Return an array of strings for all available locales + NULL for the
4472 * last element. Return NULL in case of error. */
4473 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004474find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004475{
4476 garray_T locales_ga;
4477 char_u *loc;
4478
4479 /* Find all available locales by running command "locale -a". If this
4480 * doesn't work we won't have completion. */
4481 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004482 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004483 if (locale_a == NULL)
4484 return NULL;
4485 ga_init2(&locales_ga, sizeof(char_u *), 20);
4486
4487 /* Transform locale_a string where each locale is separated by "\n"
4488 * into an array of locale strings. */
4489 loc = (char_u *)strtok((char *)locale_a, "\n");
4490
4491 while (loc != NULL)
4492 {
4493 if (ga_grow(&locales_ga, 1) == FAIL)
4494 break;
4495 loc = vim_strsave(loc);
4496 if (loc == NULL)
4497 break;
4498
4499 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4500 loc = (char_u *)strtok(NULL, "\n");
4501 }
4502 vim_free(locale_a);
4503 if (ga_grow(&locales_ga, 1) == FAIL)
4504 {
4505 ga_clear(&locales_ga);
4506 return NULL;
4507 }
4508 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4509 return (char_u **)locales_ga.ga_data;
4510}
4511
4512# if defined(EXITFREE) || defined(PROTO)
4513 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004514free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004515{
4516 int i;
4517 if (locales != NULL)
4518 {
4519 for (i = 0; locales[i] != NULL; i++)
4520 vim_free(locales[i]);
4521 vim_free(locales);
4522 locales = NULL;
4523 }
4524}
4525# endif
4526
Bram Moolenaar071d4272004-06-13 20:20:40 +00004527/*
4528 * Function given to ExpandGeneric() to obtain the possible arguments of the
4529 * ":language" command.
4530 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004531 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004532get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533{
4534 if (idx == 0)
4535 return (char_u *)"messages";
4536 if (idx == 1)
4537 return (char_u *)"ctype";
4538 if (idx == 2)
4539 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004540
4541 init_locales();
4542 if (locales == NULL)
4543 return NULL;
4544 return locales[idx - 3];
4545}
4546
4547/*
4548 * Function given to ExpandGeneric() to obtain the available locales.
4549 */
4550 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004551get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004552{
4553 init_locales();
4554 if (locales == NULL)
4555 return NULL;
4556 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557}
4558# endif
4559
4560#endif