blob: 2c9209662b1d3fbe9eba0d5edb10346723bb2bf3 [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
81do_debug(cmd)
82 char_u *cmd;
83{
84 int save_msg_scroll = msg_scroll;
85 int save_State = State;
86 int save_did_emsg = did_emsg;
87 int save_cmd_silent = cmd_silent;
88 int save_msg_silent = msg_silent;
89 int save_emsg_silent = emsg_silent;
90 int save_redir_off = redir_off;
91 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000092 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000093 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094# ifdef FEAT_EX_EXTRA
95 int save_ex_normal_busy;
96# endif
97 int n;
98 char_u *cmdline = NULL;
99 char_u *p;
100 char *tail = NULL;
101 static int last_cmd = 0;
102#define CMD_CONT 1
103#define CMD_NEXT 2
104#define CMD_STEP 3
105#define CMD_FINISH 4
106#define CMD_QUIT 5
107#define CMD_INTERRUPT 6
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100108#define CMD_BACKTRACE 7
109#define CMD_FRAME 8
110#define CMD_UP 9
111#define CMD_DOWN 10
Bram Moolenaar071d4272004-06-13 20:20:40 +0000112
113#ifdef ALWAYS_USE_GUI
114 /* Can't do this when there is no terminal for input/output. */
115 if (!gui.in_use)
116 {
117 /* Break as soon as possible. */
118 debug_break_level = 9999;
119 return;
120 }
121#endif
122
123 /* Make sure we are in raw mode and start termcap mode. Might have side
124 * effects... */
125 settmode(TMODE_RAW);
126 starttermcap();
127
128 ++RedrawingDisabled; /* don't redisplay the window */
129 ++no_wait_return; /* don't wait for return */
130 did_emsg = FALSE; /* don't use error from debugged stuff */
131 cmd_silent = FALSE; /* display commands */
132 msg_silent = FALSE; /* display messages */
133 emsg_silent = FALSE; /* display error messages */
134 redir_off = TRUE; /* don't redirect debug commands */
135
136 State = NORMAL;
137#ifdef FEAT_SNIFF
138 want_sniff_request = 0; /* No K_SNIFF wanted */
139#endif
140
141 if (!debug_did_msg)
142 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
143 if (sourcing_name != NULL)
144 msg(sourcing_name);
145 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000146 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000148 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149
150 /*
151 * Repeat getting a command and executing it.
152 */
153 for (;;)
154 {
155 msg_scroll = TRUE;
156 need_wait_return = FALSE;
157#ifdef FEAT_SNIFF
158 ProcessSniffRequests();
159#endif
160 /* Save the current typeahead buffer and replace it with an empty one.
161 * This makes sure we get input from the user here and don't interfere
162 * with the commands being executed. Reset "ex_normal_busy" to avoid
163 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000164 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165# ifdef FEAT_EX_EXTRA
166 save_ex_normal_busy = ex_normal_busy;
167 ex_normal_busy = 0;
168# endif
169 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000170 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000172 typeahead_saved = TRUE;
173 save_ignore_script = ignore_script;
174 ignore_script = TRUE;
175 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000177 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000178
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000179 if (typeahead_saved)
180 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000182 ignore_script = save_ignore_script;
183 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184# ifdef FEAT_EX_EXTRA
185 ex_normal_busy = save_ex_normal_busy;
186# endif
187
188 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100189 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190 if (cmdline != NULL)
191 {
192 /* If this is a debug command, set "last_cmd".
193 * If not, reset "last_cmd".
194 * For a blank line use previous command. */
195 p = skipwhite(cmdline);
196 if (*p != NUL)
197 {
198 switch (*p)
199 {
200 case 'c': last_cmd = CMD_CONT;
201 tail = "ont";
202 break;
203 case 'n': last_cmd = CMD_NEXT;
204 tail = "ext";
205 break;
206 case 's': last_cmd = CMD_STEP;
207 tail = "tep";
208 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100209 case 'f':
210 last_cmd = 0;
211 if (p[1] == 'r')
212 {
213 last_cmd = CMD_FRAME;
214 tail = "rame";
215 }
216 else
217 {
218 last_cmd = CMD_FINISH;
219 tail = "inish";
220 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000221 break;
222 case 'q': last_cmd = CMD_QUIT;
223 tail = "uit";
224 break;
225 case 'i': last_cmd = CMD_INTERRUPT;
226 tail = "nterrupt";
227 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100228 case 'b': last_cmd = CMD_BACKTRACE;
229 if (p[1] == 't')
230 tail = "t";
231 else
232 tail = "acktrace";
233 break;
234 case 'w': last_cmd = CMD_BACKTRACE;
235 tail = "here";
236 break;
237 case 'u': last_cmd = CMD_UP;
238 tail = "p";
239 break;
240 case 'd': last_cmd = CMD_DOWN;
241 tail = "own";
242 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000243 default: last_cmd = 0;
244 }
245 if (last_cmd != 0)
246 {
247 /* Check that the tail matches. */
248 ++p;
249 while (*p != NUL && *p == *tail)
250 {
251 ++p;
252 ++tail;
253 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100254 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255 last_cmd = 0;
256 }
257 }
258
259 if (last_cmd != 0)
260 {
261 /* Execute debug command: decided where to break next and
262 * return. */
263 switch (last_cmd)
264 {
265 case CMD_CONT:
266 debug_break_level = -1;
267 break;
268 case CMD_NEXT:
269 debug_break_level = ex_nesting_level;
270 break;
271 case CMD_STEP:
272 debug_break_level = 9999;
273 break;
274 case CMD_FINISH:
275 debug_break_level = ex_nesting_level - 1;
276 break;
277 case CMD_QUIT:
278 got_int = TRUE;
279 debug_break_level = -1;
280 break;
281 case CMD_INTERRUPT:
282 got_int = TRUE;
283 debug_break_level = 9999;
284 /* Do not repeat ">interrupt" cmd, continue stepping. */
285 last_cmd = CMD_STEP;
286 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100287 case CMD_BACKTRACE:
288 do_showbacktrace(cmd);
289 continue;
290 case CMD_FRAME:
291 if (*p == NUL)
292 {
293 do_showbacktrace(cmd);
294 }
295 else
296 {
297 p = skipwhite(p);
298 do_setdebugtracelevel(p);
299 }
300 continue;
301 case CMD_UP:
302 debug_backtrace_level++;
303 do_checkbacktracelevel();
304 continue;
305 case CMD_DOWN:
306 debug_backtrace_level--;
307 do_checkbacktracelevel();
308 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000309 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100310 /* Going out reset backtrace_level */
311 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000312 break;
313 }
314
315 /* don't debug this command */
316 n = debug_break_level;
317 debug_break_level = -1;
318 (void)do_cmdline(cmdline, getexline, NULL,
319 DOCMD_VERBOSE|DOCMD_EXCRESET);
320 debug_break_level = n;
321
322 vim_free(cmdline);
323 }
324 lines_left = Rows - 1;
325 }
326 vim_free(cmdline);
327
328 --RedrawingDisabled;
329 --no_wait_return;
330 redraw_all_later(NOT_VALID);
331 need_wait_return = FALSE;
332 msg_scroll = save_msg_scroll;
333 lines_left = Rows - 1;
334 State = save_State;
335 did_emsg = save_did_emsg;
336 cmd_silent = save_cmd_silent;
337 msg_silent = save_msg_silent;
338 emsg_silent = save_emsg_silent;
339 redir_off = save_redir_off;
340
341 /* Only print the message again when typing a command before coming back
342 * here. */
343 debug_did_msg = TRUE;
344}
345
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100346 static int
347get_maxbacktrace_level(void)
348{
349 char *p, *q;
350 int maxbacktrace = 1;
351
352 maxbacktrace = 0;
353 if (sourcing_name != NULL)
354 {
355 p = (char *)sourcing_name;
356 while ((q = strstr(p, "..")) != NULL)
357 {
358 p = q + 2;
359 maxbacktrace++;
360 }
361 }
362 return maxbacktrace;
363}
364
365 static void
366do_setdebugtracelevel(char_u *arg)
367{
368 int level;
369
370 level = atoi((char *)arg);
371 if (*arg == '+' || level < 0)
372 debug_backtrace_level += level;
373 else
374 debug_backtrace_level = level;
375
376 do_checkbacktracelevel();
377}
378
379 static void
380do_checkbacktracelevel(void)
381{
382 if (debug_backtrace_level < 0)
383 {
384 debug_backtrace_level = 0;
385 MSG(_("frame is zero"));
386 }
387 else
388 {
389 int max = get_maxbacktrace_level();
390
391 if (debug_backtrace_level > max)
392 {
393 debug_backtrace_level = max;
394 smsg((char_u *)_("frame at highest level: %d"), max);
395 }
396 }
397}
398
399 static void
400do_showbacktrace(char_u *cmd)
401{
402 char *cur;
403 char *next;
404 int i = 0;
405 int max = get_maxbacktrace_level();
406
407 if (sourcing_name != NULL)
408 {
409 cur = (char *)sourcing_name;
410 while (!got_int)
411 {
412 next = strstr(cur, "..");
413 if (next != NULL)
414 *next = NUL;
415 if (i == max - debug_backtrace_level)
416 smsg((char_u *)"->%d %s", max - i, cur);
417 else
418 smsg((char_u *)" %d %s", max - i, cur);
419 ++i;
420 if (next == NULL)
421 break;
422 *next = '.';
423 cur = next + 2;
424 }
425 }
426 if (sourcing_lnum != 0)
427 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
428 else
429 smsg((char_u *)_("cmd: %s"), cmd);
430}
431
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432/*
433 * ":debug".
434 */
435 void
436ex_debug(eap)
437 exarg_T *eap;
438{
439 int debug_break_level_save = debug_break_level;
440
441 debug_break_level = 9999;
442 do_cmdline_cmd(eap->arg);
443 debug_break_level = debug_break_level_save;
444}
445
446static char_u *debug_breakpoint_name = NULL;
447static linenr_T debug_breakpoint_lnum;
448
449/*
450 * When debugging or a breakpoint is set on a skipped command, no debug prompt
451 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
452 * debug_skipped_name is then set to the source name in the breakpoint case. If
453 * a skipped command decides itself that a debug prompt should be displayed, it
454 * can do so by calling dbg_check_skipped().
455 */
456static int debug_skipped;
457static char_u *debug_skipped_name;
458
459/*
460 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
461 * at or below the break level. But only when the line is actually
462 * executed. Return TRUE and set breakpoint_name for skipped commands that
463 * decide to execute something themselves.
464 * Called from do_one_cmd() before executing a command.
465 */
466 void
467dbg_check_breakpoint(eap)
468 exarg_T *eap;
469{
470 char_u *p;
471
472 debug_skipped = FALSE;
473 if (debug_breakpoint_name != NULL)
474 {
475 if (!eap->skip)
476 {
477 /* replace K_SNR with "<SNR>" */
478 if (debug_breakpoint_name[0] == K_SPECIAL
479 && debug_breakpoint_name[1] == KS_EXTRA
480 && debug_breakpoint_name[2] == (int)KE_SNR)
481 p = (char_u *)"<SNR>";
482 else
483 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000484 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
485 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000486 debug_breakpoint_name + (*p == NUL ? 0 : 3),
487 (long)debug_breakpoint_lnum);
488 debug_breakpoint_name = NULL;
489 do_debug(eap->cmd);
490 }
491 else
492 {
493 debug_skipped = TRUE;
494 debug_skipped_name = debug_breakpoint_name;
495 debug_breakpoint_name = NULL;
496 }
497 }
498 else if (ex_nesting_level <= debug_break_level)
499 {
500 if (!eap->skip)
501 do_debug(eap->cmd);
502 else
503 {
504 debug_skipped = TRUE;
505 debug_skipped_name = NULL;
506 }
507 }
508}
509
510/*
511 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
512 * set. Return TRUE when the debug mode is entered this time.
513 */
514 int
515dbg_check_skipped(eap)
516 exarg_T *eap;
517{
518 int prev_got_int;
519
520 if (debug_skipped)
521 {
522 /*
523 * Save the value of got_int and reset it. We don't want a previous
524 * interruption cause flushing the input buffer.
525 */
526 prev_got_int = got_int;
527 got_int = FALSE;
528 debug_breakpoint_name = debug_skipped_name;
529 /* eap->skip is TRUE */
530 eap->skip = FALSE;
531 (void)dbg_check_breakpoint(eap);
532 eap->skip = TRUE;
533 got_int |= prev_got_int;
534 return TRUE;
535 }
536 return FALSE;
537}
538
539/*
540 * The list of breakpoints: dbg_breakp.
541 * This is a grow-array of structs.
542 */
543struct debuggy
544{
545 int dbg_nr; /* breakpoint number */
546 int dbg_type; /* DBG_FUNC or DBG_FILE */
547 char_u *dbg_name; /* function or file name */
548 regprog_T *dbg_prog; /* regexp program */
549 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000550 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551};
552
553static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000554#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
555#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556static int last_breakp = 0; /* nr of last defined breakpoint */
557
Bram Moolenaar05159a02005-02-26 23:04:13 +0000558#ifdef FEAT_PROFILE
559/* Profiling uses file and func names similar to breakpoints. */
560static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
561#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000562#define DBG_FUNC 1
563#define DBG_FILE 2
564
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100565static int dbg_parsearg(char_u *arg, garray_T *gap);
566static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567
568/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000569 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
570 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
571 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572 * Returns FAIL for failure.
573 */
574 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000575dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000577 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578{
579 char_u *p = arg;
580 char_u *q;
581 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000582 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000583
Bram Moolenaar05159a02005-02-26 23:04:13 +0000584 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000586 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000587
588 /* Find "func" or "file". */
589 if (STRNCMP(p, "func", 4) == 0)
590 bp->dbg_type = DBG_FUNC;
591 else if (STRNCMP(p, "file", 4) == 0)
592 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000593 else if (
594#ifdef FEAT_PROFILE
595 gap != &prof_ga &&
596#endif
597 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000598 {
599 if (curbuf->b_ffname == NULL)
600 {
601 EMSG(_(e_noname));
602 return FAIL;
603 }
604 bp->dbg_type = DBG_FILE;
605 here = TRUE;
606 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607 else
608 {
609 EMSG2(_(e_invarg2), p);
610 return FAIL;
611 }
612 p = skipwhite(p + 4);
613
614 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000615 if (here)
616 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000617 else if (
618#ifdef FEAT_PROFILE
619 gap != &prof_ga &&
620#endif
621 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 {
623 bp->dbg_lnum = getdigits(&p);
624 p = skipwhite(p);
625 }
626 else
627 bp->dbg_lnum = 0;
628
629 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000630 if ((!here && *p == NUL)
631 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
633 {
634 EMSG2(_(e_invarg2), arg);
635 return FAIL;
636 }
637
638 if (bp->dbg_type == DBG_FUNC)
639 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000640 else if (here)
641 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000642 else
643 {
644 /* Expand the file name in the same way as do_source(). This means
645 * doing it twice, so that $DIR/file gets expanded when $DIR is
646 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000648 if (q == NULL)
649 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 vim_free(q);
652 if (p == NULL)
653 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000654 if (*p != '*')
655 {
656 bp->dbg_name = fix_fname(p);
657 vim_free(p);
658 }
659 else
660 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661 }
662
663 if (bp->dbg_name == NULL)
664 return FAIL;
665 return OK;
666}
667
668/*
669 * ":breakadd".
670 */
671 void
672ex_breakadd(eap)
673 exarg_T *eap;
674{
675 struct debuggy *bp;
676 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000677 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678
Bram Moolenaar05159a02005-02-26 23:04:13 +0000679 gap = &dbg_breakp;
680#ifdef FEAT_PROFILE
681 if (eap->cmdidx == CMD_profile)
682 gap = &prof_ga;
683#endif
684
685 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000686 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000687 bp = &DEBUGGY(gap, gap->ga_len);
688 bp->dbg_forceit = eap->forceit;
689
Bram Moolenaar071d4272004-06-13 20:20:40 +0000690 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
691 if (pat != NULL)
692 {
693 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
694 vim_free(pat);
695 }
696 if (pat == NULL || bp->dbg_prog == NULL)
697 vim_free(bp->dbg_name);
698 else
699 {
700 if (bp->dbg_lnum == 0) /* default line number is 1 */
701 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000702#ifdef FEAT_PROFILE
703 if (eap->cmdidx != CMD_profile)
704#endif
705 {
706 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
707 ++debug_tick;
708 }
709 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 }
711 }
712}
713
714/*
715 * ":debuggreedy".
716 */
717 void
718ex_debuggreedy(eap)
719 exarg_T *eap;
720{
721 if (eap->addr_count == 0 || eap->line2 != 0)
722 debug_greedy = TRUE;
723 else
724 debug_greedy = FALSE;
725}
726
727/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000728 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000729 */
730 void
731ex_breakdel(eap)
732 exarg_T *eap;
733{
734 struct debuggy *bp, *bpi;
735 int nr;
736 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000737 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738 int i;
739 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000740 garray_T *gap;
741
742 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000743 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200744 {
745#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000746 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200747#else
748 ex_ni(eap);
749 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000750#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200751 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752
753 if (vim_isdigit(*eap->arg))
754 {
755 /* ":breakdel {nr}" */
756 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000757 for (i = 0; i < gap->ga_len; ++i)
758 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 {
760 todel = i;
761 break;
762 }
763 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000764 else if (*eap->arg == '*')
765 {
766 todel = 0;
767 del_all = TRUE;
768 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 else
770 {
771 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000772 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000774 bp = &DEBUGGY(gap, gap->ga_len);
775 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000776 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000777 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778 if (bp->dbg_type == bpi->dbg_type
779 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
780 && (bp->dbg_lnum == bpi->dbg_lnum
781 || (bp->dbg_lnum == 0
782 && (best_lnum == 0
783 || bpi->dbg_lnum < best_lnum))))
784 {
785 todel = i;
786 best_lnum = bpi->dbg_lnum;
787 }
788 }
789 vim_free(bp->dbg_name);
790 }
791
792 if (todel < 0)
793 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
794 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000795 {
796 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000797 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000798 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200799 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000800 --gap->ga_len;
801 if (todel < gap->ga_len)
802 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
803 (gap->ga_len - todel) * sizeof(struct debuggy));
804#ifdef FEAT_PROFILE
805 if (eap->cmdidx == CMD_breakdel)
806#endif
807 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000808 if (!del_all)
809 break;
810 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000811
812 /* If all breakpoints were removed clear the array. */
813 if (gap->ga_len == 0)
814 ga_clear(gap);
815 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816}
817
818/*
819 * ":breaklist".
820 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 void
822ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000823 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000824{
825 struct debuggy *bp;
826 int i;
827
828 if (dbg_breakp.ga_len == 0)
829 MSG(_("No breakpoints defined"));
830 else
831 for (i = 0; i < dbg_breakp.ga_len; ++i)
832 {
833 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200834 if (bp->dbg_type == DBG_FILE)
835 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836 smsg((char_u *)_("%3d %s %s line %ld"),
837 bp->dbg_nr,
838 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200839 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000840 (long)bp->dbg_lnum);
841 }
842}
843
844/*
845 * Find a breakpoint for a function or sourced file.
846 * Returns line number at which to break; zero when no matching breakpoint.
847 */
848 linenr_T
849dbg_find_breakpoint(file, fname, after)
850 int file; /* TRUE for a file, FALSE for a function */
851 char_u *fname; /* file or function name */
852 linenr_T after; /* after this line number */
853{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000854 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
855}
856
857#if defined(FEAT_PROFILE) || defined(PROTO)
858/*
859 * Return TRUE if profiling is on for a function or sourced file.
860 */
861 int
862has_profiling(file, fname, fp)
863 int file; /* TRUE for a file, FALSE for a function */
864 char_u *fname; /* file or function name */
865 int *fp; /* return: forceit */
866{
867 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
868 != (linenr_T)0);
869}
870#endif
871
872/*
873 * Common code for dbg_find_breakpoint() and has_profiling().
874 */
875 static linenr_T
876debuggy_find(file, fname, after, gap, fp)
877 int file; /* TRUE for a file, FALSE for a function */
878 char_u *fname; /* file or function name */
879 linenr_T after; /* after this line number */
880 garray_T *gap; /* either &dbg_breakp or &prof_ga */
881 int *fp; /* if not NULL: return forceit */
882{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000883 struct debuggy *bp;
884 int i;
885 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 char_u *name = fname;
887 int prev_got_int;
888
Bram Moolenaar05159a02005-02-26 23:04:13 +0000889 /* Return quickly when there are no breakpoints. */
890 if (gap->ga_len == 0)
891 return (linenr_T)0;
892
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 /* Replace K_SNR in function name with "<SNR>". */
894 if (!file && fname[0] == K_SPECIAL)
895 {
896 name = alloc((unsigned)STRLEN(fname) + 3);
897 if (name == NULL)
898 name = fname;
899 else
900 {
901 STRCPY(name, "<SNR>");
902 STRCPY(name + 5, fname + 3);
903 }
904 }
905
Bram Moolenaar05159a02005-02-26 23:04:13 +0000906 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000908 /* Skip entries that are not useful or are for a line that is beyond
909 * an already found breakpoint. */
910 bp = &DEBUGGY(gap, i);
911 if (((bp->dbg_type == DBG_FILE) == file && (
912#ifdef FEAT_PROFILE
913 gap == &prof_ga ||
914#endif
915 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000918 * Save the value of got_int and reset it. We don't want a
919 * previous interruption cancel matching, only hitting CTRL-C
920 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000921 */
922 prev_got_int = got_int;
923 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100924 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000925 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000927 if (fp != NULL)
928 *fp = bp->dbg_forceit;
929 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930 got_int |= prev_got_int;
931 }
932 }
933 if (name != fname)
934 vim_free(name);
935
936 return lnum;
937}
938
939/*
940 * Called when a breakpoint was encountered.
941 */
942 void
943dbg_breakpoint(name, lnum)
944 char_u *name;
945 linenr_T lnum;
946{
947 /* We need to check if this line is actually executed in do_one_cmd() */
948 debug_breakpoint_name = name;
949 debug_breakpoint_lnum = lnum;
950}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000951
952
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000953# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000954/*
955 * Store the current time in "tm".
956 */
957 void
958profile_start(tm)
959 proftime_T *tm;
960{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000961# ifdef WIN3264
962 QueryPerformanceCounter(tm);
963# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000964 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000965# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000966}
967
968/*
969 * Compute the elapsed time from "tm" till now and store in "tm".
970 */
971 void
972profile_end(tm)
973 proftime_T *tm;
974{
975 proftime_T now;
976
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000977# ifdef WIN3264
978 QueryPerformanceCounter(&now);
979 tm->QuadPart = now.QuadPart - tm->QuadPart;
980# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000981 gettimeofday(&now, NULL);
982 tm->tv_usec = now.tv_usec - tm->tv_usec;
983 tm->tv_sec = now.tv_sec - tm->tv_sec;
984 if (tm->tv_usec < 0)
985 {
986 tm->tv_usec += 1000000;
987 --tm->tv_sec;
988 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000989# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000990}
991
992/*
993 * Subtract the time "tm2" from "tm".
994 */
995 void
996profile_sub(tm, tm2)
997 proftime_T *tm, *tm2;
998{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000999# ifdef WIN3264
1000 tm->QuadPart -= tm2->QuadPart;
1001# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001002 tm->tv_usec -= tm2->tv_usec;
1003 tm->tv_sec -= tm2->tv_sec;
1004 if (tm->tv_usec < 0)
1005 {
1006 tm->tv_usec += 1000000;
1007 --tm->tv_sec;
1008 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001009# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001010}
1011
1012/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001013 * Return a string that represents the time in "tm".
1014 * Uses a static buffer!
1015 */
1016 char *
1017profile_msg(tm)
1018 proftime_T *tm;
1019{
1020 static char buf[50];
1021
1022# ifdef WIN3264
1023 LARGE_INTEGER fr;
1024
1025 QueryPerformanceFrequency(&fr);
1026 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1027# else
1028 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001029# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001030 return buf;
1031}
1032
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001033/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001034 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001035 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001036 void
1037profile_setlimit(msec, tm)
1038 long msec;
1039 proftime_T *tm;
1040{
1041 if (msec <= 0) /* no limit */
1042 profile_zero(tm);
1043 else
1044 {
1045# ifdef WIN3264
1046 LARGE_INTEGER fr;
1047
1048 QueryPerformanceCounter(tm);
1049 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001050 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001051# else
1052 long usec;
1053
1054 gettimeofday(tm, NULL);
1055 usec = (long)tm->tv_usec + (long)msec * 1000;
1056 tm->tv_usec = usec % 1000000L;
1057 tm->tv_sec += usec / 1000000L;
1058# endif
1059 }
1060}
1061
1062/*
1063 * Return TRUE if the current time is past "tm".
1064 */
1065 int
1066profile_passed_limit(tm)
1067 proftime_T *tm;
1068{
1069 proftime_T now;
1070
1071# ifdef WIN3264
1072 if (tm->QuadPart == 0) /* timer was not set */
1073 return FALSE;
1074 QueryPerformanceCounter(&now);
1075 return (now.QuadPart > tm->QuadPart);
1076# else
1077 if (tm->tv_sec == 0) /* timer was not set */
1078 return FALSE;
1079 gettimeofday(&now, NULL);
1080 return (now.tv_sec > tm->tv_sec
1081 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1082# endif
1083}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001084
1085/*
1086 * Set the time in "tm" to zero.
1087 */
1088 void
1089profile_zero(tm)
1090 proftime_T *tm;
1091{
1092# ifdef WIN3264
1093 tm->QuadPart = 0;
1094# else
1095 tm->tv_usec = 0;
1096 tm->tv_sec = 0;
1097# endif
1098}
1099
Bram Moolenaar76929292008-01-06 19:07:36 +00001100# endif /* FEAT_PROFILE || FEAT_RELTIME */
1101
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001102#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1103# if defined(HAVE_MATH_H)
1104# include <math.h>
1105# endif
1106
1107/*
1108 * Divide the time "tm" by "count" and store in "tm2".
1109 */
1110 void
1111profile_divide(tm, count, tm2)
1112 proftime_T *tm;
1113 proftime_T *tm2;
1114 int count;
1115{
1116 if (count == 0)
1117 profile_zero(tm2);
1118 else
1119 {
1120# ifdef WIN3264
1121 tm2->QuadPart = tm->QuadPart / count;
1122# else
1123 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1124
1125 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001126 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001127# endif
1128 }
1129}
1130#endif
1131
Bram Moolenaar76929292008-01-06 19:07:36 +00001132# if defined(FEAT_PROFILE) || defined(PROTO)
1133/*
1134 * Functions for profiling.
1135 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001136static void script_do_profile(scriptitem_T *si);
1137static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001138static proftime_T prof_wait_time;
1139
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001140/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001141 * Add the time "tm2" to "tm".
1142 */
1143 void
1144profile_add(tm, tm2)
1145 proftime_T *tm, *tm2;
1146{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001147# ifdef WIN3264
1148 tm->QuadPart += tm2->QuadPart;
1149# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001150 tm->tv_usec += tm2->tv_usec;
1151 tm->tv_sec += tm2->tv_sec;
1152 if (tm->tv_usec >= 1000000)
1153 {
1154 tm->tv_usec -= 1000000;
1155 ++tm->tv_sec;
1156 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001157# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001158}
1159
1160/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001161 * Add the "self" time from the total time and the children's time.
1162 */
1163 void
1164profile_self(self, total, children)
1165 proftime_T *self, *total, *children;
1166{
1167 /* Check that the result won't be negative. Can happen with recursive
1168 * calls. */
1169#ifdef WIN3264
1170 if (total->QuadPart <= children->QuadPart)
1171 return;
1172#else
1173 if (total->tv_sec < children->tv_sec
1174 || (total->tv_sec == children->tv_sec
1175 && total->tv_usec <= children->tv_usec))
1176 return;
1177#endif
1178 profile_add(self, total);
1179 profile_sub(self, children);
1180}
1181
1182/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001183 * Get the current waittime.
1184 */
1185 void
1186profile_get_wait(tm)
1187 proftime_T *tm;
1188{
1189 *tm = prof_wait_time;
1190}
1191
1192/*
1193 * Subtract the passed waittime since "tm" from "tma".
1194 */
1195 void
1196profile_sub_wait(tm, tma)
1197 proftime_T *tm, *tma;
1198{
1199 proftime_T tm3 = prof_wait_time;
1200
1201 profile_sub(&tm3, tm);
1202 profile_sub(tma, &tm3);
1203}
1204
1205/*
1206 * Return TRUE if "tm1" and "tm2" are equal.
1207 */
1208 int
1209profile_equal(tm1, tm2)
1210 proftime_T *tm1, *tm2;
1211{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001212# ifdef WIN3264
1213 return (tm1->QuadPart == tm2->QuadPart);
1214# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001215 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001216# endif
1217}
1218
1219/*
1220 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1221 */
1222 int
1223profile_cmp(tm1, tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001224 const proftime_T *tm1, *tm2;
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001225{
1226# ifdef WIN3264
1227 return (int)(tm2->QuadPart - tm1->QuadPart);
1228# else
1229 if (tm1->tv_sec == tm2->tv_sec)
1230 return tm2->tv_usec - tm1->tv_usec;
1231 return tm2->tv_sec - tm1->tv_sec;
1232# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001233}
1234
Bram Moolenaar05159a02005-02-26 23:04:13 +00001235static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001236static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001237
1238/*
1239 * ":profile cmd args"
1240 */
1241 void
1242ex_profile(eap)
1243 exarg_T *eap;
1244{
1245 char_u *e;
1246 int len;
1247
1248 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001249 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001250 e = skipwhite(e);
1251
1252 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1253 {
1254 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001255 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001256 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001257 profile_zero(&prof_wait_time);
1258 set_vim_var_nr(VV_PROFILING, 1L);
1259 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001260 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001261 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001262 else if (STRCMP(eap->arg, "pause") == 0)
1263 {
1264 if (do_profiling == PROF_YES)
1265 profile_start(&pause_time);
1266 do_profiling = PROF_PAUSED;
1267 }
1268 else if (STRCMP(eap->arg, "continue") == 0)
1269 {
1270 if (do_profiling == PROF_PAUSED)
1271 {
1272 profile_end(&pause_time);
1273 profile_add(&prof_wait_time, &pause_time);
1274 }
1275 do_profiling = PROF_YES;
1276 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001277 else
1278 {
1279 /* The rest is similar to ":breakadd". */
1280 ex_breakadd(eap);
1281 }
1282}
1283
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001284/* Command line expansion for :profile. */
1285static enum
1286{
1287 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001288 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001289} pexpand_what;
1290
1291static char *pexpand_cmds[] = {
1292 "start",
1293#define PROFCMD_START 0
1294 "pause",
1295#define PROFCMD_PAUSE 1
1296 "continue",
1297#define PROFCMD_CONTINUE 2
1298 "func",
1299#define PROFCMD_FUNC 3
1300 "file",
1301#define PROFCMD_FILE 4
1302 NULL
1303#define PROFCMD_LAST 5
1304};
1305
1306/*
1307 * Function given to ExpandGeneric() to obtain the profile command
1308 * specific expansion.
1309 */
1310 char_u *
1311get_profile_name(xp, idx)
1312 expand_T *xp UNUSED;
1313 int idx;
1314{
1315 switch (pexpand_what)
1316 {
1317 case PEXP_SUBCMD:
1318 return (char_u *)pexpand_cmds[idx];
1319 /* case PEXP_FUNC: TODO */
1320 default:
1321 return NULL;
1322 }
1323}
1324
1325/*
1326 * Handle command line completion for :profile command.
1327 */
1328 void
1329set_context_in_profile_cmd(xp, arg)
1330 expand_T *xp;
1331 char_u *arg;
1332{
1333 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001334
1335 /* Default: expand subcommands. */
1336 xp->xp_context = EXPAND_PROFILE;
1337 pexpand_what = PEXP_SUBCMD;
1338 xp->xp_pattern = arg;
1339
1340 end_subcmd = skiptowhite(arg);
1341 if (*end_subcmd == NUL)
1342 return;
1343
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001344 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001345 {
1346 xp->xp_context = EXPAND_FILES;
1347 xp->xp_pattern = skipwhite(end_subcmd);
1348 return;
1349 }
1350
1351 /* TODO: expand function names after "func" */
1352 xp->xp_context = EXPAND_NOTHING;
1353}
1354
Bram Moolenaar05159a02005-02-26 23:04:13 +00001355/*
1356 * Dump the profiling info.
1357 */
1358 void
1359profile_dump()
1360{
1361 FILE *fd;
1362
1363 if (profile_fname != NULL)
1364 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001365 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001366 if (fd == NULL)
1367 EMSG2(_(e_notopen), profile_fname);
1368 else
1369 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001370 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001371 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001372 fclose(fd);
1373 }
1374 }
1375}
1376
1377/*
1378 * Start profiling script "fp".
1379 */
1380 static void
1381script_do_profile(si)
1382 scriptitem_T *si;
1383{
1384 si->sn_pr_count = 0;
1385 profile_zero(&si->sn_pr_total);
1386 profile_zero(&si->sn_pr_self);
1387
1388 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1389 si->sn_prl_idx = -1;
1390 si->sn_prof_on = TRUE;
1391 si->sn_pr_nest = 0;
1392}
1393
1394/*
1395 * save time when starting to invoke another script or function.
1396 */
1397 void
1398script_prof_save(tm)
1399 proftime_T *tm; /* place to store wait time */
1400{
1401 scriptitem_T *si;
1402
1403 if (current_SID > 0 && current_SID <= script_items.ga_len)
1404 {
1405 si = &SCRIPT_ITEM(current_SID);
1406 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1407 profile_start(&si->sn_pr_child);
1408 }
1409 profile_get_wait(tm);
1410}
1411
1412/*
1413 * Count time spent in children after invoking another script or function.
1414 */
1415 void
1416script_prof_restore(tm)
1417 proftime_T *tm;
1418{
1419 scriptitem_T *si;
1420
1421 if (current_SID > 0 && current_SID <= script_items.ga_len)
1422 {
1423 si = &SCRIPT_ITEM(current_SID);
1424 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1425 {
1426 profile_end(&si->sn_pr_child);
1427 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1428 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1429 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1430 }
1431 }
1432}
1433
1434static proftime_T inchar_time;
1435
1436/*
1437 * Called when starting to wait for the user to type a character.
1438 */
1439 void
1440prof_inchar_enter()
1441{
1442 profile_start(&inchar_time);
1443}
1444
1445/*
1446 * Called when finished waiting for the user to type a character.
1447 */
1448 void
1449prof_inchar_exit()
1450{
1451 profile_end(&inchar_time);
1452 profile_add(&prof_wait_time, &inchar_time);
1453}
1454
1455/*
1456 * Dump the profiling results for all scripts in file "fd".
1457 */
1458 static void
1459script_dump_profile(fd)
1460 FILE *fd;
1461{
1462 int id;
1463 scriptitem_T *si;
1464 int i;
1465 FILE *sfd;
1466 sn_prl_T *pp;
1467
1468 for (id = 1; id <= script_items.ga_len; ++id)
1469 {
1470 si = &SCRIPT_ITEM(id);
1471 if (si->sn_prof_on)
1472 {
1473 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1474 if (si->sn_pr_count == 1)
1475 fprintf(fd, "Sourced 1 time\n");
1476 else
1477 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1478 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1479 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1480 fprintf(fd, "\n");
1481 fprintf(fd, "count total (s) self (s)\n");
1482
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001483 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001484 if (sfd == NULL)
1485 fprintf(fd, "Cannot open file!\n");
1486 else
1487 {
1488 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1489 {
1490 if (vim_fgets(IObuff, IOSIZE, sfd))
1491 break;
1492 pp = &PRL_ITEM(si, i);
1493 if (pp->snp_count > 0)
1494 {
1495 fprintf(fd, "%5d ", pp->snp_count);
1496 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1497 fprintf(fd, " ");
1498 else
1499 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1500 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1501 }
1502 else
1503 fprintf(fd, " ");
1504 fprintf(fd, "%s", IObuff);
1505 }
1506 fclose(sfd);
1507 }
1508 fprintf(fd, "\n");
1509 }
1510 }
1511}
1512
1513/*
1514 * Return TRUE when a function defined in the current script should be
1515 * profiled.
1516 */
1517 int
1518prof_def_func()
1519{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001520 if (current_SID > 0)
1521 return SCRIPT_ITEM(current_SID).sn_pr_force;
1522 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001523}
1524
1525# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001526#endif
1527
1528/*
1529 * If 'autowrite' option set, try to write the file.
1530 * Careful: autocommands may make "buf" invalid!
1531 *
1532 * return FAIL for failure, OK otherwise
1533 */
1534 int
1535autowrite(buf, forceit)
1536 buf_T *buf;
1537 int forceit;
1538{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001539 int r;
1540
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541 if (!(p_aw || p_awa) || !p_write
1542#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001543 /* never autowrite a "nofile" or "nowrite" buffer */
1544 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001545#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001546 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001547 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001548 r = buf_write_all(buf, forceit);
1549
1550 /* Writing may succeed but the buffer still changed, e.g., when there is a
1551 * conversion error. We do want to return FAIL then. */
1552 if (buf_valid(buf) && bufIsChanged(buf))
1553 r = FAIL;
1554 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001555}
1556
1557/*
1558 * flush all buffers, except the ones that are readonly
1559 */
1560 void
1561autowrite_all()
1562{
1563 buf_T *buf;
1564
1565 if (!(p_aw || p_awa) || !p_write)
1566 return;
1567 for (buf = firstbuf; buf; buf = buf->b_next)
1568 if (bufIsChanged(buf) && !buf->b_p_ro)
1569 {
1570 (void)buf_write_all(buf, FALSE);
1571#ifdef FEAT_AUTOCMD
1572 /* an autocommand may have deleted the buffer */
1573 if (!buf_valid(buf))
1574 buf = firstbuf;
1575#endif
1576 }
1577}
1578
1579/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001580 * Return TRUE if buffer was changed and cannot be abandoned.
1581 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001582 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583 int
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001584check_changed(buf, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001585 buf_T *buf;
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001586 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001587{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001588 int forceit = (flags & CCGD_FORCEIT);
1589
Bram Moolenaar071d4272004-06-13 20:20:40 +00001590 if ( !forceit
1591 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001592 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1593 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001594 {
1595#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1596 if ((p_confirm || cmdmod.confirm) && p_write)
1597 {
1598 buf_T *buf2;
1599 int count = 0;
1600
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001601 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1603 if (bufIsChanged(buf2)
1604 && (buf2->b_ffname != NULL
1605# ifdef FEAT_BROWSE
1606 || cmdmod.browse
1607# endif
1608 ))
1609 ++count;
1610# ifdef FEAT_AUTOCMD
1611 if (!buf_valid(buf))
1612 /* Autocommand deleted buffer, oops! It's not changed now. */
1613 return FALSE;
1614# endif
1615 dialog_changed(buf, count > 1);
1616# ifdef FEAT_AUTOCMD
1617 if (!buf_valid(buf))
1618 /* Autocommand deleted buffer, oops! It's not changed now. */
1619 return FALSE;
1620# endif
1621 return bufIsChanged(buf);
1622 }
1623#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001624 if (flags & CCGD_EXCMD)
1625 EMSG(_(e_nowrtmsg));
1626 else
1627 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001628 return TRUE;
1629 }
1630 return FALSE;
1631}
1632
1633#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1634
1635#if defined(FEAT_BROWSE) || defined(PROTO)
1636/*
1637 * When wanting to write a file without a file name, ask the user for a name.
1638 */
1639 void
1640browse_save_fname(buf)
1641 buf_T *buf;
1642{
1643 if (buf->b_fname == NULL)
1644 {
1645 char_u *fname;
1646
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001647 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1648 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001649 if (fname != NULL)
1650 {
1651 if (setfname(buf, fname, NULL, TRUE) == OK)
1652 buf->b_flags |= BF_NOTEDITED;
1653 vim_free(fname);
1654 }
1655 }
1656}
1657#endif
1658
1659/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001660 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661 * Must check 'write' option first!
1662 */
1663 void
1664dialog_changed(buf, checkall)
1665 buf_T *buf;
1666 int checkall; /* may abandon all changed buffers */
1667{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001668 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001669 int ret;
1670 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001671 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001672
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001673 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674 (buf->b_fname != NULL) ?
1675 buf->b_fname : (char_u *)_("Untitled"));
1676 if (checkall)
1677 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1678 else
1679 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1680
Bram Moolenaar8218f602012-04-25 17:32:18 +02001681 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1682 * function. */
1683 ea.append = ea.forceit = FALSE;
1684
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685 if (ret == VIM_YES)
1686 {
1687#ifdef FEAT_BROWSE
1688 /* May get file name, when there is none */
1689 browse_save_fname(buf);
1690#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001691 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1692 buf->b_fname, buf->b_ffname, FALSE) == OK)
1693 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001694 (void)buf_write_all(buf, FALSE);
1695 }
1696 else if (ret == VIM_NO)
1697 {
1698 unchanged(buf, TRUE);
1699 }
1700 else if (ret == VIM_ALL)
1701 {
1702 /*
1703 * Write all modified files that can be written.
1704 * Skip readonly buffers, these need to be confirmed
1705 * individually.
1706 */
1707 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1708 {
1709 if (bufIsChanged(buf2)
1710 && (buf2->b_ffname != NULL
1711#ifdef FEAT_BROWSE
1712 || cmdmod.browse
1713#endif
1714 )
1715 && !buf2->b_p_ro)
1716 {
1717#ifdef FEAT_BROWSE
1718 /* May get file name, when there is none */
1719 browse_save_fname(buf2);
1720#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001721 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1722 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1723 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 (void)buf_write_all(buf2, FALSE);
1725#ifdef FEAT_AUTOCMD
1726 /* an autocommand may have deleted the buffer */
1727 if (!buf_valid(buf2))
1728 buf2 = firstbuf;
1729#endif
1730 }
1731 }
1732 }
1733 else if (ret == VIM_DISCARDALL)
1734 {
1735 /*
1736 * mark all buffers as unchanged
1737 */
1738 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1739 unchanged(buf2, TRUE);
1740 }
1741}
1742#endif
1743
1744/*
1745 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1746 * hidden, autowriting it or unloading it.
1747 */
1748 int
1749can_abandon(buf, forceit)
1750 buf_T *buf;
1751 int forceit;
1752{
1753 return ( P_HID(buf)
1754 || !bufIsChanged(buf)
1755 || buf->b_nwindows > 1
1756 || autowrite(buf, forceit) == OK
1757 || forceit);
1758}
1759
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001760static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001761
1762/*
1763 * Add a buffer number to "bufnrs", unless it's already there.
1764 */
1765 static void
1766add_bufnum(bufnrs, bufnump, nr)
1767 int *bufnrs;
1768 int *bufnump;
1769 int nr;
1770{
1771 int i;
1772
1773 for (i = 0; i < *bufnump; ++i)
1774 if (bufnrs[i] == nr)
1775 return;
1776 bufnrs[*bufnump] = nr;
1777 *bufnump = *bufnump + 1;
1778}
1779
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780/*
1781 * Return TRUE if any buffer was changed and cannot be abandoned.
1782 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001783 * When "unload" is true the current buffer is unloaded instead of making it
1784 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001785 */
1786 int
Bram Moolenaar027387f2016-01-02 22:25:52 +01001787check_changed_any(hidden, unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788 int hidden; /* Only check hidden buffers */
Bram Moolenaar027387f2016-01-02 22:25:52 +01001789 int unload;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001790{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001791 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792 buf_T *buf;
1793 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001794 int i;
1795 int bufnum = 0;
1796 int bufcount = 0;
1797 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001799 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 win_T *wp;
1801#endif
1802
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001803 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1804 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001805
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001806 if (bufcount == 0)
1807 return FALSE;
1808
1809 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1810 if (bufnrs == NULL)
1811 return FALSE;
1812
1813 /* curbuf */
1814 bufnrs[bufnum++] = curbuf->b_fnum;
1815#ifdef FEAT_WINDOWS
1816 /* buf in curtab */
1817 FOR_ALL_WINDOWS(wp)
1818 if (wp->w_buffer != curbuf)
1819 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1820
1821 /* buf in other tab */
1822 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1823 if (tp != curtab)
1824 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1825 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1826#endif
1827 /* any other buf */
1828 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1829 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1830
1831 for (i = 0; i < bufnum; ++i)
1832 {
1833 buf = buflist_findnr(bufnrs[i]);
1834 if (buf == NULL)
1835 continue;
1836 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1837 {
1838 /* Try auto-writing the buffer. If this fails but the buffer no
1839 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001840 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1841 | CCGD_MULTWIN
1842 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001843 break; /* didn't save - still changes */
1844 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001845 }
1846
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001847 if (i >= bufnum)
1848 goto theend;
1849
1850 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851 exiting = FALSE;
1852#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1853 /*
1854 * When ":confirm" used, don't give an error message.
1855 */
1856 if (!(p_confirm || cmdmod.confirm))
1857#endif
1858 {
1859 /* There must be a wait_return for this message, do_buffer()
1860 * may cause a redraw. But wait_return() is a no-op when vgetc()
1861 * is busy (Quit used from window menu), then make sure we don't
1862 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001863 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864 {
1865 msg_row = cmdline_row;
1866 msg_col = 0;
1867 msg_didout = FALSE;
1868 }
1869 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001870 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871 {
1872 save = no_wait_return;
1873 no_wait_return = FALSE;
1874 wait_return(FALSE);
1875 no_wait_return = save;
1876 }
1877 }
1878
1879#ifdef FEAT_WINDOWS
1880 /* Try to find a window that contains the buffer. */
1881 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001882 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 if (wp->w_buffer == buf)
1884 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001885 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886# ifdef FEAT_AUTOCMD
1887 /* Paranoia: did autocms wipe out the buffer with changes? */
1888 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001889 {
1890 goto theend;
1891 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001892# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001893 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001895buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896#endif
1897
1898 /* Open the changed buffer in the current window. */
1899 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001900 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001902theend:
1903 vim_free(bufnrs);
1904 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905}
1906
1907/*
1908 * return FAIL if there is no file name, OK if there is one
1909 * give error message for FAIL
1910 */
1911 int
1912check_fname()
1913{
1914 if (curbuf->b_ffname == NULL)
1915 {
1916 EMSG(_(e_noname));
1917 return FAIL;
1918 }
1919 return OK;
1920}
1921
1922/*
1923 * flush the contents of a buffer, unless it has no file name
1924 *
1925 * return FAIL for failure, OK otherwise
1926 */
1927 int
1928buf_write_all(buf, forceit)
1929 buf_T *buf;
1930 int forceit;
1931{
1932 int retval;
1933#ifdef FEAT_AUTOCMD
1934 buf_T *old_curbuf = curbuf;
1935#endif
1936
1937 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1938 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1939 FALSE, forceit, TRUE, FALSE));
1940#ifdef FEAT_AUTOCMD
1941 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001942 {
1943 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001945 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001946#endif
1947 return retval;
1948}
1949
1950/*
1951 * Code to handle the argument list.
1952 */
1953
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001954static char_u *do_one_arg(char_u *str);
1955static int do_arglist(char_u *str, int what, int after);
1956static void alist_check_arg_idx(void);
1957static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001958#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001959static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001960#endif
1961#define AL_SET 1
1962#define AL_ADD 2
1963#define AL_DEL 3
1964
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001966 * Isolate one argument, taking backticks.
1967 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968 * Return a pointer to the start of the next argument.
1969 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001970 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971do_one_arg(str)
1972 char_u *str;
1973{
1974 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001975 int inbacktick;
1976
Bram Moolenaar071d4272004-06-13 20:20:40 +00001977 inbacktick = FALSE;
1978 for (p = str; *str; ++str)
1979 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001980 /* When the backslash is used for escaping the special meaning of a
1981 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001982 if (rem_backslash(str))
1983 {
1984 *p++ = *str++;
1985 *p++ = *str;
1986 }
1987 else
1988 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001989 /* An item ends at a space not in backticks */
1990 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001991 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001992 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001993 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001994 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995 }
1996 }
1997 str = skipwhite(str);
1998 *p = NUL;
1999
2000 return str;
2001}
2002
Bram Moolenaar86b68352004-12-27 21:59:20 +00002003/*
2004 * Separate the arguments in "str" and return a list of pointers in the
2005 * growarray "gap".
2006 */
2007 int
2008get_arglist(gap, str)
2009 garray_T *gap;
2010 char_u *str;
2011{
2012 ga_init2(gap, (int)sizeof(char_u *), 20);
2013 while (*str != NUL)
2014 {
2015 if (ga_grow(gap, 1) == FAIL)
2016 {
2017 ga_clear(gap);
2018 return FAIL;
2019 }
2020 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2021
2022 /* Isolate one argument, change it in-place, put a NUL after it. */
2023 str = do_one_arg(str);
2024 }
2025 return OK;
2026}
2027
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002028#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002029/*
2030 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002031 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002032 * Return FAIL or OK.
2033 */
2034 int
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002035get_arglist_exp(str, fcountp, fnamesp, wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002036 char_u *str;
2037 int *fcountp;
2038 char_u ***fnamesp;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002039 int wig;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002040{
2041 garray_T ga;
2042 int i;
2043
2044 if (get_arglist(&ga, str) == FAIL)
2045 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002046 if (wig == TRUE)
2047 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2048 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2049 else
2050 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2051 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2052
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002053 ga_clear(&ga);
2054 return i;
2055}
2056#endif
2057
Bram Moolenaar071d4272004-06-13 20:20:40 +00002058#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2059/*
2060 * Redefine the argument list.
2061 */
2062 void
2063set_arglist(str)
2064 char_u *str;
2065{
2066 do_arglist(str, AL_SET, 0);
2067}
2068#endif
2069
2070/*
2071 * "what" == AL_SET: Redefine the argument list to 'str'.
2072 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2073 * "what" == AL_DEL: remove files in 'str' from the argument list.
2074 *
2075 * Return FAIL for failure, OK otherwise.
2076 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002077 static int
2078do_arglist(str, what, after)
2079 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002080 int what UNUSED;
2081 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002082{
2083 garray_T new_ga;
2084 int exp_count;
2085 char_u **exp_files;
2086 int i;
2087#ifdef FEAT_LISTCMDS
2088 char_u *p;
2089 int match;
2090#endif
2091
2092 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002093 * Set default argument for ":argadd" command.
2094 */
2095 if (what == AL_ADD && *str == NUL)
2096 {
2097 if (curbuf->b_ffname == NULL)
2098 return FAIL;
2099 str = curbuf->b_fname;
2100 }
2101
2102 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 * Collect all file name arguments in "new_ga".
2104 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002105 if (get_arglist(&new_ga, str) == FAIL)
2106 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002107
2108#ifdef FEAT_LISTCMDS
2109 if (what == AL_DEL)
2110 {
2111 regmatch_T regmatch;
2112 int didone;
2113
2114 /*
2115 * Delete the items: use each item as a regexp and find a match in the
2116 * argument list.
2117 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002118 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002119 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2120 {
2121 p = ((char_u **)new_ga.ga_data)[i];
2122 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2123 if (p == NULL)
2124 break;
2125 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2126 if (regmatch.regprog == NULL)
2127 {
2128 vim_free(p);
2129 break;
2130 }
2131
2132 didone = FALSE;
2133 for (match = 0; match < ARGCOUNT; ++match)
2134 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2135 (colnr_T)0))
2136 {
2137 didone = TRUE;
2138 vim_free(ARGLIST[match].ae_fname);
2139 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2140 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2141 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142 if (curwin->w_arg_idx > match)
2143 --curwin->w_arg_idx;
2144 --match;
2145 }
2146
Bram Moolenaar473de612013-06-08 18:19:48 +02002147 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148 vim_free(p);
2149 if (!didone)
2150 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2151 }
2152 ga_clear(&new_ga);
2153 }
2154 else
2155#endif
2156 {
2157 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2158 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2159 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002160 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002161 {
2162 EMSG(_(e_nomatch));
2163 return FAIL;
2164 }
2165
2166#ifdef FEAT_LISTCMDS
2167 if (what == AL_ADD)
2168 {
2169 (void)alist_add_list(exp_count, exp_files, after);
2170 vim_free(exp_files);
2171 }
2172 else /* what == AL_SET */
2173#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002174 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002175 }
2176
2177 alist_check_arg_idx();
2178
2179 return OK;
2180}
2181
2182/*
2183 * Check the validity of the arg_idx for each other window.
2184 */
2185 static void
2186alist_check_arg_idx()
2187{
2188#ifdef FEAT_WINDOWS
2189 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002190 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002191
Bram Moolenaarf740b292006-02-16 22:11:02 +00002192 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002193 if (win->w_alist == curwin->w_alist)
2194 check_arg_idx(win);
2195#else
2196 check_arg_idx(curwin);
2197#endif
2198}
2199
2200/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002201 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002202 * index.
2203 */
2204 static int
2205editing_arg_idx(win)
2206 win_T *win;
2207{
2208 return !(win->w_arg_idx >= WARGCOUNT(win)
2209 || (win->w_buffer->b_fnum
2210 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2211 && (win->w_buffer->b_ffname == NULL
2212 || !(fullpathcmp(
2213 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2214 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2215}
2216
2217/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002218 * Check if window "win" is editing the w_arg_idx file in its argument list.
2219 */
2220 void
2221check_arg_idx(win)
2222 win_T *win;
2223{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002224 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225 {
2226 /* We are not editing the current entry in the argument list.
2227 * Set "arg_had_last" if we are editing the last one. */
2228 win->w_arg_idx_invalid = TRUE;
2229 if (win->w_arg_idx != WARGCOUNT(win) - 1
2230 && arg_had_last == FALSE
2231#ifdef FEAT_WINDOWS
2232 && ALIST(win) == &global_alist
2233#endif
2234 && GARGCOUNT > 0
2235 && win->w_arg_idx < GARGCOUNT
2236 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2237 || (win->w_buffer->b_ffname != NULL
2238 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2239 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2240 arg_had_last = TRUE;
2241 }
2242 else
2243 {
2244 /* We are editing the current entry in the argument list.
2245 * Set "arg_had_last" if it's also the last one */
2246 win->w_arg_idx_invalid = FALSE;
2247 if (win->w_arg_idx == WARGCOUNT(win) - 1
2248#ifdef FEAT_WINDOWS
2249 && win->w_alist == &global_alist
2250#endif
2251 )
2252 arg_had_last = TRUE;
2253 }
2254}
2255
2256/*
2257 * ":args", ":argslocal" and ":argsglobal".
2258 */
2259 void
2260ex_args(eap)
2261 exarg_T *eap;
2262{
2263 int i;
2264
2265 if (eap->cmdidx != CMD_args)
2266 {
2267#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2268 alist_unlink(ALIST(curwin));
2269 if (eap->cmdidx == CMD_argglobal)
2270 ALIST(curwin) = &global_alist;
2271 else /* eap->cmdidx == CMD_arglocal */
2272 alist_new();
2273#else
2274 ex_ni(eap);
2275 return;
2276#endif
2277 }
2278
2279 if (!ends_excmd(*eap->arg))
2280 {
2281 /*
2282 * ":args file ..": define new argument list, handle like ":next"
2283 * Also for ":argslocal file .." and ":argsglobal file ..".
2284 */
2285 ex_next(eap);
2286 }
2287 else
2288#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2289 if (eap->cmdidx == CMD_args)
2290#endif
2291 {
2292 /*
2293 * ":args": list arguments.
2294 */
2295 if (ARGCOUNT > 0)
2296 {
2297 /* Overwrite the command, for a short list there is no scrolling
2298 * required and no wait_return(). */
2299 gotocmdline(TRUE);
2300 for (i = 0; i < ARGCOUNT; ++i)
2301 {
2302 if (i == curwin->w_arg_idx)
2303 msg_putchar('[');
2304 msg_outtrans(alist_name(&ARGLIST[i]));
2305 if (i == curwin->w_arg_idx)
2306 msg_putchar(']');
2307 msg_putchar(' ');
2308 }
2309 }
2310 }
2311#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2312 else if (eap->cmdidx == CMD_arglocal)
2313 {
2314 garray_T *gap = &curwin->w_alist->al_ga;
2315
2316 /*
2317 * ":argslocal": make a local copy of the global argument list.
2318 */
2319 if (ga_grow(gap, GARGCOUNT) == OK)
2320 for (i = 0; i < GARGCOUNT; ++i)
2321 if (GARGLIST[i].ae_fname != NULL)
2322 {
2323 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2324 vim_strsave(GARGLIST[i].ae_fname);
2325 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2326 GARGLIST[i].ae_fnum;
2327 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 }
2329 }
2330#endif
2331}
2332
2333/*
2334 * ":previous", ":sprevious", ":Next" and ":sNext".
2335 */
2336 void
2337ex_previous(eap)
2338 exarg_T *eap;
2339{
2340 /* If past the last one already, go to the last one. */
2341 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2342 do_argfile(eap, ARGCOUNT - 1);
2343 else
2344 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2345}
2346
2347/*
2348 * ":rewind", ":first", ":sfirst" and ":srewind".
2349 */
2350 void
2351ex_rewind(eap)
2352 exarg_T *eap;
2353{
2354 do_argfile(eap, 0);
2355}
2356
2357/*
2358 * ":last" and ":slast".
2359 */
2360 void
2361ex_last(eap)
2362 exarg_T *eap;
2363{
2364 do_argfile(eap, ARGCOUNT - 1);
2365}
2366
2367/*
2368 * ":argument" and ":sargument".
2369 */
2370 void
2371ex_argument(eap)
2372 exarg_T *eap;
2373{
2374 int i;
2375
2376 if (eap->addr_count > 0)
2377 i = eap->line2 - 1;
2378 else
2379 i = curwin->w_arg_idx;
2380 do_argfile(eap, i);
2381}
2382
2383/*
2384 * Edit file "argn" of the argument lists.
2385 */
2386 void
2387do_argfile(eap, argn)
2388 exarg_T *eap;
2389 int argn;
2390{
2391 int other;
2392 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002393 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394
2395 if (argn < 0 || argn >= ARGCOUNT)
2396 {
2397 if (ARGCOUNT <= 1)
2398 EMSG(_("E163: There is only one file to edit"));
2399 else if (argn < 0)
2400 EMSG(_("E164: Cannot go before first file"));
2401 else
2402 EMSG(_("E165: Cannot go beyond last file"));
2403 }
2404 else
2405 {
2406 setpcmark();
2407#ifdef FEAT_GUI
2408 need_mouse_correct = TRUE;
2409#endif
2410
2411#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002412 /* split window or create new tab page first */
2413 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 {
2415 if (win_split(0, 0) == FAIL)
2416 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002417 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002418 }
2419 else
2420#endif
2421 {
2422 /*
2423 * if 'hidden' set, only check for changed file when re-editing
2424 * the same buffer
2425 */
2426 other = TRUE;
2427 if (P_HID(curbuf))
2428 {
2429 p = fix_fname(alist_name(&ARGLIST[argn]));
2430 other = otherfile(p);
2431 vim_free(p);
2432 }
2433 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002434 && check_changed(curbuf, CCGD_AW
2435 | (other ? 0 : CCGD_MULTWIN)
2436 | (eap->forceit ? CCGD_FORCEIT : 0)
2437 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438 return;
2439 }
2440
2441 curwin->w_arg_idx = argn;
2442 if (argn == ARGCOUNT - 1
2443#ifdef FEAT_WINDOWS
2444 && curwin->w_alist == &global_alist
2445#endif
2446 )
2447 arg_had_last = TRUE;
2448
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002449 /* Edit the file; always use the last known line number.
2450 * When it fails (e.g. Abort for already edited file) restore the
2451 * argument index. */
2452 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002453 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002454 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2455 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002456 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002458 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 setmark('\'');
2460 }
2461}
2462
2463/*
2464 * ":next", and commands that behave like it.
2465 */
2466 void
2467ex_next(eap)
2468 exarg_T *eap;
2469{
2470 int i;
2471
2472 /*
2473 * check for changed buffer now, if this fails the argument list is not
2474 * redefined.
2475 */
2476 if ( P_HID(curbuf)
2477 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002478 || !check_changed(curbuf, CCGD_AW
2479 | (eap->forceit ? CCGD_FORCEIT : 0)
2480 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 {
2482 if (*eap->arg != NUL) /* redefine file list */
2483 {
2484 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2485 return;
2486 i = 0;
2487 }
2488 else
2489 i = curwin->w_arg_idx + (int)eap->line2;
2490 do_argfile(eap, i);
2491 }
2492}
2493
2494#ifdef FEAT_LISTCMDS
2495/*
2496 * ":argedit"
2497 */
2498 void
2499ex_argedit(eap)
2500 exarg_T *eap;
2501{
2502 int fnum;
2503 int i;
2504 char_u *s;
2505
2506 /* Add the argument to the buffer list and get the buffer number. */
2507 fnum = buflist_add(eap->arg, BLN_LISTED);
2508
2509 /* Check if this argument is already in the argument list. */
2510 for (i = 0; i < ARGCOUNT; ++i)
2511 if (ARGLIST[i].ae_fnum == fnum)
2512 break;
2513 if (i == ARGCOUNT)
2514 {
2515 /* Can't find it, add it to the argument list. */
2516 s = vim_strsave(eap->arg);
2517 if (s == NULL)
2518 return;
2519 i = alist_add_list(1, &s,
2520 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2521 if (i < 0)
2522 return;
2523 curwin->w_arg_idx = i;
2524 }
2525
2526 alist_check_arg_idx();
2527
2528 /* Edit the argument. */
2529 do_argfile(eap, i);
2530}
2531
2532/*
2533 * ":argadd"
2534 */
2535 void
2536ex_argadd(eap)
2537 exarg_T *eap;
2538{
2539 do_arglist(eap->arg, AL_ADD,
2540 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2541#ifdef FEAT_TITLE
2542 maketitle();
2543#endif
2544}
2545
2546/*
2547 * ":argdelete"
2548 */
2549 void
2550ex_argdelete(eap)
2551 exarg_T *eap;
2552{
2553 int i;
2554 int n;
2555
2556 if (eap->addr_count > 0)
2557 {
2558 /* ":1,4argdel": Delete all arguments in the range. */
2559 if (eap->line2 > ARGCOUNT)
2560 eap->line2 = ARGCOUNT;
2561 n = eap->line2 - eap->line1 + 1;
2562 if (*eap->arg != NUL || n <= 0)
2563 EMSG(_(e_invarg));
2564 else
2565 {
2566 for (i = eap->line1; i <= eap->line2; ++i)
2567 vim_free(ARGLIST[i - 1].ae_fname);
2568 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2569 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2570 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 if (curwin->w_arg_idx >= eap->line2)
2572 curwin->w_arg_idx -= n;
2573 else if (curwin->w_arg_idx > eap->line1)
2574 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002575 if (ARGCOUNT == 0)
2576 curwin->w_arg_idx = 0;
2577 else if (curwin->w_arg_idx >= ARGCOUNT)
2578 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002579 }
2580 }
2581 else if (*eap->arg == NUL)
2582 EMSG(_(e_argreq));
2583 else
2584 do_arglist(eap->arg, AL_DEL, 0);
2585#ifdef FEAT_TITLE
2586 maketitle();
2587#endif
2588}
2589
2590/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002591 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592 */
2593 void
2594ex_listdo(eap)
2595 exarg_T *eap;
2596{
2597 int i;
2598#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002599 win_T *wp;
2600 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002601#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002602 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002603 int next_fnum = 0;
2604#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2605 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002607 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002608#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002609 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002610 int qf_idx;
2611#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612
2613#ifndef FEAT_WINDOWS
2614 if (eap->cmdidx == CMD_windo)
2615 {
2616 ex_ni(eap);
2617 return;
2618 }
2619#endif
2620
2621#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002622 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002623 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2624 * great speed improvement. */
2625 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002627#ifdef FEAT_CLIPBOARD
2628 start_global_changes();
2629#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630
2631 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002632 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002634 || !check_changed(curbuf, CCGD_AW
2635 | (eap->forceit ? CCGD_FORCEIT : 0)
2636 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002637 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002638 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002639 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002641 wp = firstwin;
2642 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002644 switch (eap->cmdidx)
2645 {
2646#ifdef FEAT_WINDOWS
2647 case CMD_windo:
2648 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2649 i++;
2650 break;
2651 case CMD_tabdo:
2652 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2653 i++;
2654 break;
2655#endif
2656 case CMD_argdo:
2657 i = eap->line1 - 1;
2658 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002659 default:
2660 break;
2661 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002662 /* set pcmark now */
2663 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002664 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002665 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002666 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002667 || !buf->b_p_bl); buf = buf->b_next)
2668 if (buf->b_fnum > eap->line2)
2669 {
2670 buf = NULL;
2671 break;
2672 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002673 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002674 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002675 }
2676#ifdef FEAT_QUICKFIX
2677 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2678 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2679 {
2680 qf_size = qf_get_size(eap);
2681 if (qf_size <= 0 || eap->line1 > qf_size)
2682 buf = NULL;
2683 else
2684 {
2685 ex_cc(eap);
2686
2687 buf = curbuf;
2688 i = eap->line1 - 1;
2689 if (eap->addr_count <= 0)
2690 /* default is all the quickfix/location list entries */
2691 eap->line2 = qf_size;
2692 }
2693 }
2694#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002695 else
2696 setpcmark();
2697 listcmd_busy = TRUE; /* avoids setting pcmark below */
2698
Bram Moolenaare25bb902015-02-27 20:33:37 +01002699 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 {
2701 if (eap->cmdidx == CMD_argdo)
2702 {
2703 /* go to argument "i" */
2704 if (i == ARGCOUNT)
2705 break;
2706 /* Don't call do_argfile() when already there, it will try
2707 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002708 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002709 {
2710 /* Clear 'shm' to avoid that the file message overwrites
2711 * any output from the command. */
2712 p_shm_save = vim_strsave(p_shm);
2713 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002715 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2716 vim_free(p_shm_save);
2717 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 if (curwin->w_arg_idx != i)
2719 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 }
2721#ifdef FEAT_WINDOWS
2722 else if (eap->cmdidx == CMD_windo)
2723 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002724 /* go to window "wp" */
2725 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002727 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002728 if (curwin != wp)
2729 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002730 wp = curwin->w_next;
2731 }
2732 else if (eap->cmdidx == CMD_tabdo)
2733 {
2734 /* go to window "tp" */
2735 if (!valid_tabpage(tp))
2736 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002737 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002738 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739 }
2740#endif
2741 else if (eap->cmdidx == CMD_bufdo)
2742 {
2743 /* Remember the number of the next listed buffer, in case
2744 * ":bwipe" is used or autocommands do something strange. */
2745 next_fnum = -1;
2746 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2747 if (buf->b_p_bl)
2748 {
2749 next_fnum = buf->b_fnum;
2750 break;
2751 }
2752 }
2753
Bram Moolenaara162bc52015-01-07 16:54:21 +01002754 ++i;
2755
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 /* execute the command */
2757 do_cmdline(eap->arg, eap->getline, eap->cookie,
2758 DOCMD_VERBOSE + DOCMD_NOWAIT);
2759
2760 if (eap->cmdidx == CMD_bufdo)
2761 {
2762 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002763 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 break;
2765 /* Check if the buffer still exists. */
2766 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2767 if (buf->b_fnum == next_fnum)
2768 break;
2769 if (buf == NULL)
2770 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002771
2772 /* Go to the next buffer. Clear 'shm' to avoid that the file
2773 * message overwrites any output from the command. */
2774 p_shm_save = vim_strsave(p_shm);
2775 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002777 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2778 vim_free(p_shm_save);
2779
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002780 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002781 if (curbuf->b_fnum != next_fnum)
2782 break;
2783 }
2784
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002785#ifdef FEAT_QUICKFIX
2786 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2787 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2788 {
2789 if (i >= qf_size || i >= eap->line2)
2790 break;
2791
2792 qf_idx = qf_get_cur_idx(eap);
2793
2794 ex_cnext(eap);
2795
2796 /* If jumping to the next quickfix entry fails, quit here */
2797 if (qf_get_cur_idx(eap) == qf_idx)
2798 break;
2799 }
2800#endif
2801
Bram Moolenaar071d4272004-06-13 20:20:40 +00002802 if (eap->cmdidx == CMD_windo)
2803 {
2804 validate_cursor(); /* cursor may have moved */
2805#ifdef FEAT_SCROLLBIND
2806 /* required when 'scrollbind' has been set */
2807 if (curwin->w_p_scb)
2808 do_check_scrollbind(TRUE);
2809#endif
2810 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002811
2812#ifdef FEAT_WINDOWS
2813 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2814 if (i+1 > eap->line2)
2815 break;
2816#endif
2817 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2818 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819 }
2820 listcmd_busy = FALSE;
2821 }
2822
2823#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002824 if (save_ei != NULL)
2825 {
2826 au_event_restore(save_ei);
2827 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2828 curbuf->b_fname, TRUE, curbuf);
2829 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002830#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002831#ifdef FEAT_CLIPBOARD
2832 end_global_changes();
2833#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002834}
2835
2836/*
2837 * Add files[count] to the arglist of the current window after arg "after".
2838 * The file names in files[count] must have been allocated and are taken over.
2839 * Files[] itself is not taken over.
2840 * Returns index of first added argument. Returns -1 when failed (out of mem).
2841 */
2842 static int
2843alist_add_list(count, files, after)
2844 int count;
2845 char_u **files;
2846 int after; /* where to add: 0 = before first one */
2847{
2848 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002849 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850
2851 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2852 {
2853 if (after < 0)
2854 after = 0;
2855 if (after > ARGCOUNT)
2856 after = ARGCOUNT;
2857 if (after < ARGCOUNT)
2858 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2859 (ARGCOUNT - after) * sizeof(aentry_T));
2860 for (i = 0; i < count; ++i)
2861 {
2862 ARGLIST[after + i].ae_fname = files[i];
2863 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2864 }
2865 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002866 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2867 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002868 return after;
2869 }
2870
2871 for (i = 0; i < count; ++i)
2872 vim_free(files[i]);
2873 return -1;
2874}
2875
2876#endif /* FEAT_LISTCMDS */
2877
2878#ifdef FEAT_EVAL
2879/*
2880 * ":compiler[!] {name}"
2881 */
2882 void
2883ex_compiler(eap)
2884 exarg_T *eap;
2885{
2886 char_u *buf;
2887 char_u *old_cur_comp = NULL;
2888 char_u *p;
2889
2890 if (*eap->arg == NUL)
2891 {
2892 /* List all compiler scripts. */
2893 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2894 /* ) keep the indenter happy... */
2895 }
2896 else
2897 {
2898 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2899 if (buf != NULL)
2900 {
2901 if (eap->forceit)
2902 {
2903 /* ":compiler! {name}" sets global options */
2904 do_cmdline_cmd((char_u *)
2905 "command -nargs=* CompilerSet set <args>");
2906 }
2907 else
2908 {
2909 /* ":compiler! {name}" sets local options.
2910 * To remain backwards compatible "current_compiler" is always
2911 * used. A user's compiler plugin may set it, the distributed
2912 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002913 * "b:current_compiler" and restore "current_compiler".
2914 * Explicitly prepend "g:" to make it work in a function. */
2915 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916 if (old_cur_comp != NULL)
2917 old_cur_comp = vim_strsave(old_cur_comp);
2918 do_cmdline_cmd((char_u *)
2919 "command -nargs=* CompilerSet setlocal <args>");
2920 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002921 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002922 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923
2924 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002925 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2927 vim_free(buf);
2928
2929 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2930
2931 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002932 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933 if (p != NULL)
2934 set_internal_string_var((char_u *)"b:current_compiler", p);
2935
2936 /* Restore "current_compiler" for ":compiler {name}". */
2937 if (!eap->forceit)
2938 {
2939 if (old_cur_comp != NULL)
2940 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002941 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 old_cur_comp);
2943 vim_free(old_cur_comp);
2944 }
2945 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002946 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947 }
2948 }
2949 }
2950}
2951#endif
2952
2953/*
2954 * ":runtime {name}"
2955 */
2956 void
2957ex_runtime(eap)
2958 exarg_T *eap;
2959{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002960 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002961}
2962
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002963static void source_callback(char_u *fname, void *cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002964
2965 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002966source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002968 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002969{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002970 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971}
2972
2973/*
2974 * Source the file "name" from all directories in 'runtimepath'.
2975 * "name" can contain wildcards.
2976 * When "all" is TRUE, source all files, otherwise only the first one.
2977 * return FAIL when no file could be sourced, OK otherwise.
2978 */
2979 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002980source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002981 char_u *name;
2982 int all;
2983{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002984 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002985}
2986
2987/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002988 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2989 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2991 * used.
2992 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002993 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002994 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2995 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002996 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002997 */
2998 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002999do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 char_u *name;
3001 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003002 void (*callback)__ARGS((char_u *fname, void *ck));
3003 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004{
3005 char_u *rtp;
3006 char_u *np;
3007 char_u *buf;
3008 char_u *rtp_copy;
3009 char_u *tail;
3010 int num_files;
3011 char_u **files;
3012 int i;
3013 int did_one = FALSE;
3014#ifdef AMIGA
3015 struct Process *proc = (struct Process *)FindTask(0L);
3016 APTR save_winptr = proc->pr_WindowPtr;
3017
3018 /* Avoid a requester here for a volume that doesn't exist. */
3019 proc->pr_WindowPtr = (APTR)-1L;
3020#endif
3021
3022 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3023 * value. */
3024 rtp_copy = vim_strsave(p_rtp);
3025 buf = alloc(MAXPATHL);
3026 if (buf != NULL && rtp_copy != NULL)
3027 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003028 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003029 {
3030 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003031 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003033 verbose_leave();
3034 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003035
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036 /* Loop over all entries in 'runtimepath'. */
3037 rtp = rtp_copy;
3038 while (*rtp != NUL && (all || !did_one))
3039 {
3040 /* Copy the path from 'runtimepath' to buf[]. */
3041 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003042 if (name == NULL)
3043 {
3044 (*callback)(buf, (void *) &cookie);
3045 if (!did_one)
3046 did_one = (cookie == NULL);
3047 }
3048 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049 {
3050 add_pathsep(buf);
3051 tail = buf + STRLEN(buf);
3052
3053 /* Loop over all patterns in "name" */
3054 np = name;
3055 while (*np != NUL && (all || !did_one))
3056 {
3057 /* Append the pattern from "name" to buf[]. */
3058 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3059 "\t ");
3060
3061 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003062 {
3063 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003064 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003065 verbose_leave();
3066 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067
3068 /* Expand wildcards, invoke the callback for each match. */
3069 if (gen_expand_wildcards(1, &buf, &num_files, &files,
3070 EW_FILE) == OK)
3071 {
3072 for (i = 0; i < num_files; ++i)
3073 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003074 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075 did_one = TRUE;
3076 if (!all)
3077 break;
3078 }
3079 FreeWild(num_files, files);
3080 }
3081 }
3082 }
3083 }
3084 }
3085 vim_free(buf);
3086 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003087 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003088 {
3089 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003090 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003091 verbose_leave();
3092 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093
3094#ifdef AMIGA
3095 proc->pr_WindowPtr = save_winptr;
3096#endif
3097
3098 return did_one ? OK : FAIL;
3099}
3100
3101#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3102/*
3103 * ":options"
3104 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003105 void
3106ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003107 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003108{
3109 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3110}
3111#endif
3112
3113/*
3114 * ":source {fname}"
3115 */
3116 void
3117ex_source(eap)
3118 exarg_T *eap;
3119{
3120#ifdef FEAT_BROWSE
3121 if (cmdmod.browse)
3122 {
3123 char_u *fname = NULL;
3124
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003125 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3127 if (fname != NULL)
3128 {
3129 cmd_source(fname, eap);
3130 vim_free(fname);
3131 }
3132 }
3133 else
3134#endif
3135 cmd_source(eap->arg, eap);
3136}
3137
3138 static void
3139cmd_source(fname, eap)
3140 char_u *fname;
3141 exarg_T *eap;
3142{
3143 if (*fname == NUL)
3144 EMSG(_(e_argreq));
3145
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003147 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003148 * Need to execute the commands directly. This is required at least
3149 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150 * - ":g" command busy
3151 * - after ":argdo", ":windo" or ":bufdo"
3152 * - another command follows
3153 * - inside a loop
3154 */
3155 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3156#ifdef FEAT_EVAL
3157 || eap->cstack->cs_idx >= 0
3158#endif
3159 );
3160
3161 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003162 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163 EMSG2(_(e_notopen), fname);
3164}
3165
3166/*
3167 * ":source" and associated commands.
3168 */
3169/*
3170 * Structure used to store info for each sourced file.
3171 * It is shared between do_source() and getsourceline().
3172 * This is required, because it needs to be handed to do_cmdline() and
3173 * sourcing can be done recursively.
3174 */
3175struct source_cookie
3176{
3177 FILE *fp; /* opened file for sourcing */
3178 char_u *nextline; /* if not NULL: line that was read ahead */
3179 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003180#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003181 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3182 int error; /* TRUE if LF found after CR-LF */
3183#endif
3184#ifdef FEAT_EVAL
3185 linenr_T breakpoint; /* next line with breakpoint or zero */
3186 char_u *fname; /* name of sourced file */
3187 int dbg_tick; /* debug_tick when breakpoint was set */
3188 int level; /* top nesting level of sourced file */
3189#endif
3190#ifdef FEAT_MBYTE
3191 vimconv_T conv; /* type of conversion */
3192#endif
3193};
3194
3195#ifdef FEAT_EVAL
3196/*
3197 * Return the address holding the next breakpoint line for a source cookie.
3198 */
3199 linenr_T *
3200source_breakpoint(cookie)
3201 void *cookie;
3202{
3203 return &((struct source_cookie *)cookie)->breakpoint;
3204}
3205
3206/*
3207 * Return the address holding the debug tick for a source cookie.
3208 */
3209 int *
3210source_dbg_tick(cookie)
3211 void *cookie;
3212{
3213 return &((struct source_cookie *)cookie)->dbg_tick;
3214}
3215
3216/*
3217 * Return the nesting level for a source cookie.
3218 */
3219 int
3220source_level(cookie)
3221 void *cookie;
3222{
3223 return ((struct source_cookie *)cookie)->level;
3224}
3225#endif
3226
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003227static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003229#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3230# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003231static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003232
3233/*
3234 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003235 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236 */
3237 static FILE *
3238fopen_noinh_readbin(filename)
3239 char *filename;
3240{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003241# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003242 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3243# else
3244 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003245# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003246
3247 if (fd_tmp == -1)
3248 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003249
3250# ifdef HAVE_FD_CLOEXEC
3251 {
3252 int fdflags = fcntl(fd_tmp, F_GETFD);
3253 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003254 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003255 }
3256# endif
3257
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258 return fdopen(fd_tmp, READBIN);
3259}
3260#endif
3261
3262
3263/*
3264 * do_source: Read the file "fname" and execute its lines as EX commands.
3265 *
3266 * This function may be called recursively!
3267 *
3268 * return FAIL if file could not be opened, OK otherwise
3269 */
3270 int
3271do_source(fname, check_other, is_vimrc)
3272 char_u *fname;
3273 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003274 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003275{
3276 struct source_cookie cookie;
3277 char_u *save_sourcing_name;
3278 linenr_T save_sourcing_lnum;
3279 char_u *p;
3280 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003281 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003282 int retval = FAIL;
3283#ifdef FEAT_EVAL
3284 scid_T save_current_SID;
3285 static scid_T last_current_SID = 0;
3286 void *save_funccalp;
3287 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003288 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289# ifdef UNIX
3290 struct stat st;
3291 int stat_ok;
3292# endif
3293#endif
3294#ifdef STARTUPTIME
3295 struct timeval tv_rel;
3296 struct timeval tv_start;
3297#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003298#ifdef FEAT_PROFILE
3299 proftime_T wait_start;
3300#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303 if (p == NULL)
3304 return retval;
3305 fname_exp = fix_fname(p);
3306 vim_free(p);
3307 if (fname_exp == NULL)
3308 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003309 if (mch_isdir(fname_exp))
3310 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003311 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312 goto theend;
3313 }
3314
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003315#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003316 /* Apply SourceCmd autocommands, they should get the file and source it. */
3317 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3318 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3319 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003320 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003321# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003322 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003323# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003324 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003325# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003326 goto theend;
3327 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003328
3329 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003330 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3331#endif
3332
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003333#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3335#else
3336 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3337#endif
3338 if (cookie.fp == NULL && check_other)
3339 {
3340 /*
3341 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3342 * and ".exrc" by "_exrc" or vice versa.
3343 */
3344 p = gettail(fname_exp);
3345 if ((*p == '.' || *p == '_')
3346 && (STRICMP(p + 1, "vimrc") == 0
3347 || STRICMP(p + 1, "gvimrc") == 0
3348 || STRICMP(p + 1, "exrc") == 0))
3349 {
3350 if (*p == '_')
3351 *p = '.';
3352 else
3353 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003354#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003355 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3356#else
3357 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3358#endif
3359 }
3360 }
3361
3362 if (cookie.fp == NULL)
3363 {
3364 if (p_verbose > 0)
3365 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003366 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003367 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003368 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003369 else
3370 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003371 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003372 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373 }
3374 goto theend;
3375 }
3376
3377 /*
3378 * The file exists.
3379 * - In verbose mode, give a message.
3380 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3381 */
3382 if (p_verbose > 1)
3383 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003384 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003386 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387 else
3388 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003389 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003390 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003391 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003392 if (is_vimrc == DOSO_VIMRC)
3393 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3394 else if (is_vimrc == DOSO_GVIMRC)
3395 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003396
3397#ifdef USE_CRNL
3398 /* If no automatic file format: Set default to CR-NL. */
3399 if (*p_ffs == NUL)
3400 cookie.fileformat = EOL_DOS;
3401 else
3402 cookie.fileformat = EOL_UNKNOWN;
3403 cookie.error = FALSE;
3404#endif
3405
3406#ifdef USE_CR
3407 /* If no automatic file format: Set default to CR. */
3408 if (*p_ffs == NUL)
3409 cookie.fileformat = EOL_MAC;
3410 else
3411 cookie.fileformat = EOL_UNKNOWN;
3412 cookie.error = FALSE;
3413#endif
3414
3415 cookie.nextline = NULL;
3416 cookie.finished = FALSE;
3417
3418#ifdef FEAT_EVAL
3419 /*
3420 * Check if this script has a breakpoint.
3421 */
3422 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3423 cookie.fname = fname_exp;
3424 cookie.dbg_tick = debug_tick;
3425
3426 cookie.level = ex_nesting_level;
3427#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003428
3429 /*
3430 * Keep the sourcing name/lnum, for recursive calls.
3431 */
3432 save_sourcing_name = sourcing_name;
3433 sourcing_name = fname_exp;
3434 save_sourcing_lnum = sourcing_lnum;
3435 sourcing_lnum = 0;
3436
Bram Moolenaar73881402009-02-04 16:50:47 +00003437#ifdef FEAT_MBYTE
3438 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3439
3440 /* Read the first line so we can check for a UTF-8 BOM. */
3441 firstline = getsourceline(0, (void *)&cookie, 0);
3442 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3443 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3444 {
3445 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3446 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3447 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003448 if (p == NULL)
3449 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003450 if (p != NULL)
3451 {
3452 vim_free(firstline);
3453 firstline = p;
3454 }
3455 }
3456#endif
3457
Bram Moolenaar071d4272004-06-13 20:20:40 +00003458#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003459 if (time_fd != NULL)
3460 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461#endif
3462
3463#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003464# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003465 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003466 prof_child_enter(&wait_start); /* entering a child now */
3467# endif
3468
3469 /* Don't use local function variables, if called from a function.
3470 * Also starts profiling timer for nested script. */
3471 save_funccalp = save_funccal();
3472
Bram Moolenaar071d4272004-06-13 20:20:40 +00003473 /*
3474 * Check if this script was sourced before to finds its SID.
3475 * If it's new, generate a new SID.
3476 */
3477 save_current_SID = current_SID;
3478# ifdef UNIX
3479 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3480# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003481 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3482 {
3483 si = &SCRIPT_ITEM(current_SID);
3484 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003485 && (
3486# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003487 /* Compare dev/ino when possible, it catches symbolic
3488 * links. Also compare file names, the inode may change
3489 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003490 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003491 && (si->sn_dev == st.st_dev
3492 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003494 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003495 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003496 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003497 if (current_SID == 0)
3498 {
3499 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003500 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3501 == FAIL)
3502 goto almosttheend;
3503 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003504 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003505 ++script_items.ga_len;
3506 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3507# ifdef FEAT_PROFILE
3508 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003509# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003511 si = &SCRIPT_ITEM(current_SID);
3512 si->sn_name = fname_exp;
3513 fname_exp = NULL;
3514# ifdef UNIX
3515 if (stat_ok)
3516 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003517 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003518 si->sn_dev = st.st_dev;
3519 si->sn_ino = st.st_ino;
3520 }
3521 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003522 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003523# endif
3524
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525 /* Allocate the local script variables to use for this script. */
3526 new_script_vars(current_SID);
3527 }
3528
Bram Moolenaar05159a02005-02-26 23:04:13 +00003529# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003530 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003531 {
3532 int forceit;
3533
3534 /* Check if we do profiling for this script. */
3535 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3536 {
3537 script_do_profile(si);
3538 si->sn_pr_force = forceit;
3539 }
3540 if (si->sn_prof_on)
3541 {
3542 ++si->sn_pr_count;
3543 profile_start(&si->sn_pr_start);
3544 profile_zero(&si->sn_pr_children);
3545 }
3546 }
3547# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548#endif
3549
3550 /*
3551 * Call do_cmdline, which will call getsourceline() to get the lines.
3552 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003553 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003556
3557#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003558 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003559 {
3560 /* Get "si" again, "script_items" may have been reallocated. */
3561 si = &SCRIPT_ITEM(current_SID);
3562 if (si->sn_prof_on)
3563 {
3564 profile_end(&si->sn_pr_start);
3565 profile_sub_wait(&wait_start, &si->sn_pr_start);
3566 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003567 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3568 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003569 }
3570 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571#endif
3572
3573 if (got_int)
3574 EMSG(_(e_interr));
3575 sourcing_name = save_sourcing_name;
3576 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003577 if (p_verbose > 1)
3578 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003579 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003580 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003581 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003582 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003583 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584 }
3585#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003586 if (time_fd != NULL)
3587 {
3588 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3589 time_msg((char *)IObuff, &tv_start);
3590 time_pop(&tv_rel);
3591 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592#endif
3593
3594#ifdef FEAT_EVAL
3595 /*
3596 * After a "finish" in debug mode, need to break at first command of next
3597 * sourced file.
3598 */
3599 if (save_debug_break_level > ex_nesting_level
3600 && debug_break_level == ex_nesting_level)
3601 ++debug_break_level;
3602#endif
3603
Bram Moolenaar05159a02005-02-26 23:04:13 +00003604#ifdef FEAT_EVAL
3605almosttheend:
3606 current_SID = save_current_SID;
3607 restore_funccal(save_funccalp);
3608# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003609 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003610 prof_child_exit(&wait_start); /* leaving a child now */
3611# endif
3612#endif
3613 fclose(cookie.fp);
3614 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003615 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003616#ifdef FEAT_MBYTE
3617 convert_setup(&cookie.conv, NULL, NULL);
3618#endif
3619
Bram Moolenaar071d4272004-06-13 20:20:40 +00003620theend:
3621 vim_free(fname_exp);
3622 return retval;
3623}
3624
3625#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003626
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627/*
3628 * ":scriptnames"
3629 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630 void
3631ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003632 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003633{
3634 int i;
3635
Bram Moolenaar05159a02005-02-26 23:04:13 +00003636 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3637 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003638 {
3639 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3640 NameBuff, MAXPATHL, TRUE);
3641 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003642 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003643}
3644
3645# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3646/*
3647 * Fix slashes in the list of script names for 'shellslash'.
3648 */
3649 void
3650scriptnames_slash_adjust()
3651{
3652 int i;
3653
Bram Moolenaar05159a02005-02-26 23:04:13 +00003654 for (i = 1; i <= script_items.ga_len; ++i)
3655 if (SCRIPT_ITEM(i).sn_name != NULL)
3656 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003657}
3658# endif
3659
3660/*
3661 * Get a pointer to a script name. Used for ":verbose set".
3662 */
3663 char_u *
3664get_scriptname(id)
3665 scid_T id;
3666{
3667 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003668 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003670 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003672 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003674 return (char_u *)_("environment variable");
3675 if (id == SID_ERROR)
3676 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003677 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003679
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003680# if defined(EXITFREE) || defined(PROTO)
3681 void
3682free_scriptnames()
3683{
3684 int i;
3685
3686 for (i = script_items.ga_len; i > 0; --i)
3687 vim_free(SCRIPT_ITEM(i).sn_name);
3688 ga_clear(&script_items);
3689}
3690# endif
3691
Bram Moolenaar071d4272004-06-13 20:20:40 +00003692#endif
3693
3694#if defined(USE_CR) || defined(PROTO)
3695
3696# if defined(__MSL__) && (__MSL__ >= 22)
3697/*
3698 * Newer version of the Metrowerks library handle DOS and UNIX files
3699 * without help.
3700 * Test with earlier versions, MSL 2.2 is the library supplied with
3701 * Codewarrior Pro 2.
3702 */
3703 char *
3704fgets_cr(s, n, stream)
3705 char *s;
3706 int n;
3707 FILE *stream;
3708{
3709 return fgets(s, n, stream);
3710}
3711# else
3712/*
3713 * Version of fgets() which also works for lines ending in a <CR> only
3714 * (Macintosh format).
3715 * For older versions of the Metrowerks library.
3716 * At least CodeWarrior 9 needed this code.
3717 */
3718 char *
3719fgets_cr(s, n, stream)
3720 char *s;
3721 int n;
3722 FILE *stream;
3723{
3724 int c = 0;
3725 int char_read = 0;
3726
3727 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3728 {
3729 c = fgetc(stream);
3730 s[char_read++] = c;
3731 /* If the file is in DOS format, we need to skip a NL after a CR. I
3732 * thought it was the other way around, but this appears to work... */
3733 if (c == '\n')
3734 {
3735 c = fgetc(stream);
3736 if (c != '\r')
3737 ungetc(c, stream);
3738 }
3739 }
3740
3741 s[char_read] = 0;
3742 if (char_read == 0)
3743 return NULL;
3744
3745 if (feof(stream) && char_read == 1)
3746 return NULL;
3747
3748 return s;
3749}
3750# endif
3751#endif
3752
3753/*
3754 * Get one full line from a sourced file.
3755 * Called by do_cmdline() when it's called from do_source().
3756 *
3757 * Return a pointer to the line in allocated memory.
3758 * Return NULL for end-of-file or some error.
3759 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003760 char_u *
3761getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003762 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003763 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003764 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765{
3766 struct source_cookie *sp = (struct source_cookie *)cookie;
3767 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003768 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769
3770#ifdef FEAT_EVAL
3771 /* If breakpoints have been added/deleted need to check for it. */
3772 if (sp->dbg_tick < debug_tick)
3773 {
3774 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3775 sp->dbg_tick = debug_tick;
3776 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003777# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003778 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003779 script_line_end();
3780# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003781#endif
3782 /*
3783 * Get current line. If there is a read-ahead line, use it, otherwise get
3784 * one now.
3785 */
3786 if (sp->finished)
3787 line = NULL;
3788 else if (sp->nextline == NULL)
3789 line = get_one_sourceline(sp);
3790 else
3791 {
3792 line = sp->nextline;
3793 sp->nextline = NULL;
3794 ++sourcing_lnum;
3795 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003796#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003797 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003798 script_line_start();
3799#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003800
3801 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3802 * contain the 'C' flag. */
3803 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3804 {
3805 /* compensate for the one line read-ahead */
3806 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003807
3808 /* Get the next line and concatenate it when it starts with a
3809 * backslash. We always need to read the next line, keep it in
3810 * sp->nextline. */
3811 sp->nextline = get_one_sourceline(sp);
3812 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003814 garray_T ga;
3815
Bram Moolenaarb549a732012-02-22 18:29:33 +01003816 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003817 ga_concat(&ga, line);
3818 ga_concat(&ga, p + 1);
3819 for (;;)
3820 {
3821 vim_free(sp->nextline);
3822 sp->nextline = get_one_sourceline(sp);
3823 if (sp->nextline == NULL)
3824 break;
3825 p = skipwhite(sp->nextline);
3826 if (*p != '\\')
3827 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003828 /* Adjust the growsize to the current length to speed up
3829 * concatenating many lines. */
3830 if (ga.ga_len > 400)
3831 {
3832 if (ga.ga_len > 8000)
3833 ga.ga_growsize = 8000;
3834 else
3835 ga.ga_growsize = ga.ga_len;
3836 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003837 ga_concat(&ga, p + 1);
3838 }
3839 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003840 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003841 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003842 }
3843 }
3844
3845#ifdef FEAT_MBYTE
3846 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3847 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003848 char_u *s;
3849
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850 /* Convert the encoding of the script line. */
3851 s = string_convert(&sp->conv, line, NULL);
3852 if (s != NULL)
3853 {
3854 vim_free(line);
3855 line = s;
3856 }
3857 }
3858#endif
3859
3860#ifdef FEAT_EVAL
3861 /* Did we encounter a breakpoint? */
3862 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3863 {
3864 dbg_breakpoint(sp->fname, sourcing_lnum);
3865 /* Find next breakpoint. */
3866 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3867 sp->dbg_tick = debug_tick;
3868 }
3869#endif
3870
3871 return line;
3872}
3873
3874 static char_u *
3875get_one_sourceline(sp)
3876 struct source_cookie *sp;
3877{
3878 garray_T ga;
3879 int len;
3880 int c;
3881 char_u *buf;
3882#ifdef USE_CRNL
3883 int has_cr; /* CR-LF found */
3884#endif
3885#ifdef USE_CR
3886 char_u *scan;
3887#endif
3888 int have_read = FALSE;
3889
3890 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003891 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003892
3893 /*
3894 * Loop until there is a finished line (or end-of-file).
3895 */
3896 sourcing_lnum++;
3897 for (;;)
3898 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003899 /* make room to read at least 120 (more) characters */
3900 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 break;
3902 buf = (char_u *)ga.ga_data;
3903
3904#ifdef USE_CR
3905 if (sp->fileformat == EOL_MAC)
3906 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003907 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3908 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003909 break;
3910 }
3911 else
3912#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003913 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3914 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003915 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003916 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917#ifdef USE_CRNL
3918 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3919 * CTRL-Z by its own, or after a NL. */
3920 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3921 && sp->fileformat == EOL_DOS
3922 && buf[len - 1] == Ctrl_Z)
3923 {
3924 buf[len - 1] = NUL;
3925 break;
3926 }
3927#endif
3928
3929#ifdef USE_CR
3930 /* If the read doesn't stop on a new line, and there's
3931 * some CR then we assume a Mac format */
3932 if (sp->fileformat == EOL_UNKNOWN)
3933 {
3934 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3935 sp->fileformat = EOL_MAC;
3936 else
3937 sp->fileformat = EOL_UNIX;
3938 }
3939
3940 if (sp->fileformat == EOL_MAC)
3941 {
3942 scan = vim_strchr(buf, '\r');
3943
3944 if (scan != NULL)
3945 {
3946 *scan = '\n';
3947 if (*(scan + 1) != 0)
3948 {
3949 *(scan + 1) = 0;
3950 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3951 }
3952 }
3953 len = STRLEN(buf);
3954 }
3955#endif
3956
3957 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003958 ga.ga_len = len;
3959
3960 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003961 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003962 continue;
3963
3964 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3965 {
3966#ifdef USE_CRNL
3967 has_cr = (len >= 2 && buf[len - 2] == '\r');
3968 if (sp->fileformat == EOL_UNKNOWN)
3969 {
3970 if (has_cr)
3971 sp->fileformat = EOL_DOS;
3972 else
3973 sp->fileformat = EOL_UNIX;
3974 }
3975
3976 if (sp->fileformat == EOL_DOS)
3977 {
3978 if (has_cr) /* replace trailing CR */
3979 {
3980 buf[len - 2] = '\n';
3981 --len;
3982 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003983 }
3984 else /* lines like ":map xx yy^M" will have failed */
3985 {
3986 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003987 {
3988 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003989 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003990 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003991 sp->error = TRUE;
3992 sp->fileformat = EOL_UNIX;
3993 }
3994 }
3995#endif
3996 /* The '\n' is escaped if there is an odd number of ^V's just
3997 * before it, first set "c" just before the 'V's and then check
3998 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3999 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4000 ;
4001 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4002 {
4003 sourcing_lnum++;
4004 continue;
4005 }
4006
4007 buf[len - 1] = NUL; /* remove the NL */
4008 }
4009
4010 /*
4011 * Check for ^C here now and then, so recursive :so can be broken.
4012 */
4013 line_breakcheck();
4014 break;
4015 }
4016
4017 if (have_read)
4018 return (char_u *)ga.ga_data;
4019
4020 vim_free(ga.ga_data);
4021 return NULL;
4022}
4023
Bram Moolenaar05159a02005-02-26 23:04:13 +00004024#if defined(FEAT_PROFILE) || defined(PROTO)
4025/*
4026 * Called when starting to read a script line.
4027 * "sourcing_lnum" must be correct!
4028 * When skipping lines it may not actually be executed, but we won't find out
4029 * until later and we need to store the time now.
4030 */
4031 void
4032script_line_start()
4033{
4034 scriptitem_T *si;
4035 sn_prl_T *pp;
4036
4037 if (current_SID <= 0 || current_SID > script_items.ga_len)
4038 return;
4039 si = &SCRIPT_ITEM(current_SID);
4040 if (si->sn_prof_on && sourcing_lnum >= 1)
4041 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004042 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004043 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004044 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004045 si->sn_prl_idx = sourcing_lnum - 1;
4046 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4047 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4048 {
4049 /* Zero counters for a line that was not used before. */
4050 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4051 pp->snp_count = 0;
4052 profile_zero(&pp->sn_prl_total);
4053 profile_zero(&pp->sn_prl_self);
4054 ++si->sn_prl_ga.ga_len;
4055 }
4056 si->sn_prl_execed = FALSE;
4057 profile_start(&si->sn_prl_start);
4058 profile_zero(&si->sn_prl_children);
4059 profile_get_wait(&si->sn_prl_wait);
4060 }
4061}
4062
4063/*
4064 * Called when actually executing a function line.
4065 */
4066 void
4067script_line_exec()
4068{
4069 scriptitem_T *si;
4070
4071 if (current_SID <= 0 || current_SID > script_items.ga_len)
4072 return;
4073 si = &SCRIPT_ITEM(current_SID);
4074 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4075 si->sn_prl_execed = TRUE;
4076}
4077
4078/*
4079 * Called when done with a function line.
4080 */
4081 void
4082script_line_end()
4083{
4084 scriptitem_T *si;
4085 sn_prl_T *pp;
4086
4087 if (current_SID <= 0 || current_SID > script_items.ga_len)
4088 return;
4089 si = &SCRIPT_ITEM(current_SID);
4090 if (si->sn_prof_on && si->sn_prl_idx >= 0
4091 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4092 {
4093 if (si->sn_prl_execed)
4094 {
4095 pp = &PRL_ITEM(si, si->sn_prl_idx);
4096 ++pp->snp_count;
4097 profile_end(&si->sn_prl_start);
4098 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004099 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004100 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4101 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004102 }
4103 si->sn_prl_idx = -1;
4104 }
4105}
4106#endif
4107
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108/*
4109 * ":scriptencoding": Set encoding conversion for a sourced script.
4110 * Without the multi-byte feature it's simply ignored.
4111 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 void
4113ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004114 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115{
4116#ifdef FEAT_MBYTE
4117 struct source_cookie *sp;
4118 char_u *name;
4119
4120 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4121 {
4122 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4123 return;
4124 }
4125
4126 if (*eap->arg != NUL)
4127 {
4128 name = enc_canonize(eap->arg);
4129 if (name == NULL) /* out of memory */
4130 return;
4131 }
4132 else
4133 name = eap->arg;
4134
4135 /* Setup for conversion from the specified encoding to 'encoding'. */
4136 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4137 convert_setup(&sp->conv, name, p_enc);
4138
4139 if (name != eap->arg)
4140 vim_free(name);
4141#endif
4142}
4143
4144#if defined(FEAT_EVAL) || defined(PROTO)
4145/*
4146 * ":finish": Mark a sourced file as finished.
4147 */
4148 void
4149ex_finish(eap)
4150 exarg_T *eap;
4151{
4152 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4153 do_finish(eap, FALSE);
4154 else
4155 EMSG(_("E168: :finish used outside of a sourced file"));
4156}
4157
4158/*
4159 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4160 * Also called for a pending finish at the ":endtry" or after returning from
4161 * an extra do_cmdline(). "reanimate" is used in the latter case.
4162 */
4163 void
4164do_finish(eap, reanimate)
4165 exarg_T *eap;
4166 int reanimate;
4167{
4168 int idx;
4169
4170 if (reanimate)
4171 ((struct source_cookie *)getline_cookie(eap->getline,
4172 eap->cookie))->finished = FALSE;
4173
4174 /*
4175 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4176 * not in its finally clause (which then is to be executed next) is found.
4177 * In this case, make the ":finish" pending for execution at the ":endtry".
4178 * Otherwise, finish normally.
4179 */
4180 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4181 if (idx >= 0)
4182 {
4183 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4184 report_make_pending(CSTP_FINISH, NULL);
4185 }
4186 else
4187 ((struct source_cookie *)getline_cookie(eap->getline,
4188 eap->cookie))->finished = TRUE;
4189}
4190
4191
4192/*
4193 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4194 * message for missing ":endif".
4195 * Return FALSE when not sourcing a file.
4196 */
4197 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00004198source_finished(fgetline, cookie)
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004199 char_u *(*fgetline)(int, void *, int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004200 void *cookie;
4201{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004202 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004203 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004204 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004205}
4206#endif
4207
4208#if defined(FEAT_LISTCMDS) || defined(PROTO)
4209/*
4210 * ":checktime [buffer]"
4211 */
4212 void
4213ex_checktime(eap)
4214 exarg_T *eap;
4215{
4216 buf_T *buf;
4217 int save_no_check_timestamps = no_check_timestamps;
4218
4219 no_check_timestamps = 0;
4220 if (eap->addr_count == 0) /* default is all buffers */
4221 check_timestamps(FALSE);
4222 else
4223 {
4224 buf = buflist_findnr((int)eap->line2);
4225 if (buf != NULL) /* cannot happen? */
4226 (void)buf_check_timestamp(buf, FALSE);
4227 }
4228 no_check_timestamps = save_no_check_timestamps;
4229}
4230#endif
4231
Bram Moolenaar071d4272004-06-13 20:20:40 +00004232#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4233 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004234# define HAVE_GET_LOCALE_VAL
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004235static char *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004236
4237 static char *
4238get_locale_val(what)
4239 int what;
4240{
4241 char *loc;
4242
4243 /* Obtain the locale value from the libraries. For DJGPP this is
4244 * redefined and it doesn't use the arguments. */
4245 loc = setlocale(what, NULL);
4246
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004247# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004248 if (loc != NULL)
4249 {
4250 char_u *p;
4251
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004252 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4253 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254 p = vim_strchr(loc, '=');
4255 if (p != NULL)
4256 {
4257 loc = ++p;
4258 while (*p != NUL) /* remove trailing newline */
4259 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004260 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 {
4262 *p = NUL;
4263 break;
4264 }
4265 ++p;
4266 }
4267 }
4268 }
4269# endif
4270
4271 return loc;
4272}
4273#endif
4274
4275
4276#ifdef WIN32
4277/*
4278 * On MS-Windows locale names are strings like "German_Germany.1252", but
4279 * gettext expects "de". Try to translate one into another here for a few
4280 * supported languages.
4281 */
4282 static char_u *
4283gettext_lang(char_u *name)
4284{
4285 int i;
4286 static char *(mtable[]) = {
4287 "afrikaans", "af",
4288 "czech", "cs",
4289 "dutch", "nl",
4290 "german", "de",
4291 "english_united kingdom", "en_GB",
4292 "spanish", "es",
4293 "french", "fr",
4294 "italian", "it",
4295 "japanese", "ja",
4296 "korean", "ko",
4297 "norwegian", "no",
4298 "polish", "pl",
4299 "russian", "ru",
4300 "slovak", "sk",
4301 "swedish", "sv",
4302 "ukrainian", "uk",
4303 "chinese_china", "zh_CN",
4304 "chinese_taiwan", "zh_TW",
4305 NULL};
4306
4307 for (i = 0; mtable[i] != NULL; i += 2)
4308 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4309 return mtable[i + 1];
4310 return name;
4311}
4312#endif
4313
4314#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4315/*
4316 * Obtain the current messages language. Used to set the default for
4317 * 'helplang'. May return NULL or an empty string.
4318 */
4319 char_u *
4320get_mess_lang()
4321{
4322 char_u *p;
4323
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004324# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004325# if defined(LC_MESSAGES)
4326 p = (char_u *)get_locale_val(LC_MESSAGES);
4327# else
4328 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004329 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4330 * and LC_MONETARY may be set differently for a Japanese working in the
4331 * US. */
4332 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004333# endif
4334# else
4335 p = mch_getenv((char_u *)"LC_ALL");
4336 if (p == NULL || *p == NUL)
4337 {
4338 p = mch_getenv((char_u *)"LC_MESSAGES");
4339 if (p == NULL || *p == NUL)
4340 p = mch_getenv((char_u *)"LANG");
4341 }
4342# endif
4343# ifdef WIN32
4344 p = gettext_lang(p);
4345# endif
4346 return p;
4347}
4348#endif
4349
Bram Moolenaardef9e822004-12-31 20:58:58 +00004350/* Complicated #if; matches with where get_mess_env() is used below. */
4351#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4352 && defined(LC_MESSAGES))) \
4353 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4354 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4355 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004356static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357
4358/*
4359 * Get the language used for messages from the environment.
4360 */
4361 static char_u *
4362get_mess_env()
4363{
4364 char_u *p;
4365
4366 p = mch_getenv((char_u *)"LC_ALL");
4367 if (p == NULL || *p == NUL)
4368 {
4369 p = mch_getenv((char_u *)"LC_MESSAGES");
4370 if (p == NULL || *p == NUL)
4371 {
4372 p = mch_getenv((char_u *)"LANG");
4373 if (p != NULL && VIM_ISDIGIT(*p))
4374 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004375# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004376 if (p == NULL || *p == NUL)
4377 p = (char_u *)get_locale_val(LC_CTYPE);
4378# endif
4379 }
4380 }
4381 return p;
4382}
4383#endif
4384
4385#if defined(FEAT_EVAL) || defined(PROTO)
4386
4387/*
4388 * Set the "v:lang" variable according to the current locale setting.
4389 * Also do "v:lc_time"and "v:ctype".
4390 */
4391 void
4392set_lang_var()
4393{
4394 char_u *loc;
4395
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004396# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397 loc = (char_u *)get_locale_val(LC_CTYPE);
4398# else
4399 /* setlocale() not supported: use the default value */
4400 loc = (char_u *)"C";
4401# endif
4402 set_vim_var_string(VV_CTYPE, loc, -1);
4403
4404 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4405 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004406# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004407 loc = (char_u *)get_locale_val(LC_MESSAGES);
4408# else
4409 loc = get_mess_env();
4410# endif
4411 set_vim_var_string(VV_LANG, loc, -1);
4412
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004413# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414 loc = (char_u *)get_locale_val(LC_TIME);
4415# endif
4416 set_vim_var_string(VV_LC_TIME, loc, -1);
4417}
4418#endif
4419
4420#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4421 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4422/*
4423 * ":language": Set the language (locale).
4424 */
4425 void
4426ex_language(eap)
4427 exarg_T *eap;
4428{
4429 char *loc;
4430 char_u *p;
4431 char_u *name;
4432 int what = LC_ALL;
4433 char *whatstr = "";
4434#ifdef LC_MESSAGES
4435# define VIM_LC_MESSAGES LC_MESSAGES
4436#else
4437# define VIM_LC_MESSAGES 6789
4438#endif
4439
4440 name = eap->arg;
4441
4442 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4443 * Allow abbreviation, but require at least 3 characters to avoid
4444 * confusion with a two letter language name "me" or "ct". */
4445 p = skiptowhite(eap->arg);
4446 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4447 {
4448 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4449 {
4450 what = VIM_LC_MESSAGES;
4451 name = skipwhite(p);
4452 whatstr = "messages ";
4453 }
4454 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4455 {
4456 what = LC_CTYPE;
4457 name = skipwhite(p);
4458 whatstr = "ctype ";
4459 }
4460 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4461 {
4462 what = LC_TIME;
4463 name = skipwhite(p);
4464 whatstr = "time ";
4465 }
4466 }
4467
4468 if (*name == NUL)
4469 {
4470#ifndef LC_MESSAGES
4471 if (what == VIM_LC_MESSAGES)
4472 p = get_mess_env();
4473 else
4474#endif
4475 p = (char_u *)setlocale(what, NULL);
4476 if (p == NULL || *p == NUL)
4477 p = (char_u *)"Unknown";
4478 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4479 }
4480 else
4481 {
4482#ifndef LC_MESSAGES
4483 if (what == VIM_LC_MESSAGES)
4484 loc = "";
4485 else
4486#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004487 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004489#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4490 /* Make sure strtod() uses a decimal point, not a comma. */
4491 setlocale(LC_NUMERIC, "C");
4492#endif
4493 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494 if (loc == NULL)
4495 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4496 else
4497 {
4498#ifdef HAVE_NL_MSG_CAT_CNTR
4499 /* Need to do this for GNU gettext, otherwise cached translations
4500 * will be used again. */
4501 extern int _nl_msg_cat_cntr;
4502
4503 ++_nl_msg_cat_cntr;
4504#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004505 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004506 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4507
4508 if (what != LC_TIME)
4509 {
4510 /* Tell gettext() what to translate to. It apparently doesn't
4511 * use the currently effective locale. Also do this when
4512 * FEAT_GETTEXT isn't defined, so that shell commands use this
4513 * value. */
4514 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004515 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004516 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004517
4518 /* Clear $LANGUAGE because GNU gettext uses it. */
4519 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004520# ifdef WIN32
4521 /* Apparently MS-Windows printf() may cause a crash when
4522 * we give it 8-bit text while it's expecting text in the
4523 * current locale. This call avoids that. */
4524 setlocale(LC_CTYPE, "C");
4525# endif
4526 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004527 if (what != LC_CTYPE)
4528 {
4529 char_u *mname;
4530#ifdef WIN32
4531 mname = gettext_lang(name);
4532#else
4533 mname = name;
4534#endif
4535 vim_setenv((char_u *)"LC_MESSAGES", mname);
4536#ifdef FEAT_MULTI_LANG
4537 set_helplang_default(mname);
4538#endif
4539 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540 }
4541
4542# ifdef FEAT_EVAL
4543 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4544 set_lang_var();
4545# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004546# ifdef FEAT_TITLE
4547 maketitle();
4548# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 }
4550 }
4551}
4552
4553# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004554
4555static char_u **locales = NULL; /* Array of all available locales */
4556static int did_init_locales = FALSE;
4557
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004558static void init_locales(void);
4559static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004560
4561/*
4562 * Lazy initialization of all available locales.
4563 */
4564 static void
4565init_locales()
4566{
4567 if (!did_init_locales)
4568 {
4569 did_init_locales = TRUE;
4570 locales = find_locales();
4571 }
4572}
4573
4574/* Return an array of strings for all available locales + NULL for the
4575 * last element. Return NULL in case of error. */
4576 static char_u **
4577find_locales()
4578{
4579 garray_T locales_ga;
4580 char_u *loc;
4581
4582 /* Find all available locales by running command "locale -a". If this
4583 * doesn't work we won't have completion. */
4584 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004585 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004586 if (locale_a == NULL)
4587 return NULL;
4588 ga_init2(&locales_ga, sizeof(char_u *), 20);
4589
4590 /* Transform locale_a string where each locale is separated by "\n"
4591 * into an array of locale strings. */
4592 loc = (char_u *)strtok((char *)locale_a, "\n");
4593
4594 while (loc != NULL)
4595 {
4596 if (ga_grow(&locales_ga, 1) == FAIL)
4597 break;
4598 loc = vim_strsave(loc);
4599 if (loc == NULL)
4600 break;
4601
4602 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4603 loc = (char_u *)strtok(NULL, "\n");
4604 }
4605 vim_free(locale_a);
4606 if (ga_grow(&locales_ga, 1) == FAIL)
4607 {
4608 ga_clear(&locales_ga);
4609 return NULL;
4610 }
4611 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4612 return (char_u **)locales_ga.ga_data;
4613}
4614
4615# if defined(EXITFREE) || defined(PROTO)
4616 void
4617free_locales()
4618{
4619 int i;
4620 if (locales != NULL)
4621 {
4622 for (i = 0; locales[i] != NULL; i++)
4623 vim_free(locales[i]);
4624 vim_free(locales);
4625 locales = NULL;
4626 }
4627}
4628# endif
4629
Bram Moolenaar071d4272004-06-13 20:20:40 +00004630/*
4631 * Function given to ExpandGeneric() to obtain the possible arguments of the
4632 * ":language" command.
4633 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004634 char_u *
4635get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004636 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004637 int idx;
4638{
4639 if (idx == 0)
4640 return (char_u *)"messages";
4641 if (idx == 1)
4642 return (char_u *)"ctype";
4643 if (idx == 2)
4644 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004645
4646 init_locales();
4647 if (locales == NULL)
4648 return NULL;
4649 return locales[idx - 3];
4650}
4651
4652/*
4653 * Function given to ExpandGeneric() to obtain the available locales.
4654 */
4655 char_u *
4656get_locales(xp, idx)
4657 expand_T *xp UNUSED;
4658 int idx;
4659{
4660 init_locales();
4661 if (locales == NULL)
4662 return NULL;
4663 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664}
4665# endif
4666
4667#endif