blob: c1adea4c77fbb7ee3c5a21b57edeb371033143d1 [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# ifdef FEAT_EX_EXTRA
94 int save_ex_normal_busy;
95# endif
96 int n;
97 char_u *cmdline = NULL;
98 char_u *p;
99 char *tail = NULL;
100 static int last_cmd = 0;
101#define CMD_CONT 1
102#define CMD_NEXT 2
103#define CMD_STEP 3
104#define CMD_FINISH 4
105#define CMD_QUIT 5
106#define CMD_INTERRUPT 6
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100107#define CMD_BACKTRACE 7
108#define CMD_FRAME 8
109#define CMD_UP 9
110#define CMD_DOWN 10
Bram Moolenaar071d4272004-06-13 20:20:40 +0000111
112#ifdef ALWAYS_USE_GUI
113 /* Can't do this when there is no terminal for input/output. */
114 if (!gui.in_use)
115 {
116 /* Break as soon as possible. */
117 debug_break_level = 9999;
118 return;
119 }
120#endif
121
122 /* Make sure we are in raw mode and start termcap mode. Might have side
123 * effects... */
124 settmode(TMODE_RAW);
125 starttermcap();
126
127 ++RedrawingDisabled; /* don't redisplay the window */
128 ++no_wait_return; /* don't wait for return */
129 did_emsg = FALSE; /* don't use error from debugged stuff */
130 cmd_silent = FALSE; /* display commands */
131 msg_silent = FALSE; /* display messages */
132 emsg_silent = FALSE; /* display error messages */
133 redir_off = TRUE; /* don't redirect debug commands */
134
135 State = NORMAL;
136#ifdef FEAT_SNIFF
137 want_sniff_request = 0; /* No K_SNIFF wanted */
138#endif
139
140 if (!debug_did_msg)
141 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
142 if (sourcing_name != NULL)
143 msg(sourcing_name);
144 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000145 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000147 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148
149 /*
150 * Repeat getting a command and executing it.
151 */
152 for (;;)
153 {
154 msg_scroll = TRUE;
155 need_wait_return = FALSE;
156#ifdef FEAT_SNIFF
157 ProcessSniffRequests();
158#endif
159 /* Save the current typeahead buffer and replace it with an empty one.
160 * This makes sure we get input from the user here and don't interfere
161 * with the commands being executed. Reset "ex_normal_busy" to avoid
162 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000163 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164# ifdef FEAT_EX_EXTRA
165 save_ex_normal_busy = ex_normal_busy;
166 ex_normal_busy = 0;
167# endif
168 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000169 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000171 typeahead_saved = TRUE;
172 save_ignore_script = ignore_script;
173 ignore_script = TRUE;
174 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000176 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000178 if (typeahead_saved)
179 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000181 ignore_script = save_ignore_script;
182 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183# ifdef FEAT_EX_EXTRA
184 ex_normal_busy = save_ex_normal_busy;
185# endif
186
187 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100188 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000189 if (cmdline != NULL)
190 {
191 /* If this is a debug command, set "last_cmd".
192 * If not, reset "last_cmd".
193 * For a blank line use previous command. */
194 p = skipwhite(cmdline);
195 if (*p != NUL)
196 {
197 switch (*p)
198 {
199 case 'c': last_cmd = CMD_CONT;
200 tail = "ont";
201 break;
202 case 'n': last_cmd = CMD_NEXT;
203 tail = "ext";
204 break;
205 case 's': last_cmd = CMD_STEP;
206 tail = "tep";
207 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100208 case 'f':
209 last_cmd = 0;
210 if (p[1] == 'r')
211 {
212 last_cmd = CMD_FRAME;
213 tail = "rame";
214 }
215 else
216 {
217 last_cmd = CMD_FINISH;
218 tail = "inish";
219 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 break;
221 case 'q': last_cmd = CMD_QUIT;
222 tail = "uit";
223 break;
224 case 'i': last_cmd = CMD_INTERRUPT;
225 tail = "nterrupt";
226 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100227 case 'b': last_cmd = CMD_BACKTRACE;
228 if (p[1] == 't')
229 tail = "t";
230 else
231 tail = "acktrace";
232 break;
233 case 'w': last_cmd = CMD_BACKTRACE;
234 tail = "here";
235 break;
236 case 'u': last_cmd = CMD_UP;
237 tail = "p";
238 break;
239 case 'd': last_cmd = CMD_DOWN;
240 tail = "own";
241 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000242 default: last_cmd = 0;
243 }
244 if (last_cmd != 0)
245 {
246 /* Check that the tail matches. */
247 ++p;
248 while (*p != NUL && *p == *tail)
249 {
250 ++p;
251 ++tail;
252 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100253 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000254 last_cmd = 0;
255 }
256 }
257
258 if (last_cmd != 0)
259 {
260 /* Execute debug command: decided where to break next and
261 * return. */
262 switch (last_cmd)
263 {
264 case CMD_CONT:
265 debug_break_level = -1;
266 break;
267 case CMD_NEXT:
268 debug_break_level = ex_nesting_level;
269 break;
270 case CMD_STEP:
271 debug_break_level = 9999;
272 break;
273 case CMD_FINISH:
274 debug_break_level = ex_nesting_level - 1;
275 break;
276 case CMD_QUIT:
277 got_int = TRUE;
278 debug_break_level = -1;
279 break;
280 case CMD_INTERRUPT:
281 got_int = TRUE;
282 debug_break_level = 9999;
283 /* Do not repeat ">interrupt" cmd, continue stepping. */
284 last_cmd = CMD_STEP;
285 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100286 case CMD_BACKTRACE:
287 do_showbacktrace(cmd);
288 continue;
289 case CMD_FRAME:
290 if (*p == NUL)
291 {
292 do_showbacktrace(cmd);
293 }
294 else
295 {
296 p = skipwhite(p);
297 do_setdebugtracelevel(p);
298 }
299 continue;
300 case CMD_UP:
301 debug_backtrace_level++;
302 do_checkbacktracelevel();
303 continue;
304 case CMD_DOWN:
305 debug_backtrace_level--;
306 do_checkbacktracelevel();
307 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100309 /* Going out reset backtrace_level */
310 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000311 break;
312 }
313
314 /* don't debug this command */
315 n = debug_break_level;
316 debug_break_level = -1;
317 (void)do_cmdline(cmdline, getexline, NULL,
318 DOCMD_VERBOSE|DOCMD_EXCRESET);
319 debug_break_level = n;
320
321 vim_free(cmdline);
322 }
323 lines_left = Rows - 1;
324 }
325 vim_free(cmdline);
326
327 --RedrawingDisabled;
328 --no_wait_return;
329 redraw_all_later(NOT_VALID);
330 need_wait_return = FALSE;
331 msg_scroll = save_msg_scroll;
332 lines_left = Rows - 1;
333 State = save_State;
334 did_emsg = save_did_emsg;
335 cmd_silent = save_cmd_silent;
336 msg_silent = save_msg_silent;
337 emsg_silent = save_emsg_silent;
338 redir_off = save_redir_off;
339
340 /* Only print the message again when typing a command before coming back
341 * here. */
342 debug_did_msg = TRUE;
343}
344
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100345 static int
346get_maxbacktrace_level(void)
347{
348 char *p, *q;
349 int maxbacktrace = 1;
350
351 maxbacktrace = 0;
352 if (sourcing_name != NULL)
353 {
354 p = (char *)sourcing_name;
355 while ((q = strstr(p, "..")) != NULL)
356 {
357 p = q + 2;
358 maxbacktrace++;
359 }
360 }
361 return maxbacktrace;
362}
363
364 static void
365do_setdebugtracelevel(char_u *arg)
366{
367 int level;
368
369 level = atoi((char *)arg);
370 if (*arg == '+' || level < 0)
371 debug_backtrace_level += level;
372 else
373 debug_backtrace_level = level;
374
375 do_checkbacktracelevel();
376}
377
378 static void
379do_checkbacktracelevel(void)
380{
381 if (debug_backtrace_level < 0)
382 {
383 debug_backtrace_level = 0;
384 MSG(_("frame is zero"));
385 }
386 else
387 {
388 int max = get_maxbacktrace_level();
389
390 if (debug_backtrace_level > max)
391 {
392 debug_backtrace_level = max;
393 smsg((char_u *)_("frame at highest level: %d"), max);
394 }
395 }
396}
397
398 static void
399do_showbacktrace(char_u *cmd)
400{
401 char *cur;
402 char *next;
403 int i = 0;
404 int max = get_maxbacktrace_level();
405
406 if (sourcing_name != NULL)
407 {
408 cur = (char *)sourcing_name;
409 while (!got_int)
410 {
411 next = strstr(cur, "..");
412 if (next != NULL)
413 *next = NUL;
414 if (i == max - debug_backtrace_level)
415 smsg((char_u *)"->%d %s", max - i, cur);
416 else
417 smsg((char_u *)" %d %s", max - i, cur);
418 ++i;
419 if (next == NULL)
420 break;
421 *next = '.';
422 cur = next + 2;
423 }
424 }
425 if (sourcing_lnum != 0)
426 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
427 else
428 smsg((char_u *)_("cmd: %s"), cmd);
429}
430
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431/*
432 * ":debug".
433 */
434 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100435ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000436{
437 int debug_break_level_save = debug_break_level;
438
439 debug_break_level = 9999;
440 do_cmdline_cmd(eap->arg);
441 debug_break_level = debug_break_level_save;
442}
443
444static char_u *debug_breakpoint_name = NULL;
445static linenr_T debug_breakpoint_lnum;
446
447/*
448 * When debugging or a breakpoint is set on a skipped command, no debug prompt
449 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
450 * debug_skipped_name is then set to the source name in the breakpoint case. If
451 * a skipped command decides itself that a debug prompt should be displayed, it
452 * can do so by calling dbg_check_skipped().
453 */
454static int debug_skipped;
455static char_u *debug_skipped_name;
456
457/*
458 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
459 * at or below the break level. But only when the line is actually
460 * executed. Return TRUE and set breakpoint_name for skipped commands that
461 * decide to execute something themselves.
462 * Called from do_one_cmd() before executing a command.
463 */
464 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100465dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000466{
467 char_u *p;
468
469 debug_skipped = FALSE;
470 if (debug_breakpoint_name != NULL)
471 {
472 if (!eap->skip)
473 {
474 /* replace K_SNR with "<SNR>" */
475 if (debug_breakpoint_name[0] == K_SPECIAL
476 && debug_breakpoint_name[1] == KS_EXTRA
477 && debug_breakpoint_name[2] == (int)KE_SNR)
478 p = (char_u *)"<SNR>";
479 else
480 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000481 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
482 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000483 debug_breakpoint_name + (*p == NUL ? 0 : 3),
484 (long)debug_breakpoint_lnum);
485 debug_breakpoint_name = NULL;
486 do_debug(eap->cmd);
487 }
488 else
489 {
490 debug_skipped = TRUE;
491 debug_skipped_name = debug_breakpoint_name;
492 debug_breakpoint_name = NULL;
493 }
494 }
495 else if (ex_nesting_level <= debug_break_level)
496 {
497 if (!eap->skip)
498 do_debug(eap->cmd);
499 else
500 {
501 debug_skipped = TRUE;
502 debug_skipped_name = NULL;
503 }
504 }
505}
506
507/*
508 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
509 * set. Return TRUE when the debug mode is entered this time.
510 */
511 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100512dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513{
514 int prev_got_int;
515
516 if (debug_skipped)
517 {
518 /*
519 * Save the value of got_int and reset it. We don't want a previous
520 * interruption cause flushing the input buffer.
521 */
522 prev_got_int = got_int;
523 got_int = FALSE;
524 debug_breakpoint_name = debug_skipped_name;
525 /* eap->skip is TRUE */
526 eap->skip = FALSE;
527 (void)dbg_check_breakpoint(eap);
528 eap->skip = TRUE;
529 got_int |= prev_got_int;
530 return TRUE;
531 }
532 return FALSE;
533}
534
535/*
536 * The list of breakpoints: dbg_breakp.
537 * This is a grow-array of structs.
538 */
539struct debuggy
540{
541 int dbg_nr; /* breakpoint number */
542 int dbg_type; /* DBG_FUNC or DBG_FILE */
543 char_u *dbg_name; /* function or file name */
544 regprog_T *dbg_prog; /* regexp program */
545 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000546 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547};
548
549static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000550#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
551#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000552static int last_breakp = 0; /* nr of last defined breakpoint */
553
Bram Moolenaar05159a02005-02-26 23:04:13 +0000554#ifdef FEAT_PROFILE
555/* Profiling uses file and func names similar to breakpoints. */
556static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
557#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558#define DBG_FUNC 1
559#define DBG_FILE 2
560
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100561static int dbg_parsearg(char_u *arg, garray_T *gap);
562static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000563
564/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000565 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
566 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
567 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 * Returns FAIL for failure.
569 */
570 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100571dbg_parsearg(
572 char_u *arg,
573 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574{
575 char_u *p = arg;
576 char_u *q;
577 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000578 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579
Bram Moolenaar05159a02005-02-26 23:04:13 +0000580 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000581 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000582 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000583
584 /* Find "func" or "file". */
585 if (STRNCMP(p, "func", 4) == 0)
586 bp->dbg_type = DBG_FUNC;
587 else if (STRNCMP(p, "file", 4) == 0)
588 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000589 else if (
590#ifdef FEAT_PROFILE
591 gap != &prof_ga &&
592#endif
593 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000594 {
595 if (curbuf->b_ffname == NULL)
596 {
597 EMSG(_(e_noname));
598 return FAIL;
599 }
600 bp->dbg_type = DBG_FILE;
601 here = TRUE;
602 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 else
604 {
605 EMSG2(_(e_invarg2), p);
606 return FAIL;
607 }
608 p = skipwhite(p + 4);
609
610 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000611 if (here)
612 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000613 else if (
614#ifdef FEAT_PROFILE
615 gap != &prof_ga &&
616#endif
617 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618 {
619 bp->dbg_lnum = getdigits(&p);
620 p = skipwhite(p);
621 }
622 else
623 bp->dbg_lnum = 0;
624
625 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000626 if ((!here && *p == NUL)
627 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
629 {
630 EMSG2(_(e_invarg2), arg);
631 return FAIL;
632 }
633
634 if (bp->dbg_type == DBG_FUNC)
635 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000636 else if (here)
637 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 else
639 {
640 /* Expand the file name in the same way as do_source(). This means
641 * doing it twice, so that $DIR/file gets expanded when $DIR is
642 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 if (q == NULL)
645 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 vim_free(q);
648 if (p == NULL)
649 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000650 if (*p != '*')
651 {
652 bp->dbg_name = fix_fname(p);
653 vim_free(p);
654 }
655 else
656 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000657 }
658
659 if (bp->dbg_name == NULL)
660 return FAIL;
661 return OK;
662}
663
664/*
665 * ":breakadd".
666 */
667 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100668ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000669{
670 struct debuggy *bp;
671 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000672 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000673
Bram Moolenaar05159a02005-02-26 23:04:13 +0000674 gap = &dbg_breakp;
675#ifdef FEAT_PROFILE
676 if (eap->cmdidx == CMD_profile)
677 gap = &prof_ga;
678#endif
679
680 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000682 bp = &DEBUGGY(gap, gap->ga_len);
683 bp->dbg_forceit = eap->forceit;
684
Bram Moolenaar071d4272004-06-13 20:20:40 +0000685 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
686 if (pat != NULL)
687 {
688 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
689 vim_free(pat);
690 }
691 if (pat == NULL || bp->dbg_prog == NULL)
692 vim_free(bp->dbg_name);
693 else
694 {
695 if (bp->dbg_lnum == 0) /* default line number is 1 */
696 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000697#ifdef FEAT_PROFILE
698 if (eap->cmdidx != CMD_profile)
699#endif
700 {
701 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
702 ++debug_tick;
703 }
704 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705 }
706 }
707}
708
709/*
710 * ":debuggreedy".
711 */
712 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100713ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000714{
715 if (eap->addr_count == 0 || eap->line2 != 0)
716 debug_greedy = TRUE;
717 else
718 debug_greedy = FALSE;
719}
720
721/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000722 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000723 */
724 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100725ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726{
727 struct debuggy *bp, *bpi;
728 int nr;
729 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000730 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731 int i;
732 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000733 garray_T *gap;
734
735 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000736 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200737 {
738#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000739 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200740#else
741 ex_ni(eap);
742 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000743#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200744 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745
746 if (vim_isdigit(*eap->arg))
747 {
748 /* ":breakdel {nr}" */
749 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000750 for (i = 0; i < gap->ga_len; ++i)
751 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752 {
753 todel = i;
754 break;
755 }
756 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000757 else if (*eap->arg == '*')
758 {
759 todel = 0;
760 del_all = TRUE;
761 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000762 else
763 {
764 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000765 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000767 bp = &DEBUGGY(gap, gap->ga_len);
768 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000770 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000771 if (bp->dbg_type == bpi->dbg_type
772 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
773 && (bp->dbg_lnum == bpi->dbg_lnum
774 || (bp->dbg_lnum == 0
775 && (best_lnum == 0
776 || bpi->dbg_lnum < best_lnum))))
777 {
778 todel = i;
779 best_lnum = bpi->dbg_lnum;
780 }
781 }
782 vim_free(bp->dbg_name);
783 }
784
785 if (todel < 0)
786 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
787 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000788 {
789 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000790 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000791 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200792 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000793 --gap->ga_len;
794 if (todel < gap->ga_len)
795 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
796 (gap->ga_len - todel) * sizeof(struct debuggy));
797#ifdef FEAT_PROFILE
798 if (eap->cmdidx == CMD_breakdel)
799#endif
800 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000801 if (!del_all)
802 break;
803 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000804
805 /* If all breakpoints were removed clear the array. */
806 if (gap->ga_len == 0)
807 ga_clear(gap);
808 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809}
810
811/*
812 * ":breaklist".
813 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100815ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816{
817 struct debuggy *bp;
818 int i;
819
820 if (dbg_breakp.ga_len == 0)
821 MSG(_("No breakpoints defined"));
822 else
823 for (i = 0; i < dbg_breakp.ga_len; ++i)
824 {
825 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200826 if (bp->dbg_type == DBG_FILE)
827 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828 smsg((char_u *)_("%3d %s %s line %ld"),
829 bp->dbg_nr,
830 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200831 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832 (long)bp->dbg_lnum);
833 }
834}
835
836/*
837 * Find a breakpoint for a function or sourced file.
838 * Returns line number at which to break; zero when no matching breakpoint.
839 */
840 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100841dbg_find_breakpoint(
842 int file, /* TRUE for a file, FALSE for a function */
843 char_u *fname, /* file or function name */
844 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000846 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
847}
848
849#if defined(FEAT_PROFILE) || defined(PROTO)
850/*
851 * Return TRUE if profiling is on for a function or sourced file.
852 */
853 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100854has_profiling(
855 int file, /* TRUE for a file, FALSE for a function */
856 char_u *fname, /* file or function name */
857 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000858{
859 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
860 != (linenr_T)0);
861}
862#endif
863
864/*
865 * Common code for dbg_find_breakpoint() and has_profiling().
866 */
867 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100868debuggy_find(
869 int file, /* TRUE for a file, FALSE for a function */
870 char_u *fname, /* file or function name */
871 linenr_T after, /* after this line number */
872 garray_T *gap, /* either &dbg_breakp or &prof_ga */
873 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000874{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875 struct debuggy *bp;
876 int i;
877 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000878 char_u *name = fname;
879 int prev_got_int;
880
Bram Moolenaar05159a02005-02-26 23:04:13 +0000881 /* Return quickly when there are no breakpoints. */
882 if (gap->ga_len == 0)
883 return (linenr_T)0;
884
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885 /* Replace K_SNR in function name with "<SNR>". */
886 if (!file && fname[0] == K_SPECIAL)
887 {
888 name = alloc((unsigned)STRLEN(fname) + 3);
889 if (name == NULL)
890 name = fname;
891 else
892 {
893 STRCPY(name, "<SNR>");
894 STRCPY(name + 5, fname + 3);
895 }
896 }
897
Bram Moolenaar05159a02005-02-26 23:04:13 +0000898 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000899 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000900 /* Skip entries that are not useful or are for a line that is beyond
901 * an already found breakpoint. */
902 bp = &DEBUGGY(gap, i);
903 if (((bp->dbg_type == DBG_FILE) == file && (
904#ifdef FEAT_PROFILE
905 gap == &prof_ga ||
906#endif
907 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000908 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000910 * Save the value of got_int and reset it. We don't want a
911 * previous interruption cancel matching, only hitting CTRL-C
912 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000913 */
914 prev_got_int = got_int;
915 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100916 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000917 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000918 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000919 if (fp != NULL)
920 *fp = bp->dbg_forceit;
921 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000922 got_int |= prev_got_int;
923 }
924 }
925 if (name != fname)
926 vim_free(name);
927
928 return lnum;
929}
930
931/*
932 * Called when a breakpoint was encountered.
933 */
934 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100935dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000936{
937 /* We need to check if this line is actually executed in do_one_cmd() */
938 debug_breakpoint_name = name;
939 debug_breakpoint_lnum = lnum;
940}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000941
942
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000943# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000944/*
945 * Store the current time in "tm".
946 */
947 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100948profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000949{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000950# ifdef WIN3264
951 QueryPerformanceCounter(tm);
952# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000953 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000954# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000955}
956
957/*
958 * Compute the elapsed time from "tm" till now and store in "tm".
959 */
960 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100961profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000962{
963 proftime_T now;
964
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000965# ifdef WIN3264
966 QueryPerformanceCounter(&now);
967 tm->QuadPart = now.QuadPart - tm->QuadPart;
968# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000969 gettimeofday(&now, NULL);
970 tm->tv_usec = now.tv_usec - tm->tv_usec;
971 tm->tv_sec = now.tv_sec - tm->tv_sec;
972 if (tm->tv_usec < 0)
973 {
974 tm->tv_usec += 1000000;
975 --tm->tv_sec;
976 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000977# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000978}
979
980/*
981 * Subtract the time "tm2" from "tm".
982 */
983 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100984profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000985{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000986# ifdef WIN3264
987 tm->QuadPart -= tm2->QuadPart;
988# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000989 tm->tv_usec -= tm2->tv_usec;
990 tm->tv_sec -= tm2->tv_sec;
991 if (tm->tv_usec < 0)
992 {
993 tm->tv_usec += 1000000;
994 --tm->tv_sec;
995 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000996# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000997}
998
999/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001000 * Return a string that represents the time in "tm".
1001 * Uses a static buffer!
1002 */
1003 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001004profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001005{
1006 static char buf[50];
1007
1008# ifdef WIN3264
1009 LARGE_INTEGER fr;
1010
1011 QueryPerformanceFrequency(&fr);
1012 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1013# else
1014 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001015# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001016 return buf;
1017}
1018
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001019/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001020 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001021 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001022 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001023profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001024{
1025 if (msec <= 0) /* no limit */
1026 profile_zero(tm);
1027 else
1028 {
1029# ifdef WIN3264
1030 LARGE_INTEGER fr;
1031
1032 QueryPerformanceCounter(tm);
1033 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001034 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001035# else
1036 long usec;
1037
1038 gettimeofday(tm, NULL);
1039 usec = (long)tm->tv_usec + (long)msec * 1000;
1040 tm->tv_usec = usec % 1000000L;
1041 tm->tv_sec += usec / 1000000L;
1042# endif
1043 }
1044}
1045
1046/*
1047 * Return TRUE if the current time is past "tm".
1048 */
1049 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001050profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001051{
1052 proftime_T now;
1053
1054# ifdef WIN3264
1055 if (tm->QuadPart == 0) /* timer was not set */
1056 return FALSE;
1057 QueryPerformanceCounter(&now);
1058 return (now.QuadPart > tm->QuadPart);
1059# else
1060 if (tm->tv_sec == 0) /* timer was not set */
1061 return FALSE;
1062 gettimeofday(&now, NULL);
1063 return (now.tv_sec > tm->tv_sec
1064 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1065# endif
1066}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001067
1068/*
1069 * Set the time in "tm" to zero.
1070 */
1071 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001072profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001073{
1074# ifdef WIN3264
1075 tm->QuadPart = 0;
1076# else
1077 tm->tv_usec = 0;
1078 tm->tv_sec = 0;
1079# endif
1080}
1081
Bram Moolenaar76929292008-01-06 19:07:36 +00001082# endif /* FEAT_PROFILE || FEAT_RELTIME */
1083
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001084#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1085# if defined(HAVE_MATH_H)
1086# include <math.h>
1087# endif
1088
1089/*
1090 * Divide the time "tm" by "count" and store in "tm2".
1091 */
1092 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001093profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001094{
1095 if (count == 0)
1096 profile_zero(tm2);
1097 else
1098 {
1099# ifdef WIN3264
1100 tm2->QuadPart = tm->QuadPart / count;
1101# else
1102 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1103
1104 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001105 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001106# endif
1107 }
1108}
1109#endif
1110
Bram Moolenaar76929292008-01-06 19:07:36 +00001111# if defined(FEAT_PROFILE) || defined(PROTO)
1112/*
1113 * Functions for profiling.
1114 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001115static void script_do_profile(scriptitem_T *si);
1116static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001117static proftime_T prof_wait_time;
1118
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001119/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001120 * Add the time "tm2" to "tm".
1121 */
1122 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001123profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001124{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001125# ifdef WIN3264
1126 tm->QuadPart += tm2->QuadPart;
1127# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001128 tm->tv_usec += tm2->tv_usec;
1129 tm->tv_sec += tm2->tv_sec;
1130 if (tm->tv_usec >= 1000000)
1131 {
1132 tm->tv_usec -= 1000000;
1133 ++tm->tv_sec;
1134 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001135# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001136}
1137
1138/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001139 * Add the "self" time from the total time and the children's time.
1140 */
1141 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001142profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001143{
1144 /* Check that the result won't be negative. Can happen with recursive
1145 * calls. */
1146#ifdef WIN3264
1147 if (total->QuadPart <= children->QuadPart)
1148 return;
1149#else
1150 if (total->tv_sec < children->tv_sec
1151 || (total->tv_sec == children->tv_sec
1152 && total->tv_usec <= children->tv_usec))
1153 return;
1154#endif
1155 profile_add(self, total);
1156 profile_sub(self, children);
1157}
1158
1159/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001160 * Get the current waittime.
1161 */
1162 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001163profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001164{
1165 *tm = prof_wait_time;
1166}
1167
1168/*
1169 * Subtract the passed waittime since "tm" from "tma".
1170 */
1171 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001172profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001173{
1174 proftime_T tm3 = prof_wait_time;
1175
1176 profile_sub(&tm3, tm);
1177 profile_sub(tma, &tm3);
1178}
1179
1180/*
1181 * Return TRUE if "tm1" and "tm2" are equal.
1182 */
1183 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001184profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001185{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001186# ifdef WIN3264
1187 return (tm1->QuadPart == tm2->QuadPart);
1188# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001189 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001190# endif
1191}
1192
1193/*
1194 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1195 */
1196 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001197profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001198{
1199# ifdef WIN3264
1200 return (int)(tm2->QuadPart - tm1->QuadPart);
1201# else
1202 if (tm1->tv_sec == tm2->tv_sec)
1203 return tm2->tv_usec - tm1->tv_usec;
1204 return tm2->tv_sec - tm1->tv_sec;
1205# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001206}
1207
Bram Moolenaar05159a02005-02-26 23:04:13 +00001208static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001209static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001210
1211/*
1212 * ":profile cmd args"
1213 */
1214 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001215ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001216{
1217 char_u *e;
1218 int len;
1219
1220 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001221 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001222 e = skipwhite(e);
1223
1224 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1225 {
1226 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001227 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001228 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001229 profile_zero(&prof_wait_time);
1230 set_vim_var_nr(VV_PROFILING, 1L);
1231 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001232 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001233 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001234 else if (STRCMP(eap->arg, "pause") == 0)
1235 {
1236 if (do_profiling == PROF_YES)
1237 profile_start(&pause_time);
1238 do_profiling = PROF_PAUSED;
1239 }
1240 else if (STRCMP(eap->arg, "continue") == 0)
1241 {
1242 if (do_profiling == PROF_PAUSED)
1243 {
1244 profile_end(&pause_time);
1245 profile_add(&prof_wait_time, &pause_time);
1246 }
1247 do_profiling = PROF_YES;
1248 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001249 else
1250 {
1251 /* The rest is similar to ":breakadd". */
1252 ex_breakadd(eap);
1253 }
1254}
1255
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001256/* Command line expansion for :profile. */
1257static enum
1258{
1259 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001260 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001261} pexpand_what;
1262
1263static char *pexpand_cmds[] = {
1264 "start",
1265#define PROFCMD_START 0
1266 "pause",
1267#define PROFCMD_PAUSE 1
1268 "continue",
1269#define PROFCMD_CONTINUE 2
1270 "func",
1271#define PROFCMD_FUNC 3
1272 "file",
1273#define PROFCMD_FILE 4
1274 NULL
1275#define PROFCMD_LAST 5
1276};
1277
1278/*
1279 * Function given to ExpandGeneric() to obtain the profile command
1280 * specific expansion.
1281 */
1282 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001283get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001284{
1285 switch (pexpand_what)
1286 {
1287 case PEXP_SUBCMD:
1288 return (char_u *)pexpand_cmds[idx];
1289 /* case PEXP_FUNC: TODO */
1290 default:
1291 return NULL;
1292 }
1293}
1294
1295/*
1296 * Handle command line completion for :profile command.
1297 */
1298 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001299set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001300{
1301 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001302
1303 /* Default: expand subcommands. */
1304 xp->xp_context = EXPAND_PROFILE;
1305 pexpand_what = PEXP_SUBCMD;
1306 xp->xp_pattern = arg;
1307
1308 end_subcmd = skiptowhite(arg);
1309 if (*end_subcmd == NUL)
1310 return;
1311
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001312 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001313 {
1314 xp->xp_context = EXPAND_FILES;
1315 xp->xp_pattern = skipwhite(end_subcmd);
1316 return;
1317 }
1318
1319 /* TODO: expand function names after "func" */
1320 xp->xp_context = EXPAND_NOTHING;
1321}
1322
Bram Moolenaar05159a02005-02-26 23:04:13 +00001323/*
1324 * Dump the profiling info.
1325 */
1326 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001327profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001328{
1329 FILE *fd;
1330
1331 if (profile_fname != NULL)
1332 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001333 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001334 if (fd == NULL)
1335 EMSG2(_(e_notopen), profile_fname);
1336 else
1337 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001338 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001339 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001340 fclose(fd);
1341 }
1342 }
1343}
1344
1345/*
1346 * Start profiling script "fp".
1347 */
1348 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001349script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001350{
1351 si->sn_pr_count = 0;
1352 profile_zero(&si->sn_pr_total);
1353 profile_zero(&si->sn_pr_self);
1354
1355 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1356 si->sn_prl_idx = -1;
1357 si->sn_prof_on = TRUE;
1358 si->sn_pr_nest = 0;
1359}
1360
1361/*
1362 * save time when starting to invoke another script or function.
1363 */
1364 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001365script_prof_save(
1366 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001367{
1368 scriptitem_T *si;
1369
1370 if (current_SID > 0 && current_SID <= script_items.ga_len)
1371 {
1372 si = &SCRIPT_ITEM(current_SID);
1373 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1374 profile_start(&si->sn_pr_child);
1375 }
1376 profile_get_wait(tm);
1377}
1378
1379/*
1380 * Count time spent in children after invoking another script or function.
1381 */
1382 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001383script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001384{
1385 scriptitem_T *si;
1386
1387 if (current_SID > 0 && current_SID <= script_items.ga_len)
1388 {
1389 si = &SCRIPT_ITEM(current_SID);
1390 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1391 {
1392 profile_end(&si->sn_pr_child);
1393 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1394 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1395 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1396 }
1397 }
1398}
1399
1400static proftime_T inchar_time;
1401
1402/*
1403 * Called when starting to wait for the user to type a character.
1404 */
1405 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001406prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001407{
1408 profile_start(&inchar_time);
1409}
1410
1411/*
1412 * Called when finished waiting for the user to type a character.
1413 */
1414 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001415prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001416{
1417 profile_end(&inchar_time);
1418 profile_add(&prof_wait_time, &inchar_time);
1419}
1420
1421/*
1422 * Dump the profiling results for all scripts in file "fd".
1423 */
1424 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001425script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001426{
1427 int id;
1428 scriptitem_T *si;
1429 int i;
1430 FILE *sfd;
1431 sn_prl_T *pp;
1432
1433 for (id = 1; id <= script_items.ga_len; ++id)
1434 {
1435 si = &SCRIPT_ITEM(id);
1436 if (si->sn_prof_on)
1437 {
1438 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1439 if (si->sn_pr_count == 1)
1440 fprintf(fd, "Sourced 1 time\n");
1441 else
1442 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1443 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1444 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1445 fprintf(fd, "\n");
1446 fprintf(fd, "count total (s) self (s)\n");
1447
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001448 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001449 if (sfd == NULL)
1450 fprintf(fd, "Cannot open file!\n");
1451 else
1452 {
1453 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1454 {
1455 if (vim_fgets(IObuff, IOSIZE, sfd))
1456 break;
1457 pp = &PRL_ITEM(si, i);
1458 if (pp->snp_count > 0)
1459 {
1460 fprintf(fd, "%5d ", pp->snp_count);
1461 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1462 fprintf(fd, " ");
1463 else
1464 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1465 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1466 }
1467 else
1468 fprintf(fd, " ");
1469 fprintf(fd, "%s", IObuff);
1470 }
1471 fclose(sfd);
1472 }
1473 fprintf(fd, "\n");
1474 }
1475 }
1476}
1477
1478/*
1479 * Return TRUE when a function defined in the current script should be
1480 * profiled.
1481 */
1482 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001483prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001484{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001485 if (current_SID > 0)
1486 return SCRIPT_ITEM(current_SID).sn_pr_force;
1487 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001488}
1489
1490# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001491#endif
1492
1493/*
1494 * If 'autowrite' option set, try to write the file.
1495 * Careful: autocommands may make "buf" invalid!
1496 *
1497 * return FAIL for failure, OK otherwise
1498 */
1499 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001500autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001501{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001502 int r;
1503
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 if (!(p_aw || p_awa) || !p_write
1505#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001506 /* never autowrite a "nofile" or "nowrite" buffer */
1507 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001508#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001509 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001510 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001511 r = buf_write_all(buf, forceit);
1512
1513 /* Writing may succeed but the buffer still changed, e.g., when there is a
1514 * conversion error. We do want to return FAIL then. */
1515 if (buf_valid(buf) && bufIsChanged(buf))
1516 r = FAIL;
1517 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001518}
1519
1520/*
1521 * flush all buffers, except the ones that are readonly
1522 */
1523 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001524autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001525{
1526 buf_T *buf;
1527
1528 if (!(p_aw || p_awa) || !p_write)
1529 return;
1530 for (buf = firstbuf; buf; buf = buf->b_next)
1531 if (bufIsChanged(buf) && !buf->b_p_ro)
1532 {
1533 (void)buf_write_all(buf, FALSE);
1534#ifdef FEAT_AUTOCMD
1535 /* an autocommand may have deleted the buffer */
1536 if (!buf_valid(buf))
1537 buf = firstbuf;
1538#endif
1539 }
1540}
1541
1542/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001543 * Return TRUE if buffer was changed and cannot be abandoned.
1544 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001545 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001546 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001547check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001548{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001549 int forceit = (flags & CCGD_FORCEIT);
1550
Bram Moolenaar071d4272004-06-13 20:20:40 +00001551 if ( !forceit
1552 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001553 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1554 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001555 {
1556#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1557 if ((p_confirm || cmdmod.confirm) && p_write)
1558 {
1559 buf_T *buf2;
1560 int count = 0;
1561
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001562 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001563 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1564 if (bufIsChanged(buf2)
1565 && (buf2->b_ffname != NULL
1566# ifdef FEAT_BROWSE
1567 || cmdmod.browse
1568# endif
1569 ))
1570 ++count;
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 dialog_changed(buf, count > 1);
1577# ifdef FEAT_AUTOCMD
1578 if (!buf_valid(buf))
1579 /* Autocommand deleted buffer, oops! It's not changed now. */
1580 return FALSE;
1581# endif
1582 return bufIsChanged(buf);
1583 }
1584#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001585 if (flags & CCGD_EXCMD)
1586 EMSG(_(e_nowrtmsg));
1587 else
1588 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589 return TRUE;
1590 }
1591 return FALSE;
1592}
1593
1594#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1595
1596#if defined(FEAT_BROWSE) || defined(PROTO)
1597/*
1598 * When wanting to write a file without a file name, ask the user for a name.
1599 */
1600 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001601browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602{
1603 if (buf->b_fname == NULL)
1604 {
1605 char_u *fname;
1606
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001607 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1608 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001609 if (fname != NULL)
1610 {
1611 if (setfname(buf, fname, NULL, TRUE) == OK)
1612 buf->b_flags |= BF_NOTEDITED;
1613 vim_free(fname);
1614 }
1615 }
1616}
1617#endif
1618
1619/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001620 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621 * Must check 'write' option first!
1622 */
1623 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001624dialog_changed(
1625 buf_T *buf,
1626 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001628 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001629 int ret;
1630 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001631 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001632
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001633 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001634 (buf->b_fname != NULL) ?
1635 buf->b_fname : (char_u *)_("Untitled"));
1636 if (checkall)
1637 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1638 else
1639 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1640
Bram Moolenaar8218f602012-04-25 17:32:18 +02001641 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1642 * function. */
1643 ea.append = ea.forceit = FALSE;
1644
Bram Moolenaar071d4272004-06-13 20:20:40 +00001645 if (ret == VIM_YES)
1646 {
1647#ifdef FEAT_BROWSE
1648 /* May get file name, when there is none */
1649 browse_save_fname(buf);
1650#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001651 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1652 buf->b_fname, buf->b_ffname, FALSE) == OK)
1653 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654 (void)buf_write_all(buf, FALSE);
1655 }
1656 else if (ret == VIM_NO)
1657 {
1658 unchanged(buf, TRUE);
1659 }
1660 else if (ret == VIM_ALL)
1661 {
1662 /*
1663 * Write all modified files that can be written.
1664 * Skip readonly buffers, these need to be confirmed
1665 * individually.
1666 */
1667 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1668 {
1669 if (bufIsChanged(buf2)
1670 && (buf2->b_ffname != NULL
1671#ifdef FEAT_BROWSE
1672 || cmdmod.browse
1673#endif
1674 )
1675 && !buf2->b_p_ro)
1676 {
1677#ifdef FEAT_BROWSE
1678 /* May get file name, when there is none */
1679 browse_save_fname(buf2);
1680#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001681 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1682 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1683 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684 (void)buf_write_all(buf2, FALSE);
1685#ifdef FEAT_AUTOCMD
1686 /* an autocommand may have deleted the buffer */
1687 if (!buf_valid(buf2))
1688 buf2 = firstbuf;
1689#endif
1690 }
1691 }
1692 }
1693 else if (ret == VIM_DISCARDALL)
1694 {
1695 /*
1696 * mark all buffers as unchanged
1697 */
1698 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1699 unchanged(buf2, TRUE);
1700 }
1701}
1702#endif
1703
1704/*
1705 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1706 * hidden, autowriting it or unloading it.
1707 */
1708 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001709can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001710{
1711 return ( P_HID(buf)
1712 || !bufIsChanged(buf)
1713 || buf->b_nwindows > 1
1714 || autowrite(buf, forceit) == OK
1715 || forceit);
1716}
1717
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001718static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001719
1720/*
1721 * Add a buffer number to "bufnrs", unless it's already there.
1722 */
1723 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001724add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001725{
1726 int i;
1727
1728 for (i = 0; i < *bufnump; ++i)
1729 if (bufnrs[i] == nr)
1730 return;
1731 bufnrs[*bufnump] = nr;
1732 *bufnump = *bufnump + 1;
1733}
1734
Bram Moolenaar071d4272004-06-13 20:20:40 +00001735/*
1736 * Return TRUE if any buffer was changed and cannot be abandoned.
1737 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001738 * When "unload" is true the current buffer is unloaded instead of making it
1739 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 */
1741 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001742check_changed_any(
1743 int hidden, /* Only check hidden buffers */
1744 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001746 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747 buf_T *buf;
1748 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001749 int i;
1750 int bufnum = 0;
1751 int bufcount = 0;
1752 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001753#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001754 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755 win_T *wp;
1756#endif
1757
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001758 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1759 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001761 if (bufcount == 0)
1762 return FALSE;
1763
1764 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1765 if (bufnrs == NULL)
1766 return FALSE;
1767
1768 /* curbuf */
1769 bufnrs[bufnum++] = curbuf->b_fnum;
1770#ifdef FEAT_WINDOWS
1771 /* buf in curtab */
1772 FOR_ALL_WINDOWS(wp)
1773 if (wp->w_buffer != curbuf)
1774 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1775
1776 /* buf in other tab */
1777 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1778 if (tp != curtab)
1779 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1780 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1781#endif
1782 /* any other buf */
1783 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1784 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1785
1786 for (i = 0; i < bufnum; ++i)
1787 {
1788 buf = buflist_findnr(bufnrs[i]);
1789 if (buf == NULL)
1790 continue;
1791 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1792 {
1793 /* Try auto-writing the buffer. If this fails but the buffer no
1794 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001795 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1796 | CCGD_MULTWIN
1797 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001798 break; /* didn't save - still changes */
1799 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 }
1801
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001802 if (i >= bufnum)
1803 goto theend;
1804
1805 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806 exiting = FALSE;
1807#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1808 /*
1809 * When ":confirm" used, don't give an error message.
1810 */
1811 if (!(p_confirm || cmdmod.confirm))
1812#endif
1813 {
1814 /* There must be a wait_return for this message, do_buffer()
1815 * may cause a redraw. But wait_return() is a no-op when vgetc()
1816 * is busy (Quit used from window menu), then make sure we don't
1817 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001818 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819 {
1820 msg_row = cmdline_row;
1821 msg_col = 0;
1822 msg_didout = FALSE;
1823 }
1824 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001825 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826 {
1827 save = no_wait_return;
1828 no_wait_return = FALSE;
1829 wait_return(FALSE);
1830 no_wait_return = save;
1831 }
1832 }
1833
1834#ifdef FEAT_WINDOWS
1835 /* Try to find a window that contains the buffer. */
1836 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001837 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 if (wp->w_buffer == buf)
1839 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001840 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001841# ifdef FEAT_AUTOCMD
1842 /* Paranoia: did autocms wipe out the buffer with changes? */
1843 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001844 {
1845 goto theend;
1846 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001848 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001850buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851#endif
1852
1853 /* Open the changed buffer in the current window. */
1854 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001855 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001856
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001857theend:
1858 vim_free(bufnrs);
1859 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860}
1861
1862/*
1863 * return FAIL if there is no file name, OK if there is one
1864 * give error message for FAIL
1865 */
1866 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001867check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001868{
1869 if (curbuf->b_ffname == NULL)
1870 {
1871 EMSG(_(e_noname));
1872 return FAIL;
1873 }
1874 return OK;
1875}
1876
1877/*
1878 * flush the contents of a buffer, unless it has no file name
1879 *
1880 * return FAIL for failure, OK otherwise
1881 */
1882 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001883buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001884{
1885 int retval;
1886#ifdef FEAT_AUTOCMD
1887 buf_T *old_curbuf = curbuf;
1888#endif
1889
1890 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1891 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1892 FALSE, forceit, TRUE, FALSE));
1893#ifdef FEAT_AUTOCMD
1894 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001895 {
1896 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001898 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899#endif
1900 return retval;
1901}
1902
1903/*
1904 * Code to handle the argument list.
1905 */
1906
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001907static char_u *do_one_arg(char_u *str);
1908static int do_arglist(char_u *str, int what, int after);
1909static void alist_check_arg_idx(void);
1910static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001911#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001912static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001913#endif
1914#define AL_SET 1
1915#define AL_ADD 2
1916#define AL_DEL 3
1917
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001919 * Isolate one argument, taking backticks.
1920 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 * Return a pointer to the start of the next argument.
1922 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001923 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001924do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925{
1926 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001927 int inbacktick;
1928
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929 inbacktick = FALSE;
1930 for (p = str; *str; ++str)
1931 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001932 /* When the backslash is used for escaping the special meaning of a
1933 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934 if (rem_backslash(str))
1935 {
1936 *p++ = *str++;
1937 *p++ = *str;
1938 }
1939 else
1940 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001941 /* An item ends at a space not in backticks */
1942 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001944 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001946 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001947 }
1948 }
1949 str = skipwhite(str);
1950 *p = NUL;
1951
1952 return str;
1953}
1954
Bram Moolenaar86b68352004-12-27 21:59:20 +00001955/*
1956 * Separate the arguments in "str" and return a list of pointers in the
1957 * growarray "gap".
1958 */
1959 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001960get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001961{
1962 ga_init2(gap, (int)sizeof(char_u *), 20);
1963 while (*str != NUL)
1964 {
1965 if (ga_grow(gap, 1) == FAIL)
1966 {
1967 ga_clear(gap);
1968 return FAIL;
1969 }
1970 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1971
1972 /* Isolate one argument, change it in-place, put a NUL after it. */
1973 str = do_one_arg(str);
1974 }
1975 return OK;
1976}
1977
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001978#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001979/*
1980 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001981 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001982 * Return FAIL or OK.
1983 */
1984 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001985get_arglist_exp(
1986 char_u *str,
1987 int *fcountp,
1988 char_u ***fnamesp,
1989 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001990{
1991 garray_T ga;
1992 int i;
1993
1994 if (get_arglist(&ga, str) == FAIL)
1995 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001996 if (wig == TRUE)
1997 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1998 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1999 else
2000 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2001 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2002
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002003 ga_clear(&ga);
2004 return i;
2005}
2006#endif
2007
Bram Moolenaar071d4272004-06-13 20:20:40 +00002008#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2009/*
2010 * Redefine the argument list.
2011 */
2012 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002013set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002014{
2015 do_arglist(str, AL_SET, 0);
2016}
2017#endif
2018
2019/*
2020 * "what" == AL_SET: Redefine the argument list to 'str'.
2021 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2022 * "what" == AL_DEL: remove files in 'str' from the argument list.
2023 *
2024 * Return FAIL for failure, OK otherwise.
2025 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002027do_arglist(
2028 char_u *str,
2029 int what UNUSED,
2030 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031{
2032 garray_T new_ga;
2033 int exp_count;
2034 char_u **exp_files;
2035 int i;
2036#ifdef FEAT_LISTCMDS
2037 char_u *p;
2038 int match;
2039#endif
2040
2041 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002042 * Set default argument for ":argadd" command.
2043 */
2044 if (what == AL_ADD && *str == NUL)
2045 {
2046 if (curbuf->b_ffname == NULL)
2047 return FAIL;
2048 str = curbuf->b_fname;
2049 }
2050
2051 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002052 * Collect all file name arguments in "new_ga".
2053 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002054 if (get_arglist(&new_ga, str) == FAIL)
2055 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002056
2057#ifdef FEAT_LISTCMDS
2058 if (what == AL_DEL)
2059 {
2060 regmatch_T regmatch;
2061 int didone;
2062
2063 /*
2064 * Delete the items: use each item as a regexp and find a match in the
2065 * argument list.
2066 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002067 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2069 {
2070 p = ((char_u **)new_ga.ga_data)[i];
2071 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2072 if (p == NULL)
2073 break;
2074 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2075 if (regmatch.regprog == NULL)
2076 {
2077 vim_free(p);
2078 break;
2079 }
2080
2081 didone = FALSE;
2082 for (match = 0; match < ARGCOUNT; ++match)
2083 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2084 (colnr_T)0))
2085 {
2086 didone = TRUE;
2087 vim_free(ARGLIST[match].ae_fname);
2088 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2089 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2090 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 if (curwin->w_arg_idx > match)
2092 --curwin->w_arg_idx;
2093 --match;
2094 }
2095
Bram Moolenaar473de612013-06-08 18:19:48 +02002096 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002097 vim_free(p);
2098 if (!didone)
2099 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2100 }
2101 ga_clear(&new_ga);
2102 }
2103 else
2104#endif
2105 {
2106 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2107 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2108 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002109 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002110 {
2111 EMSG(_(e_nomatch));
2112 return FAIL;
2113 }
2114
2115#ifdef FEAT_LISTCMDS
2116 if (what == AL_ADD)
2117 {
2118 (void)alist_add_list(exp_count, exp_files, after);
2119 vim_free(exp_files);
2120 }
2121 else /* what == AL_SET */
2122#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002123 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124 }
2125
2126 alist_check_arg_idx();
2127
2128 return OK;
2129}
2130
2131/*
2132 * Check the validity of the arg_idx for each other window.
2133 */
2134 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002135alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136{
2137#ifdef FEAT_WINDOWS
2138 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002139 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002140
Bram Moolenaarf740b292006-02-16 22:11:02 +00002141 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142 if (win->w_alist == curwin->w_alist)
2143 check_arg_idx(win);
2144#else
2145 check_arg_idx(curwin);
2146#endif
2147}
2148
2149/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002150 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002151 * index.
2152 */
2153 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002154editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002155{
2156 return !(win->w_arg_idx >= WARGCOUNT(win)
2157 || (win->w_buffer->b_fnum
2158 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2159 && (win->w_buffer->b_ffname == NULL
2160 || !(fullpathcmp(
2161 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2162 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2163}
2164
2165/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002166 * Check if window "win" is editing the w_arg_idx file in its argument list.
2167 */
2168 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002169check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002171 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 {
2173 /* We are not editing the current entry in the argument list.
2174 * Set "arg_had_last" if we are editing the last one. */
2175 win->w_arg_idx_invalid = TRUE;
2176 if (win->w_arg_idx != WARGCOUNT(win) - 1
2177 && arg_had_last == FALSE
2178#ifdef FEAT_WINDOWS
2179 && ALIST(win) == &global_alist
2180#endif
2181 && GARGCOUNT > 0
2182 && win->w_arg_idx < GARGCOUNT
2183 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2184 || (win->w_buffer->b_ffname != NULL
2185 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2186 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2187 arg_had_last = TRUE;
2188 }
2189 else
2190 {
2191 /* We are editing the current entry in the argument list.
2192 * Set "arg_had_last" if it's also the last one */
2193 win->w_arg_idx_invalid = FALSE;
2194 if (win->w_arg_idx == WARGCOUNT(win) - 1
2195#ifdef FEAT_WINDOWS
2196 && win->w_alist == &global_alist
2197#endif
2198 )
2199 arg_had_last = TRUE;
2200 }
2201}
2202
2203/*
2204 * ":args", ":argslocal" and ":argsglobal".
2205 */
2206 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002207ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002208{
2209 int i;
2210
2211 if (eap->cmdidx != CMD_args)
2212 {
2213#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2214 alist_unlink(ALIST(curwin));
2215 if (eap->cmdidx == CMD_argglobal)
2216 ALIST(curwin) = &global_alist;
2217 else /* eap->cmdidx == CMD_arglocal */
2218 alist_new();
2219#else
2220 ex_ni(eap);
2221 return;
2222#endif
2223 }
2224
2225 if (!ends_excmd(*eap->arg))
2226 {
2227 /*
2228 * ":args file ..": define new argument list, handle like ":next"
2229 * Also for ":argslocal file .." and ":argsglobal file ..".
2230 */
2231 ex_next(eap);
2232 }
2233 else
2234#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2235 if (eap->cmdidx == CMD_args)
2236#endif
2237 {
2238 /*
2239 * ":args": list arguments.
2240 */
2241 if (ARGCOUNT > 0)
2242 {
2243 /* Overwrite the command, for a short list there is no scrolling
2244 * required and no wait_return(). */
2245 gotocmdline(TRUE);
2246 for (i = 0; i < ARGCOUNT; ++i)
2247 {
2248 if (i == curwin->w_arg_idx)
2249 msg_putchar('[');
2250 msg_outtrans(alist_name(&ARGLIST[i]));
2251 if (i == curwin->w_arg_idx)
2252 msg_putchar(']');
2253 msg_putchar(' ');
2254 }
2255 }
2256 }
2257#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2258 else if (eap->cmdidx == CMD_arglocal)
2259 {
2260 garray_T *gap = &curwin->w_alist->al_ga;
2261
2262 /*
2263 * ":argslocal": make a local copy of the global argument list.
2264 */
2265 if (ga_grow(gap, GARGCOUNT) == OK)
2266 for (i = 0; i < GARGCOUNT; ++i)
2267 if (GARGLIST[i].ae_fname != NULL)
2268 {
2269 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2270 vim_strsave(GARGLIST[i].ae_fname);
2271 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2272 GARGLIST[i].ae_fnum;
2273 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 }
2275 }
2276#endif
2277}
2278
2279/*
2280 * ":previous", ":sprevious", ":Next" and ":sNext".
2281 */
2282 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002283ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284{
2285 /* If past the last one already, go to the last one. */
2286 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2287 do_argfile(eap, ARGCOUNT - 1);
2288 else
2289 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2290}
2291
2292/*
2293 * ":rewind", ":first", ":sfirst" and ":srewind".
2294 */
2295 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002296ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297{
2298 do_argfile(eap, 0);
2299}
2300
2301/*
2302 * ":last" and ":slast".
2303 */
2304 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002305ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306{
2307 do_argfile(eap, ARGCOUNT - 1);
2308}
2309
2310/*
2311 * ":argument" and ":sargument".
2312 */
2313 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002314ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002315{
2316 int i;
2317
2318 if (eap->addr_count > 0)
2319 i = eap->line2 - 1;
2320 else
2321 i = curwin->w_arg_idx;
2322 do_argfile(eap, i);
2323}
2324
2325/*
2326 * Edit file "argn" of the argument lists.
2327 */
2328 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002329do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002330{
2331 int other;
2332 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002333 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002334
2335 if (argn < 0 || argn >= ARGCOUNT)
2336 {
2337 if (ARGCOUNT <= 1)
2338 EMSG(_("E163: There is only one file to edit"));
2339 else if (argn < 0)
2340 EMSG(_("E164: Cannot go before first file"));
2341 else
2342 EMSG(_("E165: Cannot go beyond last file"));
2343 }
2344 else
2345 {
2346 setpcmark();
2347#ifdef FEAT_GUI
2348 need_mouse_correct = TRUE;
2349#endif
2350
2351#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002352 /* split window or create new tab page first */
2353 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354 {
2355 if (win_split(0, 0) == FAIL)
2356 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002357 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 }
2359 else
2360#endif
2361 {
2362 /*
2363 * if 'hidden' set, only check for changed file when re-editing
2364 * the same buffer
2365 */
2366 other = TRUE;
2367 if (P_HID(curbuf))
2368 {
2369 p = fix_fname(alist_name(&ARGLIST[argn]));
2370 other = otherfile(p);
2371 vim_free(p);
2372 }
2373 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002374 && check_changed(curbuf, CCGD_AW
2375 | (other ? 0 : CCGD_MULTWIN)
2376 | (eap->forceit ? CCGD_FORCEIT : 0)
2377 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378 return;
2379 }
2380
2381 curwin->w_arg_idx = argn;
2382 if (argn == ARGCOUNT - 1
2383#ifdef FEAT_WINDOWS
2384 && curwin->w_alist == &global_alist
2385#endif
2386 )
2387 arg_had_last = TRUE;
2388
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002389 /* Edit the file; always use the last known line number.
2390 * When it fails (e.g. Abort for already edited file) restore the
2391 * argument index. */
2392 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002394 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2395 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002396 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002397 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002398 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399 setmark('\'');
2400 }
2401}
2402
2403/*
2404 * ":next", and commands that behave like it.
2405 */
2406 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002407ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408{
2409 int i;
2410
2411 /*
2412 * check for changed buffer now, if this fails the argument list is not
2413 * redefined.
2414 */
2415 if ( P_HID(curbuf)
2416 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002417 || !check_changed(curbuf, CCGD_AW
2418 | (eap->forceit ? CCGD_FORCEIT : 0)
2419 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420 {
2421 if (*eap->arg != NUL) /* redefine file list */
2422 {
2423 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2424 return;
2425 i = 0;
2426 }
2427 else
2428 i = curwin->w_arg_idx + (int)eap->line2;
2429 do_argfile(eap, i);
2430 }
2431}
2432
2433#ifdef FEAT_LISTCMDS
2434/*
2435 * ":argedit"
2436 */
2437 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002438ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439{
2440 int fnum;
2441 int i;
2442 char_u *s;
2443
2444 /* Add the argument to the buffer list and get the buffer number. */
2445 fnum = buflist_add(eap->arg, BLN_LISTED);
2446
2447 /* Check if this argument is already in the argument list. */
2448 for (i = 0; i < ARGCOUNT; ++i)
2449 if (ARGLIST[i].ae_fnum == fnum)
2450 break;
2451 if (i == ARGCOUNT)
2452 {
2453 /* Can't find it, add it to the argument list. */
2454 s = vim_strsave(eap->arg);
2455 if (s == NULL)
2456 return;
2457 i = alist_add_list(1, &s,
2458 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2459 if (i < 0)
2460 return;
2461 curwin->w_arg_idx = i;
2462 }
2463
2464 alist_check_arg_idx();
2465
2466 /* Edit the argument. */
2467 do_argfile(eap, i);
2468}
2469
2470/*
2471 * ":argadd"
2472 */
2473 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002474ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002475{
2476 do_arglist(eap->arg, AL_ADD,
2477 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2478#ifdef FEAT_TITLE
2479 maketitle();
2480#endif
2481}
2482
2483/*
2484 * ":argdelete"
2485 */
2486 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002487ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488{
2489 int i;
2490 int n;
2491
2492 if (eap->addr_count > 0)
2493 {
2494 /* ":1,4argdel": Delete all arguments in the range. */
2495 if (eap->line2 > ARGCOUNT)
2496 eap->line2 = ARGCOUNT;
2497 n = eap->line2 - eap->line1 + 1;
2498 if (*eap->arg != NUL || n <= 0)
2499 EMSG(_(e_invarg));
2500 else
2501 {
2502 for (i = eap->line1; i <= eap->line2; ++i)
2503 vim_free(ARGLIST[i - 1].ae_fname);
2504 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2505 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2506 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507 if (curwin->w_arg_idx >= eap->line2)
2508 curwin->w_arg_idx -= n;
2509 else if (curwin->w_arg_idx > eap->line1)
2510 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002511 if (ARGCOUNT == 0)
2512 curwin->w_arg_idx = 0;
2513 else if (curwin->w_arg_idx >= ARGCOUNT)
2514 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515 }
2516 }
2517 else if (*eap->arg == NUL)
2518 EMSG(_(e_argreq));
2519 else
2520 do_arglist(eap->arg, AL_DEL, 0);
2521#ifdef FEAT_TITLE
2522 maketitle();
2523#endif
2524}
2525
2526/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002527 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002528 */
2529 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002530ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531{
2532 int i;
2533#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002534 win_T *wp;
2535 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002537 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538 int next_fnum = 0;
2539#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2540 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002542 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002543#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002544 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002545 int qf_idx;
2546#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002547
2548#ifndef FEAT_WINDOWS
2549 if (eap->cmdidx == CMD_windo)
2550 {
2551 ex_ni(eap);
2552 return;
2553 }
2554#endif
2555
2556#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002557 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002558 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2559 * great speed improvement. */
2560 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002561#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002562#ifdef FEAT_CLIPBOARD
2563 start_global_changes();
2564#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565
2566 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002567 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002569 || !check_changed(curbuf, CCGD_AW
2570 | (eap->forceit ? CCGD_FORCEIT : 0)
2571 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002574 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002575#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002576 wp = firstwin;
2577 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002579 switch (eap->cmdidx)
2580 {
2581#ifdef FEAT_WINDOWS
2582 case CMD_windo:
2583 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2584 i++;
2585 break;
2586 case CMD_tabdo:
2587 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2588 i++;
2589 break;
2590#endif
2591 case CMD_argdo:
2592 i = eap->line1 - 1;
2593 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002594 default:
2595 break;
2596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597 /* set pcmark now */
2598 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002599 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002600 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002601 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002602 || !buf->b_p_bl); buf = buf->b_next)
2603 if (buf->b_fnum > eap->line2)
2604 {
2605 buf = NULL;
2606 break;
2607 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002608 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002609 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002610 }
2611#ifdef FEAT_QUICKFIX
2612 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2613 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2614 {
2615 qf_size = qf_get_size(eap);
2616 if (qf_size <= 0 || eap->line1 > qf_size)
2617 buf = NULL;
2618 else
2619 {
2620 ex_cc(eap);
2621
2622 buf = curbuf;
2623 i = eap->line1 - 1;
2624 if (eap->addr_count <= 0)
2625 /* default is all the quickfix/location list entries */
2626 eap->line2 = qf_size;
2627 }
2628 }
2629#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630 else
2631 setpcmark();
2632 listcmd_busy = TRUE; /* avoids setting pcmark below */
2633
Bram Moolenaare25bb902015-02-27 20:33:37 +01002634 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002635 {
2636 if (eap->cmdidx == CMD_argdo)
2637 {
2638 /* go to argument "i" */
2639 if (i == ARGCOUNT)
2640 break;
2641 /* Don't call do_argfile() when already there, it will try
2642 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002643 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002644 {
2645 /* Clear 'shm' to avoid that the file message overwrites
2646 * any output from the command. */
2647 p_shm_save = vim_strsave(p_shm);
2648 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002650 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2651 vim_free(p_shm_save);
2652 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653 if (curwin->w_arg_idx != i)
2654 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002655 }
2656#ifdef FEAT_WINDOWS
2657 else if (eap->cmdidx == CMD_windo)
2658 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002659 /* go to window "wp" */
2660 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002662 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002663 if (curwin != wp)
2664 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002665 wp = curwin->w_next;
2666 }
2667 else if (eap->cmdidx == CMD_tabdo)
2668 {
2669 /* go to window "tp" */
2670 if (!valid_tabpage(tp))
2671 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002672 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002673 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674 }
2675#endif
2676 else if (eap->cmdidx == CMD_bufdo)
2677 {
2678 /* Remember the number of the next listed buffer, in case
2679 * ":bwipe" is used or autocommands do something strange. */
2680 next_fnum = -1;
2681 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2682 if (buf->b_p_bl)
2683 {
2684 next_fnum = buf->b_fnum;
2685 break;
2686 }
2687 }
2688
Bram Moolenaara162bc52015-01-07 16:54:21 +01002689 ++i;
2690
Bram Moolenaar071d4272004-06-13 20:20:40 +00002691 /* execute the command */
2692 do_cmdline(eap->arg, eap->getline, eap->cookie,
2693 DOCMD_VERBOSE + DOCMD_NOWAIT);
2694
2695 if (eap->cmdidx == CMD_bufdo)
2696 {
2697 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002698 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002699 break;
2700 /* Check if the buffer still exists. */
2701 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2702 if (buf->b_fnum == next_fnum)
2703 break;
2704 if (buf == NULL)
2705 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002706
2707 /* Go to the next buffer. Clear 'shm' to avoid that the file
2708 * message overwrites any output from the command. */
2709 p_shm_save = vim_strsave(p_shm);
2710 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002712 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2713 vim_free(p_shm_save);
2714
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002715 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716 if (curbuf->b_fnum != next_fnum)
2717 break;
2718 }
2719
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002720#ifdef FEAT_QUICKFIX
2721 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2722 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2723 {
2724 if (i >= qf_size || i >= eap->line2)
2725 break;
2726
2727 qf_idx = qf_get_cur_idx(eap);
2728
2729 ex_cnext(eap);
2730
2731 /* If jumping to the next quickfix entry fails, quit here */
2732 if (qf_get_cur_idx(eap) == qf_idx)
2733 break;
2734 }
2735#endif
2736
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 if (eap->cmdidx == CMD_windo)
2738 {
2739 validate_cursor(); /* cursor may have moved */
2740#ifdef FEAT_SCROLLBIND
2741 /* required when 'scrollbind' has been set */
2742 if (curwin->w_p_scb)
2743 do_check_scrollbind(TRUE);
2744#endif
2745 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002746
2747#ifdef FEAT_WINDOWS
2748 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2749 if (i+1 > eap->line2)
2750 break;
2751#endif
2752 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2753 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754 }
2755 listcmd_busy = FALSE;
2756 }
2757
2758#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002759 if (save_ei != NULL)
2760 {
2761 au_event_restore(save_ei);
2762 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2763 curbuf->b_fname, TRUE, curbuf);
2764 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002765#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002766#ifdef FEAT_CLIPBOARD
2767 end_global_changes();
2768#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769}
2770
2771/*
2772 * Add files[count] to the arglist of the current window after arg "after".
2773 * The file names in files[count] must have been allocated and are taken over.
2774 * Files[] itself is not taken over.
2775 * Returns index of first added argument. Returns -1 when failed (out of mem).
2776 */
2777 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002778alist_add_list(
2779 int count,
2780 char_u **files,
2781 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002782{
2783 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002784 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785
2786 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2787 {
2788 if (after < 0)
2789 after = 0;
2790 if (after > ARGCOUNT)
2791 after = ARGCOUNT;
2792 if (after < ARGCOUNT)
2793 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2794 (ARGCOUNT - after) * sizeof(aentry_T));
2795 for (i = 0; i < count; ++i)
2796 {
2797 ARGLIST[after + i].ae_fname = files[i];
2798 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2799 }
2800 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002801 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2802 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002803 return after;
2804 }
2805
2806 for (i = 0; i < count; ++i)
2807 vim_free(files[i]);
2808 return -1;
2809}
2810
2811#endif /* FEAT_LISTCMDS */
2812
2813#ifdef FEAT_EVAL
2814/*
2815 * ":compiler[!] {name}"
2816 */
2817 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002818ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819{
2820 char_u *buf;
2821 char_u *old_cur_comp = NULL;
2822 char_u *p;
2823
2824 if (*eap->arg == NUL)
2825 {
2826 /* List all compiler scripts. */
2827 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2828 /* ) keep the indenter happy... */
2829 }
2830 else
2831 {
2832 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2833 if (buf != NULL)
2834 {
2835 if (eap->forceit)
2836 {
2837 /* ":compiler! {name}" sets global options */
2838 do_cmdline_cmd((char_u *)
2839 "command -nargs=* CompilerSet set <args>");
2840 }
2841 else
2842 {
2843 /* ":compiler! {name}" sets local options.
2844 * To remain backwards compatible "current_compiler" is always
2845 * used. A user's compiler plugin may set it, the distributed
2846 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002847 * "b:current_compiler" and restore "current_compiler".
2848 * Explicitly prepend "g:" to make it work in a function. */
2849 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850 if (old_cur_comp != NULL)
2851 old_cur_comp = vim_strsave(old_cur_comp);
2852 do_cmdline_cmd((char_u *)
2853 "command -nargs=* CompilerSet setlocal <args>");
2854 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002855 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002856 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857
2858 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002859 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002860 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2861 vim_free(buf);
2862
2863 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2864
2865 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002866 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002867 if (p != NULL)
2868 set_internal_string_var((char_u *)"b:current_compiler", p);
2869
2870 /* Restore "current_compiler" for ":compiler {name}". */
2871 if (!eap->forceit)
2872 {
2873 if (old_cur_comp != NULL)
2874 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002875 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876 old_cur_comp);
2877 vim_free(old_cur_comp);
2878 }
2879 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002880 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881 }
2882 }
2883 }
2884}
2885#endif
2886
2887/*
2888 * ":runtime {name}"
2889 */
2890 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002891ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002893 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894}
2895
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002896static void source_callback(char_u *fname, void *cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897
2898 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002899source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002901 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902}
2903
2904/*
2905 * Source the file "name" from all directories in 'runtimepath'.
2906 * "name" can contain wildcards.
2907 * When "all" is TRUE, source all files, otherwise only the first one.
2908 * return FAIL when no file could be sourced, OK otherwise.
2909 */
2910 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002911source_runtime(char_u *name, int all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002913 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914}
2915
2916/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002917 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2918 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2920 * used.
2921 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002922 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002923 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2924 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002925 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926 */
2927 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002928do_in_runtimepath(
2929 char_u *name,
2930 int all,
2931 void (*callback)(char_u *fname, void *ck),
2932 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933{
2934 char_u *rtp;
2935 char_u *np;
2936 char_u *buf;
2937 char_u *rtp_copy;
2938 char_u *tail;
2939 int num_files;
2940 char_u **files;
2941 int i;
2942 int did_one = FALSE;
2943#ifdef AMIGA
2944 struct Process *proc = (struct Process *)FindTask(0L);
2945 APTR save_winptr = proc->pr_WindowPtr;
2946
2947 /* Avoid a requester here for a volume that doesn't exist. */
2948 proc->pr_WindowPtr = (APTR)-1L;
2949#endif
2950
2951 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2952 * value. */
2953 rtp_copy = vim_strsave(p_rtp);
2954 buf = alloc(MAXPATHL);
2955 if (buf != NULL && rtp_copy != NULL)
2956 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002957 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002958 {
2959 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002960 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002961 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002962 verbose_leave();
2963 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002964
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965 /* Loop over all entries in 'runtimepath'. */
2966 rtp = rtp_copy;
2967 while (*rtp != NUL && (all || !did_one))
2968 {
2969 /* Copy the path from 'runtimepath' to buf[]. */
2970 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002971 if (name == NULL)
2972 {
2973 (*callback)(buf, (void *) &cookie);
2974 if (!did_one)
2975 did_one = (cookie == NULL);
2976 }
2977 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002978 {
2979 add_pathsep(buf);
2980 tail = buf + STRLEN(buf);
2981
2982 /* Loop over all patterns in "name" */
2983 np = name;
2984 while (*np != NUL && (all || !did_one))
2985 {
2986 /* Append the pattern from "name" to buf[]. */
2987 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2988 "\t ");
2989
2990 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002991 {
2992 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002993 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002994 verbose_leave();
2995 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002996
2997 /* Expand wildcards, invoke the callback for each match. */
2998 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2999 EW_FILE) == OK)
3000 {
3001 for (i = 0; i < num_files; ++i)
3002 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003003 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 did_one = TRUE;
3005 if (!all)
3006 break;
3007 }
3008 FreeWild(num_files, files);
3009 }
3010 }
3011 }
3012 }
3013 }
3014 vim_free(buf);
3015 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003016 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003017 {
3018 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003019 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003020 verbose_leave();
3021 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022
3023#ifdef AMIGA
3024 proc->pr_WindowPtr = save_winptr;
3025#endif
3026
3027 return did_one ? OK : FAIL;
3028}
3029
3030#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3031/*
3032 * ":options"
3033 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003035ex_options(
3036 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037{
3038 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3039}
3040#endif
3041
3042/*
3043 * ":source {fname}"
3044 */
3045 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003046ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003047{
3048#ifdef FEAT_BROWSE
3049 if (cmdmod.browse)
3050 {
3051 char_u *fname = NULL;
3052
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003053 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003054 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3055 if (fname != NULL)
3056 {
3057 cmd_source(fname, eap);
3058 vim_free(fname);
3059 }
3060 }
3061 else
3062#endif
3063 cmd_source(eap->arg, eap);
3064}
3065
3066 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003067cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068{
3069 if (*fname == NUL)
3070 EMSG(_(e_argreq));
3071
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003073 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003074 * Need to execute the commands directly. This is required at least
3075 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 * - ":g" command busy
3077 * - after ":argdo", ":windo" or ":bufdo"
3078 * - another command follows
3079 * - inside a loop
3080 */
3081 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3082#ifdef FEAT_EVAL
3083 || eap->cstack->cs_idx >= 0
3084#endif
3085 );
3086
3087 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003088 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089 EMSG2(_(e_notopen), fname);
3090}
3091
3092/*
3093 * ":source" and associated commands.
3094 */
3095/*
3096 * Structure used to store info for each sourced file.
3097 * It is shared between do_source() and getsourceline().
3098 * This is required, because it needs to be handed to do_cmdline() and
3099 * sourcing can be done recursively.
3100 */
3101struct source_cookie
3102{
3103 FILE *fp; /* opened file for sourcing */
3104 char_u *nextline; /* if not NULL: line that was read ahead */
3105 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003106#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3108 int error; /* TRUE if LF found after CR-LF */
3109#endif
3110#ifdef FEAT_EVAL
3111 linenr_T breakpoint; /* next line with breakpoint or zero */
3112 char_u *fname; /* name of sourced file */
3113 int dbg_tick; /* debug_tick when breakpoint was set */
3114 int level; /* top nesting level of sourced file */
3115#endif
3116#ifdef FEAT_MBYTE
3117 vimconv_T conv; /* type of conversion */
3118#endif
3119};
3120
3121#ifdef FEAT_EVAL
3122/*
3123 * Return the address holding the next breakpoint line for a source cookie.
3124 */
3125 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003126source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003127{
3128 return &((struct source_cookie *)cookie)->breakpoint;
3129}
3130
3131/*
3132 * Return the address holding the debug tick for a source cookie.
3133 */
3134 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003135source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136{
3137 return &((struct source_cookie *)cookie)->dbg_tick;
3138}
3139
3140/*
3141 * Return the nesting level for a source cookie.
3142 */
3143 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003144source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145{
3146 return ((struct source_cookie *)cookie)->level;
3147}
3148#endif
3149
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003150static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003152#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3153# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003154static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003155
3156/*
3157 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003158 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159 */
3160 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003161fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003163# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003164 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3165# else
3166 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003167# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168
3169 if (fd_tmp == -1)
3170 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003171
3172# ifdef HAVE_FD_CLOEXEC
3173 {
3174 int fdflags = fcntl(fd_tmp, F_GETFD);
3175 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003176 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003177 }
3178# endif
3179
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180 return fdopen(fd_tmp, READBIN);
3181}
3182#endif
3183
3184
3185/*
3186 * do_source: Read the file "fname" and execute its lines as EX commands.
3187 *
3188 * This function may be called recursively!
3189 *
3190 * return FAIL if file could not be opened, OK otherwise
3191 */
3192 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003193do_source(
3194 char_u *fname,
3195 int check_other, /* check for .vimrc and _vimrc */
3196 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197{
3198 struct source_cookie cookie;
3199 char_u *save_sourcing_name;
3200 linenr_T save_sourcing_lnum;
3201 char_u *p;
3202 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003203 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204 int retval = FAIL;
3205#ifdef FEAT_EVAL
3206 scid_T save_current_SID;
3207 static scid_T last_current_SID = 0;
3208 void *save_funccalp;
3209 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003210 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211# ifdef UNIX
3212 struct stat st;
3213 int stat_ok;
3214# endif
3215#endif
3216#ifdef STARTUPTIME
3217 struct timeval tv_rel;
3218 struct timeval tv_start;
3219#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003220#ifdef FEAT_PROFILE
3221 proftime_T wait_start;
3222#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223
Bram Moolenaar071d4272004-06-13 20:20:40 +00003224 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 if (p == NULL)
3226 return retval;
3227 fname_exp = fix_fname(p);
3228 vim_free(p);
3229 if (fname_exp == NULL)
3230 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231 if (mch_isdir(fname_exp))
3232 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003233 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234 goto theend;
3235 }
3236
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003237#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003238 /* Apply SourceCmd autocommands, they should get the file and source it. */
3239 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3240 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3241 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003242 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003243# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003244 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003245# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003246 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003247# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003248 goto theend;
3249 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003250
3251 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003252 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3253#endif
3254
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003255#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3257#else
3258 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3259#endif
3260 if (cookie.fp == NULL && check_other)
3261 {
3262 /*
3263 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3264 * and ".exrc" by "_exrc" or vice versa.
3265 */
3266 p = gettail(fname_exp);
3267 if ((*p == '.' || *p == '_')
3268 && (STRICMP(p + 1, "vimrc") == 0
3269 || STRICMP(p + 1, "gvimrc") == 0
3270 || STRICMP(p + 1, "exrc") == 0))
3271 {
3272 if (*p == '_')
3273 *p = '.';
3274 else
3275 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003276#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003277 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3278#else
3279 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3280#endif
3281 }
3282 }
3283
3284 if (cookie.fp == NULL)
3285 {
3286 if (p_verbose > 0)
3287 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003288 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003290 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291 else
3292 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003293 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003294 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295 }
3296 goto theend;
3297 }
3298
3299 /*
3300 * The file exists.
3301 * - In verbose mode, give a message.
3302 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3303 */
3304 if (p_verbose > 1)
3305 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003306 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003308 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003309 else
3310 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003311 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003312 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003314 if (is_vimrc == DOSO_VIMRC)
3315 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3316 else if (is_vimrc == DOSO_GVIMRC)
3317 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318
3319#ifdef USE_CRNL
3320 /* If no automatic file format: Set default to CR-NL. */
3321 if (*p_ffs == NUL)
3322 cookie.fileformat = EOL_DOS;
3323 else
3324 cookie.fileformat = EOL_UNKNOWN;
3325 cookie.error = FALSE;
3326#endif
3327
3328#ifdef USE_CR
3329 /* If no automatic file format: Set default to CR. */
3330 if (*p_ffs == NUL)
3331 cookie.fileformat = EOL_MAC;
3332 else
3333 cookie.fileformat = EOL_UNKNOWN;
3334 cookie.error = FALSE;
3335#endif
3336
3337 cookie.nextline = NULL;
3338 cookie.finished = FALSE;
3339
3340#ifdef FEAT_EVAL
3341 /*
3342 * Check if this script has a breakpoint.
3343 */
3344 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3345 cookie.fname = fname_exp;
3346 cookie.dbg_tick = debug_tick;
3347
3348 cookie.level = ex_nesting_level;
3349#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003350
3351 /*
3352 * Keep the sourcing name/lnum, for recursive calls.
3353 */
3354 save_sourcing_name = sourcing_name;
3355 sourcing_name = fname_exp;
3356 save_sourcing_lnum = sourcing_lnum;
3357 sourcing_lnum = 0;
3358
Bram Moolenaar73881402009-02-04 16:50:47 +00003359#ifdef FEAT_MBYTE
3360 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3361
3362 /* Read the first line so we can check for a UTF-8 BOM. */
3363 firstline = getsourceline(0, (void *)&cookie, 0);
3364 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3365 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3366 {
3367 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3368 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3369 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003370 if (p == NULL)
3371 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003372 if (p != NULL)
3373 {
3374 vim_free(firstline);
3375 firstline = p;
3376 }
3377 }
3378#endif
3379
Bram Moolenaar071d4272004-06-13 20:20:40 +00003380#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003381 if (time_fd != NULL)
3382 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383#endif
3384
3385#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003386# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003387 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003388 prof_child_enter(&wait_start); /* entering a child now */
3389# endif
3390
3391 /* Don't use local function variables, if called from a function.
3392 * Also starts profiling timer for nested script. */
3393 save_funccalp = save_funccal();
3394
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395 /*
3396 * Check if this script was sourced before to finds its SID.
3397 * If it's new, generate a new SID.
3398 */
3399 save_current_SID = current_SID;
3400# ifdef UNIX
3401 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3402# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003403 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3404 {
3405 si = &SCRIPT_ITEM(current_SID);
3406 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003407 && (
3408# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003409 /* Compare dev/ino when possible, it catches symbolic
3410 * links. Also compare file names, the inode may change
3411 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003412 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003413 && (si->sn_dev == st.st_dev
3414 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003415# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003416 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003417 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003418 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003419 if (current_SID == 0)
3420 {
3421 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003422 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3423 == FAIL)
3424 goto almosttheend;
3425 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003426 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003427 ++script_items.ga_len;
3428 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3429# ifdef FEAT_PROFILE
3430 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003431# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003432 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003433 si = &SCRIPT_ITEM(current_SID);
3434 si->sn_name = fname_exp;
3435 fname_exp = NULL;
3436# ifdef UNIX
3437 if (stat_ok)
3438 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003439 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003440 si->sn_dev = st.st_dev;
3441 si->sn_ino = st.st_ino;
3442 }
3443 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003444 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003445# endif
3446
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447 /* Allocate the local script variables to use for this script. */
3448 new_script_vars(current_SID);
3449 }
3450
Bram Moolenaar05159a02005-02-26 23:04:13 +00003451# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003452 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003453 {
3454 int forceit;
3455
3456 /* Check if we do profiling for this script. */
3457 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3458 {
3459 script_do_profile(si);
3460 si->sn_pr_force = forceit;
3461 }
3462 if (si->sn_prof_on)
3463 {
3464 ++si->sn_pr_count;
3465 profile_start(&si->sn_pr_start);
3466 profile_zero(&si->sn_pr_children);
3467 }
3468 }
3469# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470#endif
3471
3472 /*
3473 * Call do_cmdline, which will call getsourceline() to get the lines.
3474 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003475 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003477 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003478
3479#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003480 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003481 {
3482 /* Get "si" again, "script_items" may have been reallocated. */
3483 si = &SCRIPT_ITEM(current_SID);
3484 if (si->sn_prof_on)
3485 {
3486 profile_end(&si->sn_pr_start);
3487 profile_sub_wait(&wait_start, &si->sn_pr_start);
3488 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003489 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3490 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003491 }
3492 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493#endif
3494
3495 if (got_int)
3496 EMSG(_(e_interr));
3497 sourcing_name = save_sourcing_name;
3498 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003499 if (p_verbose > 1)
3500 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003501 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003502 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003503 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003504 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003505 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003506 }
3507#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003508 if (time_fd != NULL)
3509 {
3510 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3511 time_msg((char *)IObuff, &tv_start);
3512 time_pop(&tv_rel);
3513 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514#endif
3515
3516#ifdef FEAT_EVAL
3517 /*
3518 * After a "finish" in debug mode, need to break at first command of next
3519 * sourced file.
3520 */
3521 if (save_debug_break_level > ex_nesting_level
3522 && debug_break_level == ex_nesting_level)
3523 ++debug_break_level;
3524#endif
3525
Bram Moolenaar05159a02005-02-26 23:04:13 +00003526#ifdef FEAT_EVAL
3527almosttheend:
3528 current_SID = save_current_SID;
3529 restore_funccal(save_funccalp);
3530# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003531 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003532 prof_child_exit(&wait_start); /* leaving a child now */
3533# endif
3534#endif
3535 fclose(cookie.fp);
3536 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003537 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003538#ifdef FEAT_MBYTE
3539 convert_setup(&cookie.conv, NULL, NULL);
3540#endif
3541
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542theend:
3543 vim_free(fname_exp);
3544 return retval;
3545}
3546
3547#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003548
Bram Moolenaar071d4272004-06-13 20:20:40 +00003549/*
3550 * ":scriptnames"
3551 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003553ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554{
3555 int i;
3556
Bram Moolenaar05159a02005-02-26 23:04:13 +00003557 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3558 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003559 {
3560 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3561 NameBuff, MAXPATHL, TRUE);
3562 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003563 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003564}
3565
3566# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3567/*
3568 * Fix slashes in the list of script names for 'shellslash'.
3569 */
3570 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003571scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003572{
3573 int i;
3574
Bram Moolenaar05159a02005-02-26 23:04:13 +00003575 for (i = 1; i <= script_items.ga_len; ++i)
3576 if (SCRIPT_ITEM(i).sn_name != NULL)
3577 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578}
3579# endif
3580
3581/*
3582 * Get a pointer to a script name. Used for ":verbose set".
3583 */
3584 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003585get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586{
3587 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003588 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003589 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003590 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003591 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003592 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003594 return (char_u *)_("environment variable");
3595 if (id == SID_ERROR)
3596 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003597 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003599
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003600# if defined(EXITFREE) || defined(PROTO)
3601 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003602free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003603{
3604 int i;
3605
3606 for (i = script_items.ga_len; i > 0; --i)
3607 vim_free(SCRIPT_ITEM(i).sn_name);
3608 ga_clear(&script_items);
3609}
3610# endif
3611
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612#endif
3613
3614#if defined(USE_CR) || defined(PROTO)
3615
3616# if defined(__MSL__) && (__MSL__ >= 22)
3617/*
3618 * Newer version of the Metrowerks library handle DOS and UNIX files
3619 * without help.
3620 * Test with earlier versions, MSL 2.2 is the library supplied with
3621 * Codewarrior Pro 2.
3622 */
3623 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003624fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003625{
3626 return fgets(s, n, stream);
3627}
3628# else
3629/*
3630 * Version of fgets() which also works for lines ending in a <CR> only
3631 * (Macintosh format).
3632 * For older versions of the Metrowerks library.
3633 * At least CodeWarrior 9 needed this code.
3634 */
3635 char *
3636fgets_cr(s, n, stream)
3637 char *s;
3638 int n;
3639 FILE *stream;
3640{
3641 int c = 0;
3642 int char_read = 0;
3643
3644 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3645 {
3646 c = fgetc(stream);
3647 s[char_read++] = c;
3648 /* If the file is in DOS format, we need to skip a NL after a CR. I
3649 * thought it was the other way around, but this appears to work... */
3650 if (c == '\n')
3651 {
3652 c = fgetc(stream);
3653 if (c != '\r')
3654 ungetc(c, stream);
3655 }
3656 }
3657
3658 s[char_read] = 0;
3659 if (char_read == 0)
3660 return NULL;
3661
3662 if (feof(stream) && char_read == 1)
3663 return NULL;
3664
3665 return s;
3666}
3667# endif
3668#endif
3669
3670/*
3671 * Get one full line from a sourced file.
3672 * Called by do_cmdline() when it's called from do_source().
3673 *
3674 * Return a pointer to the line in allocated memory.
3675 * Return NULL for end-of-file or some error.
3676 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003678getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003679{
3680 struct source_cookie *sp = (struct source_cookie *)cookie;
3681 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003682 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683
3684#ifdef FEAT_EVAL
3685 /* If breakpoints have been added/deleted need to check for it. */
3686 if (sp->dbg_tick < debug_tick)
3687 {
3688 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3689 sp->dbg_tick = debug_tick;
3690 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003691# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003692 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003693 script_line_end();
3694# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003695#endif
3696 /*
3697 * Get current line. If there is a read-ahead line, use it, otherwise get
3698 * one now.
3699 */
3700 if (sp->finished)
3701 line = NULL;
3702 else if (sp->nextline == NULL)
3703 line = get_one_sourceline(sp);
3704 else
3705 {
3706 line = sp->nextline;
3707 sp->nextline = NULL;
3708 ++sourcing_lnum;
3709 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003710#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003711 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003712 script_line_start();
3713#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714
3715 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3716 * contain the 'C' flag. */
3717 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3718 {
3719 /* compensate for the one line read-ahead */
3720 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003721
3722 /* Get the next line and concatenate it when it starts with a
3723 * backslash. We always need to read the next line, keep it in
3724 * sp->nextline. */
3725 sp->nextline = get_one_sourceline(sp);
3726 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003727 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003728 garray_T ga;
3729
Bram Moolenaarb549a732012-02-22 18:29:33 +01003730 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003731 ga_concat(&ga, line);
3732 ga_concat(&ga, p + 1);
3733 for (;;)
3734 {
3735 vim_free(sp->nextline);
3736 sp->nextline = get_one_sourceline(sp);
3737 if (sp->nextline == NULL)
3738 break;
3739 p = skipwhite(sp->nextline);
3740 if (*p != '\\')
3741 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003742 /* Adjust the growsize to the current length to speed up
3743 * concatenating many lines. */
3744 if (ga.ga_len > 400)
3745 {
3746 if (ga.ga_len > 8000)
3747 ga.ga_growsize = 8000;
3748 else
3749 ga.ga_growsize = ga.ga_len;
3750 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003751 ga_concat(&ga, p + 1);
3752 }
3753 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003755 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003756 }
3757 }
3758
3759#ifdef FEAT_MBYTE
3760 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3761 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003762 char_u *s;
3763
Bram Moolenaar071d4272004-06-13 20:20:40 +00003764 /* Convert the encoding of the script line. */
3765 s = string_convert(&sp->conv, line, NULL);
3766 if (s != NULL)
3767 {
3768 vim_free(line);
3769 line = s;
3770 }
3771 }
3772#endif
3773
3774#ifdef FEAT_EVAL
3775 /* Did we encounter a breakpoint? */
3776 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3777 {
3778 dbg_breakpoint(sp->fname, sourcing_lnum);
3779 /* Find next breakpoint. */
3780 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3781 sp->dbg_tick = debug_tick;
3782 }
3783#endif
3784
3785 return line;
3786}
3787
3788 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003789get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790{
3791 garray_T ga;
3792 int len;
3793 int c;
3794 char_u *buf;
3795#ifdef USE_CRNL
3796 int has_cr; /* CR-LF found */
3797#endif
3798#ifdef USE_CR
3799 char_u *scan;
3800#endif
3801 int have_read = FALSE;
3802
3803 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003804 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003805
3806 /*
3807 * Loop until there is a finished line (or end-of-file).
3808 */
3809 sourcing_lnum++;
3810 for (;;)
3811 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003812 /* make room to read at least 120 (more) characters */
3813 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814 break;
3815 buf = (char_u *)ga.ga_data;
3816
3817#ifdef USE_CR
3818 if (sp->fileformat == EOL_MAC)
3819 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003820 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3821 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822 break;
3823 }
3824 else
3825#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003826 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3827 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003828 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003829 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830#ifdef USE_CRNL
3831 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3832 * CTRL-Z by its own, or after a NL. */
3833 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3834 && sp->fileformat == EOL_DOS
3835 && buf[len - 1] == Ctrl_Z)
3836 {
3837 buf[len - 1] = NUL;
3838 break;
3839 }
3840#endif
3841
3842#ifdef USE_CR
3843 /* If the read doesn't stop on a new line, and there's
3844 * some CR then we assume a Mac format */
3845 if (sp->fileformat == EOL_UNKNOWN)
3846 {
3847 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3848 sp->fileformat = EOL_MAC;
3849 else
3850 sp->fileformat = EOL_UNIX;
3851 }
3852
3853 if (sp->fileformat == EOL_MAC)
3854 {
3855 scan = vim_strchr(buf, '\r');
3856
3857 if (scan != NULL)
3858 {
3859 *scan = '\n';
3860 if (*(scan + 1) != 0)
3861 {
3862 *(scan + 1) = 0;
3863 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3864 }
3865 }
3866 len = STRLEN(buf);
3867 }
3868#endif
3869
3870 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003871 ga.ga_len = len;
3872
3873 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003874 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003875 continue;
3876
3877 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3878 {
3879#ifdef USE_CRNL
3880 has_cr = (len >= 2 && buf[len - 2] == '\r');
3881 if (sp->fileformat == EOL_UNKNOWN)
3882 {
3883 if (has_cr)
3884 sp->fileformat = EOL_DOS;
3885 else
3886 sp->fileformat = EOL_UNIX;
3887 }
3888
3889 if (sp->fileformat == EOL_DOS)
3890 {
3891 if (has_cr) /* replace trailing CR */
3892 {
3893 buf[len - 2] = '\n';
3894 --len;
3895 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896 }
3897 else /* lines like ":map xx yy^M" will have failed */
3898 {
3899 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003900 {
3901 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003902 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003903 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003904 sp->error = TRUE;
3905 sp->fileformat = EOL_UNIX;
3906 }
3907 }
3908#endif
3909 /* The '\n' is escaped if there is an odd number of ^V's just
3910 * before it, first set "c" just before the 'V's and then check
3911 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3912 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3913 ;
3914 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3915 {
3916 sourcing_lnum++;
3917 continue;
3918 }
3919
3920 buf[len - 1] = NUL; /* remove the NL */
3921 }
3922
3923 /*
3924 * Check for ^C here now and then, so recursive :so can be broken.
3925 */
3926 line_breakcheck();
3927 break;
3928 }
3929
3930 if (have_read)
3931 return (char_u *)ga.ga_data;
3932
3933 vim_free(ga.ga_data);
3934 return NULL;
3935}
3936
Bram Moolenaar05159a02005-02-26 23:04:13 +00003937#if defined(FEAT_PROFILE) || defined(PROTO)
3938/*
3939 * Called when starting to read a script line.
3940 * "sourcing_lnum" must be correct!
3941 * When skipping lines it may not actually be executed, but we won't find out
3942 * until later and we need to store the time now.
3943 */
3944 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003945script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003946{
3947 scriptitem_T *si;
3948 sn_prl_T *pp;
3949
3950 if (current_SID <= 0 || current_SID > script_items.ga_len)
3951 return;
3952 si = &SCRIPT_ITEM(current_SID);
3953 if (si->sn_prof_on && sourcing_lnum >= 1)
3954 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003955 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003956 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02003957 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00003958 si->sn_prl_idx = sourcing_lnum - 1;
3959 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3960 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3961 {
3962 /* Zero counters for a line that was not used before. */
3963 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3964 pp->snp_count = 0;
3965 profile_zero(&pp->sn_prl_total);
3966 profile_zero(&pp->sn_prl_self);
3967 ++si->sn_prl_ga.ga_len;
3968 }
3969 si->sn_prl_execed = FALSE;
3970 profile_start(&si->sn_prl_start);
3971 profile_zero(&si->sn_prl_children);
3972 profile_get_wait(&si->sn_prl_wait);
3973 }
3974}
3975
3976/*
3977 * Called when actually executing a function line.
3978 */
3979 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003980script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003981{
3982 scriptitem_T *si;
3983
3984 if (current_SID <= 0 || current_SID > script_items.ga_len)
3985 return;
3986 si = &SCRIPT_ITEM(current_SID);
3987 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3988 si->sn_prl_execed = TRUE;
3989}
3990
3991/*
3992 * Called when done with a function line.
3993 */
3994 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003995script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003996{
3997 scriptitem_T *si;
3998 sn_prl_T *pp;
3999
4000 if (current_SID <= 0 || current_SID > script_items.ga_len)
4001 return;
4002 si = &SCRIPT_ITEM(current_SID);
4003 if (si->sn_prof_on && si->sn_prl_idx >= 0
4004 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4005 {
4006 if (si->sn_prl_execed)
4007 {
4008 pp = &PRL_ITEM(si, si->sn_prl_idx);
4009 ++pp->snp_count;
4010 profile_end(&si->sn_prl_start);
4011 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004012 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004013 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4014 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004015 }
4016 si->sn_prl_idx = -1;
4017 }
4018}
4019#endif
4020
Bram Moolenaar071d4272004-06-13 20:20:40 +00004021/*
4022 * ":scriptencoding": Set encoding conversion for a sourced script.
4023 * Without the multi-byte feature it's simply ignored.
4024 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004025 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004026ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027{
4028#ifdef FEAT_MBYTE
4029 struct source_cookie *sp;
4030 char_u *name;
4031
4032 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4033 {
4034 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4035 return;
4036 }
4037
4038 if (*eap->arg != NUL)
4039 {
4040 name = enc_canonize(eap->arg);
4041 if (name == NULL) /* out of memory */
4042 return;
4043 }
4044 else
4045 name = eap->arg;
4046
4047 /* Setup for conversion from the specified encoding to 'encoding'. */
4048 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4049 convert_setup(&sp->conv, name, p_enc);
4050
4051 if (name != eap->arg)
4052 vim_free(name);
4053#endif
4054}
4055
4056#if defined(FEAT_EVAL) || defined(PROTO)
4057/*
4058 * ":finish": Mark a sourced file as finished.
4059 */
4060 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004061ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004062{
4063 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4064 do_finish(eap, FALSE);
4065 else
4066 EMSG(_("E168: :finish used outside of a sourced file"));
4067}
4068
4069/*
4070 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4071 * Also called for a pending finish at the ":endtry" or after returning from
4072 * an extra do_cmdline(). "reanimate" is used in the latter case.
4073 */
4074 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004075do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004076{
4077 int idx;
4078
4079 if (reanimate)
4080 ((struct source_cookie *)getline_cookie(eap->getline,
4081 eap->cookie))->finished = FALSE;
4082
4083 /*
4084 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4085 * not in its finally clause (which then is to be executed next) is found.
4086 * In this case, make the ":finish" pending for execution at the ":endtry".
4087 * Otherwise, finish normally.
4088 */
4089 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4090 if (idx >= 0)
4091 {
4092 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4093 report_make_pending(CSTP_FINISH, NULL);
4094 }
4095 else
4096 ((struct source_cookie *)getline_cookie(eap->getline,
4097 eap->cookie))->finished = TRUE;
4098}
4099
4100
4101/*
4102 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4103 * message for missing ":endif".
4104 * Return FALSE when not sourcing a file.
4105 */
4106 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004107source_finished(
4108 char_u *(*fgetline)(int, void *, int),
4109 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004111 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004113 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114}
4115#endif
4116
4117#if defined(FEAT_LISTCMDS) || defined(PROTO)
4118/*
4119 * ":checktime [buffer]"
4120 */
4121 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004122ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123{
4124 buf_T *buf;
4125 int save_no_check_timestamps = no_check_timestamps;
4126
4127 no_check_timestamps = 0;
4128 if (eap->addr_count == 0) /* default is all buffers */
4129 check_timestamps(FALSE);
4130 else
4131 {
4132 buf = buflist_findnr((int)eap->line2);
4133 if (buf != NULL) /* cannot happen? */
4134 (void)buf_check_timestamp(buf, FALSE);
4135 }
4136 no_check_timestamps = save_no_check_timestamps;
4137}
4138#endif
4139
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4141 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004142# define HAVE_GET_LOCALE_VAL
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004143static char *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004144
4145 static char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004146get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004147{
4148 char *loc;
4149
4150 /* Obtain the locale value from the libraries. For DJGPP this is
4151 * redefined and it doesn't use the arguments. */
4152 loc = setlocale(what, NULL);
4153
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004154# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004155 if (loc != NULL)
4156 {
4157 char_u *p;
4158
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004159 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4160 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161 p = vim_strchr(loc, '=');
4162 if (p != NULL)
4163 {
4164 loc = ++p;
4165 while (*p != NUL) /* remove trailing newline */
4166 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004167 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168 {
4169 *p = NUL;
4170 break;
4171 }
4172 ++p;
4173 }
4174 }
4175 }
4176# endif
4177
4178 return loc;
4179}
4180#endif
4181
4182
4183#ifdef WIN32
4184/*
4185 * On MS-Windows locale names are strings like "German_Germany.1252", but
4186 * gettext expects "de". Try to translate one into another here for a few
4187 * supported languages.
4188 */
4189 static char_u *
4190gettext_lang(char_u *name)
4191{
4192 int i;
4193 static char *(mtable[]) = {
4194 "afrikaans", "af",
4195 "czech", "cs",
4196 "dutch", "nl",
4197 "german", "de",
4198 "english_united kingdom", "en_GB",
4199 "spanish", "es",
4200 "french", "fr",
4201 "italian", "it",
4202 "japanese", "ja",
4203 "korean", "ko",
4204 "norwegian", "no",
4205 "polish", "pl",
4206 "russian", "ru",
4207 "slovak", "sk",
4208 "swedish", "sv",
4209 "ukrainian", "uk",
4210 "chinese_china", "zh_CN",
4211 "chinese_taiwan", "zh_TW",
4212 NULL};
4213
4214 for (i = 0; mtable[i] != NULL; i += 2)
4215 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4216 return mtable[i + 1];
4217 return name;
4218}
4219#endif
4220
4221#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4222/*
4223 * Obtain the current messages language. Used to set the default for
4224 * 'helplang'. May return NULL or an empty string.
4225 */
4226 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004227get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228{
4229 char_u *p;
4230
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004231# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004232# if defined(LC_MESSAGES)
4233 p = (char_u *)get_locale_val(LC_MESSAGES);
4234# else
4235 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004236 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4237 * and LC_MONETARY may be set differently for a Japanese working in the
4238 * US. */
4239 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004240# endif
4241# else
4242 p = mch_getenv((char_u *)"LC_ALL");
4243 if (p == NULL || *p == NUL)
4244 {
4245 p = mch_getenv((char_u *)"LC_MESSAGES");
4246 if (p == NULL || *p == NUL)
4247 p = mch_getenv((char_u *)"LANG");
4248 }
4249# endif
4250# ifdef WIN32
4251 p = gettext_lang(p);
4252# endif
4253 return p;
4254}
4255#endif
4256
Bram Moolenaardef9e822004-12-31 20:58:58 +00004257/* Complicated #if; matches with where get_mess_env() is used below. */
4258#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4259 && defined(LC_MESSAGES))) \
4260 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4261 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4262 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004263static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004264
4265/*
4266 * Get the language used for messages from the environment.
4267 */
4268 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004269get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270{
4271 char_u *p;
4272
4273 p = mch_getenv((char_u *)"LC_ALL");
4274 if (p == NULL || *p == NUL)
4275 {
4276 p = mch_getenv((char_u *)"LC_MESSAGES");
4277 if (p == NULL || *p == NUL)
4278 {
4279 p = mch_getenv((char_u *)"LANG");
4280 if (p != NULL && VIM_ISDIGIT(*p))
4281 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004282# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004283 if (p == NULL || *p == NUL)
4284 p = (char_u *)get_locale_val(LC_CTYPE);
4285# endif
4286 }
4287 }
4288 return p;
4289}
4290#endif
4291
4292#if defined(FEAT_EVAL) || defined(PROTO)
4293
4294/*
4295 * Set the "v:lang" variable according to the current locale setting.
4296 * Also do "v:lc_time"and "v:ctype".
4297 */
4298 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004299set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004300{
4301 char_u *loc;
4302
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004303# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004304 loc = (char_u *)get_locale_val(LC_CTYPE);
4305# else
4306 /* setlocale() not supported: use the default value */
4307 loc = (char_u *)"C";
4308# endif
4309 set_vim_var_string(VV_CTYPE, loc, -1);
4310
4311 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4312 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004313# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314 loc = (char_u *)get_locale_val(LC_MESSAGES);
4315# else
4316 loc = get_mess_env();
4317# endif
4318 set_vim_var_string(VV_LANG, loc, -1);
4319
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004320# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 loc = (char_u *)get_locale_val(LC_TIME);
4322# endif
4323 set_vim_var_string(VV_LC_TIME, loc, -1);
4324}
4325#endif
4326
4327#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4328 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4329/*
4330 * ":language": Set the language (locale).
4331 */
4332 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004333ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334{
4335 char *loc;
4336 char_u *p;
4337 char_u *name;
4338 int what = LC_ALL;
4339 char *whatstr = "";
4340#ifdef LC_MESSAGES
4341# define VIM_LC_MESSAGES LC_MESSAGES
4342#else
4343# define VIM_LC_MESSAGES 6789
4344#endif
4345
4346 name = eap->arg;
4347
4348 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4349 * Allow abbreviation, but require at least 3 characters to avoid
4350 * confusion with a two letter language name "me" or "ct". */
4351 p = skiptowhite(eap->arg);
4352 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4353 {
4354 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4355 {
4356 what = VIM_LC_MESSAGES;
4357 name = skipwhite(p);
4358 whatstr = "messages ";
4359 }
4360 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4361 {
4362 what = LC_CTYPE;
4363 name = skipwhite(p);
4364 whatstr = "ctype ";
4365 }
4366 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4367 {
4368 what = LC_TIME;
4369 name = skipwhite(p);
4370 whatstr = "time ";
4371 }
4372 }
4373
4374 if (*name == NUL)
4375 {
4376#ifndef LC_MESSAGES
4377 if (what == VIM_LC_MESSAGES)
4378 p = get_mess_env();
4379 else
4380#endif
4381 p = (char_u *)setlocale(what, NULL);
4382 if (p == NULL || *p == NUL)
4383 p = (char_u *)"Unknown";
4384 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4385 }
4386 else
4387 {
4388#ifndef LC_MESSAGES
4389 if (what == VIM_LC_MESSAGES)
4390 loc = "";
4391 else
4392#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004393 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004395#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4396 /* Make sure strtod() uses a decimal point, not a comma. */
4397 setlocale(LC_NUMERIC, "C");
4398#endif
4399 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004400 if (loc == NULL)
4401 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4402 else
4403 {
4404#ifdef HAVE_NL_MSG_CAT_CNTR
4405 /* Need to do this for GNU gettext, otherwise cached translations
4406 * will be used again. */
4407 extern int _nl_msg_cat_cntr;
4408
4409 ++_nl_msg_cat_cntr;
4410#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004411 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004412 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4413
4414 if (what != LC_TIME)
4415 {
4416 /* Tell gettext() what to translate to. It apparently doesn't
4417 * use the currently effective locale. Also do this when
4418 * FEAT_GETTEXT isn't defined, so that shell commands use this
4419 * value. */
4420 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004421 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004423
4424 /* Clear $LANGUAGE because GNU gettext uses it. */
4425 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004426# ifdef WIN32
4427 /* Apparently MS-Windows printf() may cause a crash when
4428 * we give it 8-bit text while it's expecting text in the
4429 * current locale. This call avoids that. */
4430 setlocale(LC_CTYPE, "C");
4431# endif
4432 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 if (what != LC_CTYPE)
4434 {
4435 char_u *mname;
4436#ifdef WIN32
4437 mname = gettext_lang(name);
4438#else
4439 mname = name;
4440#endif
4441 vim_setenv((char_u *)"LC_MESSAGES", mname);
4442#ifdef FEAT_MULTI_LANG
4443 set_helplang_default(mname);
4444#endif
4445 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446 }
4447
4448# ifdef FEAT_EVAL
4449 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4450 set_lang_var();
4451# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004452# ifdef FEAT_TITLE
4453 maketitle();
4454# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455 }
4456 }
4457}
4458
4459# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004460
4461static char_u **locales = NULL; /* Array of all available locales */
4462static int did_init_locales = FALSE;
4463
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004464static void init_locales(void);
4465static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004466
4467/*
4468 * Lazy initialization of all available locales.
4469 */
4470 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004471init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004472{
4473 if (!did_init_locales)
4474 {
4475 did_init_locales = TRUE;
4476 locales = find_locales();
4477 }
4478}
4479
4480/* Return an array of strings for all available locales + NULL for the
4481 * last element. Return NULL in case of error. */
4482 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004483find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004484{
4485 garray_T locales_ga;
4486 char_u *loc;
4487
4488 /* Find all available locales by running command "locale -a". If this
4489 * doesn't work we won't have completion. */
4490 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004491 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004492 if (locale_a == NULL)
4493 return NULL;
4494 ga_init2(&locales_ga, sizeof(char_u *), 20);
4495
4496 /* Transform locale_a string where each locale is separated by "\n"
4497 * into an array of locale strings. */
4498 loc = (char_u *)strtok((char *)locale_a, "\n");
4499
4500 while (loc != NULL)
4501 {
4502 if (ga_grow(&locales_ga, 1) == FAIL)
4503 break;
4504 loc = vim_strsave(loc);
4505 if (loc == NULL)
4506 break;
4507
4508 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4509 loc = (char_u *)strtok(NULL, "\n");
4510 }
4511 vim_free(locale_a);
4512 if (ga_grow(&locales_ga, 1) == FAIL)
4513 {
4514 ga_clear(&locales_ga);
4515 return NULL;
4516 }
4517 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4518 return (char_u **)locales_ga.ga_data;
4519}
4520
4521# if defined(EXITFREE) || defined(PROTO)
4522 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004523free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004524{
4525 int i;
4526 if (locales != NULL)
4527 {
4528 for (i = 0; locales[i] != NULL; i++)
4529 vim_free(locales[i]);
4530 vim_free(locales);
4531 locales = NULL;
4532 }
4533}
4534# endif
4535
Bram Moolenaar071d4272004-06-13 20:20:40 +00004536/*
4537 * Function given to ExpandGeneric() to obtain the possible arguments of the
4538 * ":language" command.
4539 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004541get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004542{
4543 if (idx == 0)
4544 return (char_u *)"messages";
4545 if (idx == 1)
4546 return (char_u *)"ctype";
4547 if (idx == 2)
4548 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004549
4550 init_locales();
4551 if (locales == NULL)
4552 return NULL;
4553 return locales[idx - 3];
4554}
4555
4556/*
4557 * Function given to ExpandGeneric() to obtain the available locales.
4558 */
4559 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004560get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004561{
4562 init_locales();
4563 if (locales == NULL)
4564 return NULL;
4565 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566}
4567# endif
4568
4569#endif