blob: 012a1af222bd430d1dfe24bf5a47706f090273b9 [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
17static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
18
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 Moolenaar05159a02005-02-26 23:04:13 +0000565static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
566static linenr_T debuggy_find __ARGS((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 */
1136static void script_do_profile __ARGS((scriptitem_T *si));
1137static void script_dump_profile __ARGS((FILE *fd));
1138static 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 Moolenaar970a1b82012-03-23 18:39:18 +01001760static void add_bufnum __ARGS((int *bufnrs, int *bufnump, int nr));
1761
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 Moolenaar1cd871b2004-12-19 22:46:22 +00001954static char_u *do_one_arg __ARGS((char_u *str));
1955static int do_arglist __ARGS((char_u *str, int what, int after));
1956static void alist_check_arg_idx __ARGS((void));
1957static int editing_arg_idx __ARGS((win_T *win));
1958#ifdef FEAT_LISTCMDS
1959static int alist_add_list __ARGS((int count, char_u **files, int after));
1960#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 /*
2093 * Collect all file name arguments in "new_ga".
2094 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002095 if (get_arglist(&new_ga, str) == FAIL)
2096 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002097
2098#ifdef FEAT_LISTCMDS
2099 if (what == AL_DEL)
2100 {
2101 regmatch_T regmatch;
2102 int didone;
2103
2104 /*
2105 * Delete the items: use each item as a regexp and find a match in the
2106 * argument list.
2107 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002108 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002109 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2110 {
2111 p = ((char_u **)new_ga.ga_data)[i];
2112 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2113 if (p == NULL)
2114 break;
2115 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2116 if (regmatch.regprog == NULL)
2117 {
2118 vim_free(p);
2119 break;
2120 }
2121
2122 didone = FALSE;
2123 for (match = 0; match < ARGCOUNT; ++match)
2124 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2125 (colnr_T)0))
2126 {
2127 didone = TRUE;
2128 vim_free(ARGLIST[match].ae_fname);
2129 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2130 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2131 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132 if (curwin->w_arg_idx > match)
2133 --curwin->w_arg_idx;
2134 --match;
2135 }
2136
Bram Moolenaar473de612013-06-08 18:19:48 +02002137 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002138 vim_free(p);
2139 if (!didone)
2140 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2141 }
2142 ga_clear(&new_ga);
2143 }
2144 else
2145#endif
2146 {
2147 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2148 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2149 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002150 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002151 {
2152 EMSG(_(e_nomatch));
2153 return FAIL;
2154 }
2155
2156#ifdef FEAT_LISTCMDS
2157 if (what == AL_ADD)
2158 {
2159 (void)alist_add_list(exp_count, exp_files, after);
2160 vim_free(exp_files);
2161 }
2162 else /* what == AL_SET */
2163#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002164 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 }
2166
2167 alist_check_arg_idx();
2168
2169 return OK;
2170}
2171
2172/*
2173 * Check the validity of the arg_idx for each other window.
2174 */
2175 static void
2176alist_check_arg_idx()
2177{
2178#ifdef FEAT_WINDOWS
2179 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002180 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002181
Bram Moolenaarf740b292006-02-16 22:11:02 +00002182 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183 if (win->w_alist == curwin->w_alist)
2184 check_arg_idx(win);
2185#else
2186 check_arg_idx(curwin);
2187#endif
2188}
2189
2190/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002191 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002192 * index.
2193 */
2194 static int
2195editing_arg_idx(win)
2196 win_T *win;
2197{
2198 return !(win->w_arg_idx >= WARGCOUNT(win)
2199 || (win->w_buffer->b_fnum
2200 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2201 && (win->w_buffer->b_ffname == NULL
2202 || !(fullpathcmp(
2203 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2204 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2205}
2206
2207/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002208 * Check if window "win" is editing the w_arg_idx file in its argument list.
2209 */
2210 void
2211check_arg_idx(win)
2212 win_T *win;
2213{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002214 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002215 {
2216 /* We are not editing the current entry in the argument list.
2217 * Set "arg_had_last" if we are editing the last one. */
2218 win->w_arg_idx_invalid = TRUE;
2219 if (win->w_arg_idx != WARGCOUNT(win) - 1
2220 && arg_had_last == FALSE
2221#ifdef FEAT_WINDOWS
2222 && ALIST(win) == &global_alist
2223#endif
2224 && GARGCOUNT > 0
2225 && win->w_arg_idx < GARGCOUNT
2226 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2227 || (win->w_buffer->b_ffname != NULL
2228 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2229 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2230 arg_had_last = TRUE;
2231 }
2232 else
2233 {
2234 /* We are editing the current entry in the argument list.
2235 * Set "arg_had_last" if it's also the last one */
2236 win->w_arg_idx_invalid = FALSE;
2237 if (win->w_arg_idx == WARGCOUNT(win) - 1
2238#ifdef FEAT_WINDOWS
2239 && win->w_alist == &global_alist
2240#endif
2241 )
2242 arg_had_last = TRUE;
2243 }
2244}
2245
2246/*
2247 * ":args", ":argslocal" and ":argsglobal".
2248 */
2249 void
2250ex_args(eap)
2251 exarg_T *eap;
2252{
2253 int i;
2254
2255 if (eap->cmdidx != CMD_args)
2256 {
2257#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2258 alist_unlink(ALIST(curwin));
2259 if (eap->cmdidx == CMD_argglobal)
2260 ALIST(curwin) = &global_alist;
2261 else /* eap->cmdidx == CMD_arglocal */
2262 alist_new();
2263#else
2264 ex_ni(eap);
2265 return;
2266#endif
2267 }
2268
2269 if (!ends_excmd(*eap->arg))
2270 {
2271 /*
2272 * ":args file ..": define new argument list, handle like ":next"
2273 * Also for ":argslocal file .." and ":argsglobal file ..".
2274 */
2275 ex_next(eap);
2276 }
2277 else
2278#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2279 if (eap->cmdidx == CMD_args)
2280#endif
2281 {
2282 /*
2283 * ":args": list arguments.
2284 */
2285 if (ARGCOUNT > 0)
2286 {
2287 /* Overwrite the command, for a short list there is no scrolling
2288 * required and no wait_return(). */
2289 gotocmdline(TRUE);
2290 for (i = 0; i < ARGCOUNT; ++i)
2291 {
2292 if (i == curwin->w_arg_idx)
2293 msg_putchar('[');
2294 msg_outtrans(alist_name(&ARGLIST[i]));
2295 if (i == curwin->w_arg_idx)
2296 msg_putchar(']');
2297 msg_putchar(' ');
2298 }
2299 }
2300 }
2301#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2302 else if (eap->cmdidx == CMD_arglocal)
2303 {
2304 garray_T *gap = &curwin->w_alist->al_ga;
2305
2306 /*
2307 * ":argslocal": make a local copy of the global argument list.
2308 */
2309 if (ga_grow(gap, GARGCOUNT) == OK)
2310 for (i = 0; i < GARGCOUNT; ++i)
2311 if (GARGLIST[i].ae_fname != NULL)
2312 {
2313 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2314 vim_strsave(GARGLIST[i].ae_fname);
2315 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2316 GARGLIST[i].ae_fnum;
2317 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002318 }
2319 }
2320#endif
2321}
2322
2323/*
2324 * ":previous", ":sprevious", ":Next" and ":sNext".
2325 */
2326 void
2327ex_previous(eap)
2328 exarg_T *eap;
2329{
2330 /* If past the last one already, go to the last one. */
2331 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2332 do_argfile(eap, ARGCOUNT - 1);
2333 else
2334 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2335}
2336
2337/*
2338 * ":rewind", ":first", ":sfirst" and ":srewind".
2339 */
2340 void
2341ex_rewind(eap)
2342 exarg_T *eap;
2343{
2344 do_argfile(eap, 0);
2345}
2346
2347/*
2348 * ":last" and ":slast".
2349 */
2350 void
2351ex_last(eap)
2352 exarg_T *eap;
2353{
2354 do_argfile(eap, ARGCOUNT - 1);
2355}
2356
2357/*
2358 * ":argument" and ":sargument".
2359 */
2360 void
2361ex_argument(eap)
2362 exarg_T *eap;
2363{
2364 int i;
2365
2366 if (eap->addr_count > 0)
2367 i = eap->line2 - 1;
2368 else
2369 i = curwin->w_arg_idx;
2370 do_argfile(eap, i);
2371}
2372
2373/*
2374 * Edit file "argn" of the argument lists.
2375 */
2376 void
2377do_argfile(eap, argn)
2378 exarg_T *eap;
2379 int argn;
2380{
2381 int other;
2382 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002383 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384
2385 if (argn < 0 || argn >= ARGCOUNT)
2386 {
2387 if (ARGCOUNT <= 1)
2388 EMSG(_("E163: There is only one file to edit"));
2389 else if (argn < 0)
2390 EMSG(_("E164: Cannot go before first file"));
2391 else
2392 EMSG(_("E165: Cannot go beyond last file"));
2393 }
2394 else
2395 {
2396 setpcmark();
2397#ifdef FEAT_GUI
2398 need_mouse_correct = TRUE;
2399#endif
2400
2401#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002402 /* split window or create new tab page first */
2403 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404 {
2405 if (win_split(0, 0) == FAIL)
2406 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002407 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 }
2409 else
2410#endif
2411 {
2412 /*
2413 * if 'hidden' set, only check for changed file when re-editing
2414 * the same buffer
2415 */
2416 other = TRUE;
2417 if (P_HID(curbuf))
2418 {
2419 p = fix_fname(alist_name(&ARGLIST[argn]));
2420 other = otherfile(p);
2421 vim_free(p);
2422 }
2423 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002424 && check_changed(curbuf, CCGD_AW
2425 | (other ? 0 : CCGD_MULTWIN)
2426 | (eap->forceit ? CCGD_FORCEIT : 0)
2427 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002428 return;
2429 }
2430
2431 curwin->w_arg_idx = argn;
2432 if (argn == ARGCOUNT - 1
2433#ifdef FEAT_WINDOWS
2434 && curwin->w_alist == &global_alist
2435#endif
2436 )
2437 arg_had_last = TRUE;
2438
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002439 /* Edit the file; always use the last known line number.
2440 * When it fails (e.g. Abort for already edited file) restore the
2441 * argument index. */
2442 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002443 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002444 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2445 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002446 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002448 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002449 setmark('\'');
2450 }
2451}
2452
2453/*
2454 * ":next", and commands that behave like it.
2455 */
2456 void
2457ex_next(eap)
2458 exarg_T *eap;
2459{
2460 int i;
2461
2462 /*
2463 * check for changed buffer now, if this fails the argument list is not
2464 * redefined.
2465 */
2466 if ( P_HID(curbuf)
2467 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002468 || !check_changed(curbuf, CCGD_AW
2469 | (eap->forceit ? CCGD_FORCEIT : 0)
2470 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471 {
2472 if (*eap->arg != NUL) /* redefine file list */
2473 {
2474 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2475 return;
2476 i = 0;
2477 }
2478 else
2479 i = curwin->w_arg_idx + (int)eap->line2;
2480 do_argfile(eap, i);
2481 }
2482}
2483
2484#ifdef FEAT_LISTCMDS
2485/*
2486 * ":argedit"
2487 */
2488 void
2489ex_argedit(eap)
2490 exarg_T *eap;
2491{
2492 int fnum;
2493 int i;
2494 char_u *s;
2495
2496 /* Add the argument to the buffer list and get the buffer number. */
2497 fnum = buflist_add(eap->arg, BLN_LISTED);
2498
2499 /* Check if this argument is already in the argument list. */
2500 for (i = 0; i < ARGCOUNT; ++i)
2501 if (ARGLIST[i].ae_fnum == fnum)
2502 break;
2503 if (i == ARGCOUNT)
2504 {
2505 /* Can't find it, add it to the argument list. */
2506 s = vim_strsave(eap->arg);
2507 if (s == NULL)
2508 return;
2509 i = alist_add_list(1, &s,
2510 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2511 if (i < 0)
2512 return;
2513 curwin->w_arg_idx = i;
2514 }
2515
2516 alist_check_arg_idx();
2517
2518 /* Edit the argument. */
2519 do_argfile(eap, i);
2520}
2521
2522/*
2523 * ":argadd"
2524 */
2525 void
2526ex_argadd(eap)
2527 exarg_T *eap;
2528{
2529 do_arglist(eap->arg, AL_ADD,
2530 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2531#ifdef FEAT_TITLE
2532 maketitle();
2533#endif
2534}
2535
2536/*
2537 * ":argdelete"
2538 */
2539 void
2540ex_argdelete(eap)
2541 exarg_T *eap;
2542{
2543 int i;
2544 int n;
2545
2546 if (eap->addr_count > 0)
2547 {
2548 /* ":1,4argdel": Delete all arguments in the range. */
2549 if (eap->line2 > ARGCOUNT)
2550 eap->line2 = ARGCOUNT;
2551 n = eap->line2 - eap->line1 + 1;
2552 if (*eap->arg != NUL || n <= 0)
2553 EMSG(_(e_invarg));
2554 else
2555 {
2556 for (i = eap->line1; i <= eap->line2; ++i)
2557 vim_free(ARGLIST[i - 1].ae_fname);
2558 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2559 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2560 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002561 if (curwin->w_arg_idx >= eap->line2)
2562 curwin->w_arg_idx -= n;
2563 else if (curwin->w_arg_idx > eap->line1)
2564 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002565 if (ARGCOUNT == 0)
2566 curwin->w_arg_idx = 0;
2567 else if (curwin->w_arg_idx >= ARGCOUNT)
2568 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002569 }
2570 }
2571 else if (*eap->arg == NUL)
2572 EMSG(_(e_argreq));
2573 else
2574 do_arglist(eap->arg, AL_DEL, 0);
2575#ifdef FEAT_TITLE
2576 maketitle();
2577#endif
2578}
2579
2580/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002581 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582 */
2583 void
2584ex_listdo(eap)
2585 exarg_T *eap;
2586{
2587 int i;
2588#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002589 win_T *wp;
2590 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002591#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002592 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593 int next_fnum = 0;
2594#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2595 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002597 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002598#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002599 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002600 int qf_idx;
2601#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602
2603#ifndef FEAT_WINDOWS
2604 if (eap->cmdidx == CMD_windo)
2605 {
2606 ex_ni(eap);
2607 return;
2608 }
2609#endif
2610
2611#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002612 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002613 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2614 * great speed improvement. */
2615 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002617#ifdef FEAT_CLIPBOARD
2618 start_global_changes();
2619#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620
2621 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002622 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002624 || !check_changed(curbuf, CCGD_AW
2625 | (eap->forceit ? CCGD_FORCEIT : 0)
2626 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002629 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002631 wp = firstwin;
2632 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002634 switch (eap->cmdidx)
2635 {
2636#ifdef FEAT_WINDOWS
2637 case CMD_windo:
2638 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2639 i++;
2640 break;
2641 case CMD_tabdo:
2642 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2643 i++;
2644 break;
2645#endif
2646 case CMD_argdo:
2647 i = eap->line1 - 1;
2648 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002649 default:
2650 break;
2651 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652 /* set pcmark now */
2653 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002654 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002655 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002656 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002657 || !buf->b_p_bl); buf = buf->b_next)
2658 if (buf->b_fnum > eap->line2)
2659 {
2660 buf = NULL;
2661 break;
2662 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002663 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002664 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002665 }
2666#ifdef FEAT_QUICKFIX
2667 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2668 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2669 {
2670 qf_size = qf_get_size(eap);
2671 if (qf_size <= 0 || eap->line1 > qf_size)
2672 buf = NULL;
2673 else
2674 {
2675 ex_cc(eap);
2676
2677 buf = curbuf;
2678 i = eap->line1 - 1;
2679 if (eap->addr_count <= 0)
2680 /* default is all the quickfix/location list entries */
2681 eap->line2 = qf_size;
2682 }
2683 }
2684#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685 else
2686 setpcmark();
2687 listcmd_busy = TRUE; /* avoids setting pcmark below */
2688
Bram Moolenaare25bb902015-02-27 20:33:37 +01002689 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690 {
2691 if (eap->cmdidx == CMD_argdo)
2692 {
2693 /* go to argument "i" */
2694 if (i == ARGCOUNT)
2695 break;
2696 /* Don't call do_argfile() when already there, it will try
2697 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002698 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002699 {
2700 /* Clear 'shm' to avoid that the file message overwrites
2701 * any output from the command. */
2702 p_shm_save = vim_strsave(p_shm);
2703 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002704 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002705 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2706 vim_free(p_shm_save);
2707 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 if (curwin->w_arg_idx != i)
2709 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710 }
2711#ifdef FEAT_WINDOWS
2712 else if (eap->cmdidx == CMD_windo)
2713 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002714 /* go to window "wp" */
2715 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002717 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002718 if (curwin != wp)
2719 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002720 wp = curwin->w_next;
2721 }
2722 else if (eap->cmdidx == CMD_tabdo)
2723 {
2724 /* go to window "tp" */
2725 if (!valid_tabpage(tp))
2726 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002727 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002728 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729 }
2730#endif
2731 else if (eap->cmdidx == CMD_bufdo)
2732 {
2733 /* Remember the number of the next listed buffer, in case
2734 * ":bwipe" is used or autocommands do something strange. */
2735 next_fnum = -1;
2736 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2737 if (buf->b_p_bl)
2738 {
2739 next_fnum = buf->b_fnum;
2740 break;
2741 }
2742 }
2743
Bram Moolenaara162bc52015-01-07 16:54:21 +01002744 ++i;
2745
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746 /* execute the command */
2747 do_cmdline(eap->arg, eap->getline, eap->cookie,
2748 DOCMD_VERBOSE + DOCMD_NOWAIT);
2749
2750 if (eap->cmdidx == CMD_bufdo)
2751 {
2752 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002753 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754 break;
2755 /* Check if the buffer still exists. */
2756 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2757 if (buf->b_fnum == next_fnum)
2758 break;
2759 if (buf == NULL)
2760 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002761
2762 /* Go to the next buffer. Clear 'shm' to avoid that the file
2763 * message overwrites any output from the command. */
2764 p_shm_save = vim_strsave(p_shm);
2765 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002767 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2768 vim_free(p_shm_save);
2769
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002770 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002771 if (curbuf->b_fnum != next_fnum)
2772 break;
2773 }
2774
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002775#ifdef FEAT_QUICKFIX
2776 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2777 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2778 {
2779 if (i >= qf_size || i >= eap->line2)
2780 break;
2781
2782 qf_idx = qf_get_cur_idx(eap);
2783
2784 ex_cnext(eap);
2785
2786 /* If jumping to the next quickfix entry fails, quit here */
2787 if (qf_get_cur_idx(eap) == qf_idx)
2788 break;
2789 }
2790#endif
2791
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792 if (eap->cmdidx == CMD_windo)
2793 {
2794 validate_cursor(); /* cursor may have moved */
2795#ifdef FEAT_SCROLLBIND
2796 /* required when 'scrollbind' has been set */
2797 if (curwin->w_p_scb)
2798 do_check_scrollbind(TRUE);
2799#endif
2800 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002801
2802#ifdef FEAT_WINDOWS
2803 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2804 if (i+1 > eap->line2)
2805 break;
2806#endif
2807 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2808 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002809 }
2810 listcmd_busy = FALSE;
2811 }
2812
2813#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002814 if (save_ei != NULL)
2815 {
2816 au_event_restore(save_ei);
2817 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2818 curbuf->b_fname, TRUE, curbuf);
2819 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002821#ifdef FEAT_CLIPBOARD
2822 end_global_changes();
2823#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824}
2825
2826/*
2827 * Add files[count] to the arglist of the current window after arg "after".
2828 * The file names in files[count] must have been allocated and are taken over.
2829 * Files[] itself is not taken over.
2830 * Returns index of first added argument. Returns -1 when failed (out of mem).
2831 */
2832 static int
2833alist_add_list(count, files, after)
2834 int count;
2835 char_u **files;
2836 int after; /* where to add: 0 = before first one */
2837{
2838 int i;
2839
2840 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2841 {
2842 if (after < 0)
2843 after = 0;
2844 if (after > ARGCOUNT)
2845 after = ARGCOUNT;
2846 if (after < ARGCOUNT)
2847 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2848 (ARGCOUNT - after) * sizeof(aentry_T));
2849 for (i = 0; i < count; ++i)
2850 {
2851 ARGLIST[after + i].ae_fname = files[i];
2852 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2853 }
2854 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855 if (curwin->w_arg_idx >= after)
2856 ++curwin->w_arg_idx;
2857 return after;
2858 }
2859
2860 for (i = 0; i < count; ++i)
2861 vim_free(files[i]);
2862 return -1;
2863}
2864
2865#endif /* FEAT_LISTCMDS */
2866
2867#ifdef FEAT_EVAL
2868/*
2869 * ":compiler[!] {name}"
2870 */
2871 void
2872ex_compiler(eap)
2873 exarg_T *eap;
2874{
2875 char_u *buf;
2876 char_u *old_cur_comp = NULL;
2877 char_u *p;
2878
2879 if (*eap->arg == NUL)
2880 {
2881 /* List all compiler scripts. */
2882 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2883 /* ) keep the indenter happy... */
2884 }
2885 else
2886 {
2887 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2888 if (buf != NULL)
2889 {
2890 if (eap->forceit)
2891 {
2892 /* ":compiler! {name}" sets global options */
2893 do_cmdline_cmd((char_u *)
2894 "command -nargs=* CompilerSet set <args>");
2895 }
2896 else
2897 {
2898 /* ":compiler! {name}" sets local options.
2899 * To remain backwards compatible "current_compiler" is always
2900 * used. A user's compiler plugin may set it, the distributed
2901 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002902 * "b:current_compiler" and restore "current_compiler".
2903 * Explicitly prepend "g:" to make it work in a function. */
2904 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905 if (old_cur_comp != NULL)
2906 old_cur_comp = vim_strsave(old_cur_comp);
2907 do_cmdline_cmd((char_u *)
2908 "command -nargs=* CompilerSet setlocal <args>");
2909 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002910 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002911 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912
2913 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002914 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2916 vim_free(buf);
2917
2918 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2919
2920 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002921 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002922 if (p != NULL)
2923 set_internal_string_var((char_u *)"b:current_compiler", p);
2924
2925 /* Restore "current_compiler" for ":compiler {name}". */
2926 if (!eap->forceit)
2927 {
2928 if (old_cur_comp != NULL)
2929 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002930 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931 old_cur_comp);
2932 vim_free(old_cur_comp);
2933 }
2934 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002935 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936 }
2937 }
2938 }
2939}
2940#endif
2941
2942/*
2943 * ":runtime {name}"
2944 */
2945 void
2946ex_runtime(eap)
2947 exarg_T *eap;
2948{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002949 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950}
2951
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002952static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953
2954 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002955source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002957 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002959 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960}
2961
2962/*
2963 * Source the file "name" from all directories in 'runtimepath'.
2964 * "name" can contain wildcards.
2965 * When "all" is TRUE, source all files, otherwise only the first one.
2966 * return FAIL when no file could be sourced, OK otherwise.
2967 */
2968 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002969source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002970 char_u *name;
2971 int all;
2972{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002973 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002974}
2975
2976/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002977 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2978 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002979 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2980 * used.
2981 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002982 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002983 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2984 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002985 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002986 */
2987 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002988do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002989 char_u *name;
2990 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002991 void (*callback)__ARGS((char_u *fname, void *ck));
2992 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002993{
2994 char_u *rtp;
2995 char_u *np;
2996 char_u *buf;
2997 char_u *rtp_copy;
2998 char_u *tail;
2999 int num_files;
3000 char_u **files;
3001 int i;
3002 int did_one = FALSE;
3003#ifdef AMIGA
3004 struct Process *proc = (struct Process *)FindTask(0L);
3005 APTR save_winptr = proc->pr_WindowPtr;
3006
3007 /* Avoid a requester here for a volume that doesn't exist. */
3008 proc->pr_WindowPtr = (APTR)-1L;
3009#endif
3010
3011 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3012 * value. */
3013 rtp_copy = vim_strsave(p_rtp);
3014 buf = alloc(MAXPATHL);
3015 if (buf != NULL && rtp_copy != NULL)
3016 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003017 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003018 {
3019 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003020 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003022 verbose_leave();
3023 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003024
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025 /* Loop over all entries in 'runtimepath'. */
3026 rtp = rtp_copy;
3027 while (*rtp != NUL && (all || !did_one))
3028 {
3029 /* Copy the path from 'runtimepath' to buf[]. */
3030 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003031 if (name == NULL)
3032 {
3033 (*callback)(buf, (void *) &cookie);
3034 if (!did_one)
3035 did_one = (cookie == NULL);
3036 }
3037 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038 {
3039 add_pathsep(buf);
3040 tail = buf + STRLEN(buf);
3041
3042 /* Loop over all patterns in "name" */
3043 np = name;
3044 while (*np != NUL && (all || !did_one))
3045 {
3046 /* Append the pattern from "name" to buf[]. */
3047 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3048 "\t ");
3049
3050 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003051 {
3052 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003053 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003054 verbose_leave();
3055 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056
3057 /* Expand wildcards, invoke the callback for each match. */
3058 if (gen_expand_wildcards(1, &buf, &num_files, &files,
3059 EW_FILE) == OK)
3060 {
3061 for (i = 0; i < num_files; ++i)
3062 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003063 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064 did_one = TRUE;
3065 if (!all)
3066 break;
3067 }
3068 FreeWild(num_files, files);
3069 }
3070 }
3071 }
3072 }
3073 }
3074 vim_free(buf);
3075 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003076 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003077 {
3078 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003079 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003080 verbose_leave();
3081 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003082
3083#ifdef AMIGA
3084 proc->pr_WindowPtr = save_winptr;
3085#endif
3086
3087 return did_one ? OK : FAIL;
3088}
3089
3090#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3091/*
3092 * ":options"
3093 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094 void
3095ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003096 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003097{
3098 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3099}
3100#endif
3101
3102/*
3103 * ":source {fname}"
3104 */
3105 void
3106ex_source(eap)
3107 exarg_T *eap;
3108{
3109#ifdef FEAT_BROWSE
3110 if (cmdmod.browse)
3111 {
3112 char_u *fname = NULL;
3113
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003114 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003115 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3116 if (fname != NULL)
3117 {
3118 cmd_source(fname, eap);
3119 vim_free(fname);
3120 }
3121 }
3122 else
3123#endif
3124 cmd_source(eap->arg, eap);
3125}
3126
3127 static void
3128cmd_source(fname, eap)
3129 char_u *fname;
3130 exarg_T *eap;
3131{
3132 if (*fname == NUL)
3133 EMSG(_(e_argreq));
3134
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003136 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003137 * Need to execute the commands directly. This is required at least
3138 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139 * - ":g" command busy
3140 * - after ":argdo", ":windo" or ":bufdo"
3141 * - another command follows
3142 * - inside a loop
3143 */
3144 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3145#ifdef FEAT_EVAL
3146 || eap->cstack->cs_idx >= 0
3147#endif
3148 );
3149
3150 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003151 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152 EMSG2(_(e_notopen), fname);
3153}
3154
3155/*
3156 * ":source" and associated commands.
3157 */
3158/*
3159 * Structure used to store info for each sourced file.
3160 * It is shared between do_source() and getsourceline().
3161 * This is required, because it needs to be handed to do_cmdline() and
3162 * sourcing can be done recursively.
3163 */
3164struct source_cookie
3165{
3166 FILE *fp; /* opened file for sourcing */
3167 char_u *nextline; /* if not NULL: line that was read ahead */
3168 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003169#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003170 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3171 int error; /* TRUE if LF found after CR-LF */
3172#endif
3173#ifdef FEAT_EVAL
3174 linenr_T breakpoint; /* next line with breakpoint or zero */
3175 char_u *fname; /* name of sourced file */
3176 int dbg_tick; /* debug_tick when breakpoint was set */
3177 int level; /* top nesting level of sourced file */
3178#endif
3179#ifdef FEAT_MBYTE
3180 vimconv_T conv; /* type of conversion */
3181#endif
3182};
3183
3184#ifdef FEAT_EVAL
3185/*
3186 * Return the address holding the next breakpoint line for a source cookie.
3187 */
3188 linenr_T *
3189source_breakpoint(cookie)
3190 void *cookie;
3191{
3192 return &((struct source_cookie *)cookie)->breakpoint;
3193}
3194
3195/*
3196 * Return the address holding the debug tick for a source cookie.
3197 */
3198 int *
3199source_dbg_tick(cookie)
3200 void *cookie;
3201{
3202 return &((struct source_cookie *)cookie)->dbg_tick;
3203}
3204
3205/*
3206 * Return the nesting level for a source cookie.
3207 */
3208 int
3209source_level(cookie)
3210 void *cookie;
3211{
3212 return ((struct source_cookie *)cookie)->level;
3213}
3214#endif
3215
3216static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
3217
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003218#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3219# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220static FILE *fopen_noinh_readbin __ARGS((char *filename));
3221
3222/*
3223 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003224 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 */
3226 static FILE *
3227fopen_noinh_readbin(filename)
3228 char *filename;
3229{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003230# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003231 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3232# else
3233 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003234# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003235
3236 if (fd_tmp == -1)
3237 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003238
3239# ifdef HAVE_FD_CLOEXEC
3240 {
3241 int fdflags = fcntl(fd_tmp, F_GETFD);
3242 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003243 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003244 }
3245# endif
3246
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247 return fdopen(fd_tmp, READBIN);
3248}
3249#endif
3250
3251
3252/*
3253 * do_source: Read the file "fname" and execute its lines as EX commands.
3254 *
3255 * This function may be called recursively!
3256 *
3257 * return FAIL if file could not be opened, OK otherwise
3258 */
3259 int
3260do_source(fname, check_other, is_vimrc)
3261 char_u *fname;
3262 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003263 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264{
3265 struct source_cookie cookie;
3266 char_u *save_sourcing_name;
3267 linenr_T save_sourcing_lnum;
3268 char_u *p;
3269 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003270 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271 int retval = FAIL;
3272#ifdef FEAT_EVAL
3273 scid_T save_current_SID;
3274 static scid_T last_current_SID = 0;
3275 void *save_funccalp;
3276 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003277 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278# ifdef UNIX
3279 struct stat st;
3280 int stat_ok;
3281# endif
3282#endif
3283#ifdef STARTUPTIME
3284 struct timeval tv_rel;
3285 struct timeval tv_start;
3286#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003287#ifdef FEAT_PROFILE
3288 proftime_T wait_start;
3289#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292 if (p == NULL)
3293 return retval;
3294 fname_exp = fix_fname(p);
3295 vim_free(p);
3296 if (fname_exp == NULL)
3297 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298 if (mch_isdir(fname_exp))
3299 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003300 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301 goto theend;
3302 }
3303
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003304#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003305 /* Apply SourceCmd autocommands, they should get the file and source it. */
3306 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3307 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3308 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003309 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003310# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003311 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003312# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003313 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003314# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003315 goto theend;
3316 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003317
3318 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003319 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3320#endif
3321
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003322#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003323 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3324#else
3325 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3326#endif
3327 if (cookie.fp == NULL && check_other)
3328 {
3329 /*
3330 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3331 * and ".exrc" by "_exrc" or vice versa.
3332 */
3333 p = gettail(fname_exp);
3334 if ((*p == '.' || *p == '_')
3335 && (STRICMP(p + 1, "vimrc") == 0
3336 || STRICMP(p + 1, "gvimrc") == 0
3337 || STRICMP(p + 1, "exrc") == 0))
3338 {
3339 if (*p == '_')
3340 *p = '.';
3341 else
3342 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003343#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3345#else
3346 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3347#endif
3348 }
3349 }
3350
3351 if (cookie.fp == NULL)
3352 {
3353 if (p_verbose > 0)
3354 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003355 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003357 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358 else
3359 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003360 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003361 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003362 }
3363 goto theend;
3364 }
3365
3366 /*
3367 * The file exists.
3368 * - In verbose mode, give a message.
3369 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3370 */
3371 if (p_verbose > 1)
3372 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003373 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003374 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003375 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003376 else
3377 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003378 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003379 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003380 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003381 if (is_vimrc == DOSO_VIMRC)
3382 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3383 else if (is_vimrc == DOSO_GVIMRC)
3384 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385
3386#ifdef USE_CRNL
3387 /* If no automatic file format: Set default to CR-NL. */
3388 if (*p_ffs == NUL)
3389 cookie.fileformat = EOL_DOS;
3390 else
3391 cookie.fileformat = EOL_UNKNOWN;
3392 cookie.error = FALSE;
3393#endif
3394
3395#ifdef USE_CR
3396 /* If no automatic file format: Set default to CR. */
3397 if (*p_ffs == NUL)
3398 cookie.fileformat = EOL_MAC;
3399 else
3400 cookie.fileformat = EOL_UNKNOWN;
3401 cookie.error = FALSE;
3402#endif
3403
3404 cookie.nextline = NULL;
3405 cookie.finished = FALSE;
3406
3407#ifdef FEAT_EVAL
3408 /*
3409 * Check if this script has a breakpoint.
3410 */
3411 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3412 cookie.fname = fname_exp;
3413 cookie.dbg_tick = debug_tick;
3414
3415 cookie.level = ex_nesting_level;
3416#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003417
3418 /*
3419 * Keep the sourcing name/lnum, for recursive calls.
3420 */
3421 save_sourcing_name = sourcing_name;
3422 sourcing_name = fname_exp;
3423 save_sourcing_lnum = sourcing_lnum;
3424 sourcing_lnum = 0;
3425
Bram Moolenaar73881402009-02-04 16:50:47 +00003426#ifdef FEAT_MBYTE
3427 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3428
3429 /* Read the first line so we can check for a UTF-8 BOM. */
3430 firstline = getsourceline(0, (void *)&cookie, 0);
3431 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3432 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3433 {
3434 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3435 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3436 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003437 if (p == NULL)
3438 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003439 if (p != NULL)
3440 {
3441 vim_free(firstline);
3442 firstline = p;
3443 }
3444 }
3445#endif
3446
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003448 if (time_fd != NULL)
3449 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003450#endif
3451
3452#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003453# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003454 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003455 prof_child_enter(&wait_start); /* entering a child now */
3456# endif
3457
3458 /* Don't use local function variables, if called from a function.
3459 * Also starts profiling timer for nested script. */
3460 save_funccalp = save_funccal();
3461
Bram Moolenaar071d4272004-06-13 20:20:40 +00003462 /*
3463 * Check if this script was sourced before to finds its SID.
3464 * If it's new, generate a new SID.
3465 */
3466 save_current_SID = current_SID;
3467# ifdef UNIX
3468 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3469# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003470 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3471 {
3472 si = &SCRIPT_ITEM(current_SID);
3473 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003474 && (
3475# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003476 /* Compare dev/ino when possible, it catches symbolic
3477 * links. Also compare file names, the inode may change
3478 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003479 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003480 && (si->sn_dev == st.st_dev
3481 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003483 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003485 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003486 if (current_SID == 0)
3487 {
3488 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003489 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3490 == FAIL)
3491 goto almosttheend;
3492 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003494 ++script_items.ga_len;
3495 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3496# ifdef FEAT_PROFILE
3497 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003499 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003500 si = &SCRIPT_ITEM(current_SID);
3501 si->sn_name = fname_exp;
3502 fname_exp = NULL;
3503# ifdef UNIX
3504 if (stat_ok)
3505 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003506 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003507 si->sn_dev = st.st_dev;
3508 si->sn_ino = st.st_ino;
3509 }
3510 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003511 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003512# endif
3513
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514 /* Allocate the local script variables to use for this script. */
3515 new_script_vars(current_SID);
3516 }
3517
Bram Moolenaar05159a02005-02-26 23:04:13 +00003518# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003519 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003520 {
3521 int forceit;
3522
3523 /* Check if we do profiling for this script. */
3524 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3525 {
3526 script_do_profile(si);
3527 si->sn_pr_force = forceit;
3528 }
3529 if (si->sn_prof_on)
3530 {
3531 ++si->sn_pr_count;
3532 profile_start(&si->sn_pr_start);
3533 profile_zero(&si->sn_pr_children);
3534 }
3535 }
3536# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537#endif
3538
3539 /*
3540 * Call do_cmdline, which will call getsourceline() to get the lines.
3541 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003542 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003543 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003545
3546#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003547 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003548 {
3549 /* Get "si" again, "script_items" may have been reallocated. */
3550 si = &SCRIPT_ITEM(current_SID);
3551 if (si->sn_prof_on)
3552 {
3553 profile_end(&si->sn_pr_start);
3554 profile_sub_wait(&wait_start, &si->sn_pr_start);
3555 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003556 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3557 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003558 }
3559 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560#endif
3561
3562 if (got_int)
3563 EMSG(_(e_interr));
3564 sourcing_name = save_sourcing_name;
3565 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003566 if (p_verbose > 1)
3567 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003568 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003569 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003570 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003571 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003572 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573 }
3574#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003575 if (time_fd != NULL)
3576 {
3577 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3578 time_msg((char *)IObuff, &tv_start);
3579 time_pop(&tv_rel);
3580 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003581#endif
3582
3583#ifdef FEAT_EVAL
3584 /*
3585 * After a "finish" in debug mode, need to break at first command of next
3586 * sourced file.
3587 */
3588 if (save_debug_break_level > ex_nesting_level
3589 && debug_break_level == ex_nesting_level)
3590 ++debug_break_level;
3591#endif
3592
Bram Moolenaar05159a02005-02-26 23:04:13 +00003593#ifdef FEAT_EVAL
3594almosttheend:
3595 current_SID = save_current_SID;
3596 restore_funccal(save_funccalp);
3597# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003598 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003599 prof_child_exit(&wait_start); /* leaving a child now */
3600# endif
3601#endif
3602 fclose(cookie.fp);
3603 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003604 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003605#ifdef FEAT_MBYTE
3606 convert_setup(&cookie.conv, NULL, NULL);
3607#endif
3608
Bram Moolenaar071d4272004-06-13 20:20:40 +00003609theend:
3610 vim_free(fname_exp);
3611 return retval;
3612}
3613
3614#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003615
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616/*
3617 * ":scriptnames"
3618 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003619 void
3620ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003621 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003622{
3623 int i;
3624
Bram Moolenaar05159a02005-02-26 23:04:13 +00003625 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3626 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003627 {
3628 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3629 NameBuff, MAXPATHL, TRUE);
3630 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003631 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003632}
3633
3634# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3635/*
3636 * Fix slashes in the list of script names for 'shellslash'.
3637 */
3638 void
3639scriptnames_slash_adjust()
3640{
3641 int i;
3642
Bram Moolenaar05159a02005-02-26 23:04:13 +00003643 for (i = 1; i <= script_items.ga_len; ++i)
3644 if (SCRIPT_ITEM(i).sn_name != NULL)
3645 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646}
3647# endif
3648
3649/*
3650 * Get a pointer to a script name. Used for ":verbose set".
3651 */
3652 char_u *
3653get_scriptname(id)
3654 scid_T id;
3655{
3656 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003657 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003658 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003659 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003660 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003661 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003662 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003663 return (char_u *)_("environment variable");
3664 if (id == SID_ERROR)
3665 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003666 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003668
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003669# if defined(EXITFREE) || defined(PROTO)
3670 void
3671free_scriptnames()
3672{
3673 int i;
3674
3675 for (i = script_items.ga_len; i > 0; --i)
3676 vim_free(SCRIPT_ITEM(i).sn_name);
3677 ga_clear(&script_items);
3678}
3679# endif
3680
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681#endif
3682
3683#if defined(USE_CR) || defined(PROTO)
3684
3685# if defined(__MSL__) && (__MSL__ >= 22)
3686/*
3687 * Newer version of the Metrowerks library handle DOS and UNIX files
3688 * without help.
3689 * Test with earlier versions, MSL 2.2 is the library supplied with
3690 * Codewarrior Pro 2.
3691 */
3692 char *
3693fgets_cr(s, n, stream)
3694 char *s;
3695 int n;
3696 FILE *stream;
3697{
3698 return fgets(s, n, stream);
3699}
3700# else
3701/*
3702 * Version of fgets() which also works for lines ending in a <CR> only
3703 * (Macintosh format).
3704 * For older versions of the Metrowerks library.
3705 * At least CodeWarrior 9 needed this code.
3706 */
3707 char *
3708fgets_cr(s, n, stream)
3709 char *s;
3710 int n;
3711 FILE *stream;
3712{
3713 int c = 0;
3714 int char_read = 0;
3715
3716 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3717 {
3718 c = fgetc(stream);
3719 s[char_read++] = c;
3720 /* If the file is in DOS format, we need to skip a NL after a CR. I
3721 * thought it was the other way around, but this appears to work... */
3722 if (c == '\n')
3723 {
3724 c = fgetc(stream);
3725 if (c != '\r')
3726 ungetc(c, stream);
3727 }
3728 }
3729
3730 s[char_read] = 0;
3731 if (char_read == 0)
3732 return NULL;
3733
3734 if (feof(stream) && char_read == 1)
3735 return NULL;
3736
3737 return s;
3738}
3739# endif
3740#endif
3741
3742/*
3743 * Get one full line from a sourced file.
3744 * Called by do_cmdline() when it's called from do_source().
3745 *
3746 * Return a pointer to the line in allocated memory.
3747 * Return NULL for end-of-file or some error.
3748 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749 char_u *
3750getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003751 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003752 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003753 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754{
3755 struct source_cookie *sp = (struct source_cookie *)cookie;
3756 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003757 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758
3759#ifdef FEAT_EVAL
3760 /* If breakpoints have been added/deleted need to check for it. */
3761 if (sp->dbg_tick < debug_tick)
3762 {
3763 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3764 sp->dbg_tick = debug_tick;
3765 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003766# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003767 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003768 script_line_end();
3769# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003770#endif
3771 /*
3772 * Get current line. If there is a read-ahead line, use it, otherwise get
3773 * one now.
3774 */
3775 if (sp->finished)
3776 line = NULL;
3777 else if (sp->nextline == NULL)
3778 line = get_one_sourceline(sp);
3779 else
3780 {
3781 line = sp->nextline;
3782 sp->nextline = NULL;
3783 ++sourcing_lnum;
3784 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003785#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003786 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003787 script_line_start();
3788#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789
3790 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3791 * contain the 'C' flag. */
3792 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3793 {
3794 /* compensate for the one line read-ahead */
3795 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003796
3797 /* Get the next line and concatenate it when it starts with a
3798 * backslash. We always need to read the next line, keep it in
3799 * sp->nextline. */
3800 sp->nextline = get_one_sourceline(sp);
3801 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003803 garray_T ga;
3804
Bram Moolenaarb549a732012-02-22 18:29:33 +01003805 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003806 ga_concat(&ga, line);
3807 ga_concat(&ga, p + 1);
3808 for (;;)
3809 {
3810 vim_free(sp->nextline);
3811 sp->nextline = get_one_sourceline(sp);
3812 if (sp->nextline == NULL)
3813 break;
3814 p = skipwhite(sp->nextline);
3815 if (*p != '\\')
3816 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003817 /* Adjust the growsize to the current length to speed up
3818 * concatenating many lines. */
3819 if (ga.ga_len > 400)
3820 {
3821 if (ga.ga_len > 8000)
3822 ga.ga_growsize = 8000;
3823 else
3824 ga.ga_growsize = ga.ga_len;
3825 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003826 ga_concat(&ga, p + 1);
3827 }
3828 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003830 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003831 }
3832 }
3833
3834#ifdef FEAT_MBYTE
3835 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3836 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003837 char_u *s;
3838
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839 /* Convert the encoding of the script line. */
3840 s = string_convert(&sp->conv, line, NULL);
3841 if (s != NULL)
3842 {
3843 vim_free(line);
3844 line = s;
3845 }
3846 }
3847#endif
3848
3849#ifdef FEAT_EVAL
3850 /* Did we encounter a breakpoint? */
3851 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3852 {
3853 dbg_breakpoint(sp->fname, sourcing_lnum);
3854 /* Find next breakpoint. */
3855 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3856 sp->dbg_tick = debug_tick;
3857 }
3858#endif
3859
3860 return line;
3861}
3862
3863 static char_u *
3864get_one_sourceline(sp)
3865 struct source_cookie *sp;
3866{
3867 garray_T ga;
3868 int len;
3869 int c;
3870 char_u *buf;
3871#ifdef USE_CRNL
3872 int has_cr; /* CR-LF found */
3873#endif
3874#ifdef USE_CR
3875 char_u *scan;
3876#endif
3877 int have_read = FALSE;
3878
3879 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003880 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881
3882 /*
3883 * Loop until there is a finished line (or end-of-file).
3884 */
3885 sourcing_lnum++;
3886 for (;;)
3887 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003888 /* make room to read at least 120 (more) characters */
3889 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003890 break;
3891 buf = (char_u *)ga.ga_data;
3892
3893#ifdef USE_CR
3894 if (sp->fileformat == EOL_MAC)
3895 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003896 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3897 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898 break;
3899 }
3900 else
3901#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003902 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3903 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003904 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003905 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906#ifdef USE_CRNL
3907 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3908 * CTRL-Z by its own, or after a NL. */
3909 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3910 && sp->fileformat == EOL_DOS
3911 && buf[len - 1] == Ctrl_Z)
3912 {
3913 buf[len - 1] = NUL;
3914 break;
3915 }
3916#endif
3917
3918#ifdef USE_CR
3919 /* If the read doesn't stop on a new line, and there's
3920 * some CR then we assume a Mac format */
3921 if (sp->fileformat == EOL_UNKNOWN)
3922 {
3923 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3924 sp->fileformat = EOL_MAC;
3925 else
3926 sp->fileformat = EOL_UNIX;
3927 }
3928
3929 if (sp->fileformat == EOL_MAC)
3930 {
3931 scan = vim_strchr(buf, '\r');
3932
3933 if (scan != NULL)
3934 {
3935 *scan = '\n';
3936 if (*(scan + 1) != 0)
3937 {
3938 *(scan + 1) = 0;
3939 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3940 }
3941 }
3942 len = STRLEN(buf);
3943 }
3944#endif
3945
3946 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003947 ga.ga_len = len;
3948
3949 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003950 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003951 continue;
3952
3953 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3954 {
3955#ifdef USE_CRNL
3956 has_cr = (len >= 2 && buf[len - 2] == '\r');
3957 if (sp->fileformat == EOL_UNKNOWN)
3958 {
3959 if (has_cr)
3960 sp->fileformat = EOL_DOS;
3961 else
3962 sp->fileformat = EOL_UNIX;
3963 }
3964
3965 if (sp->fileformat == EOL_DOS)
3966 {
3967 if (has_cr) /* replace trailing CR */
3968 {
3969 buf[len - 2] = '\n';
3970 --len;
3971 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003972 }
3973 else /* lines like ":map xx yy^M" will have failed */
3974 {
3975 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003976 {
3977 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003978 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003979 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003980 sp->error = TRUE;
3981 sp->fileformat = EOL_UNIX;
3982 }
3983 }
3984#endif
3985 /* The '\n' is escaped if there is an odd number of ^V's just
3986 * before it, first set "c" just before the 'V's and then check
3987 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3988 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3989 ;
3990 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3991 {
3992 sourcing_lnum++;
3993 continue;
3994 }
3995
3996 buf[len - 1] = NUL; /* remove the NL */
3997 }
3998
3999 /*
4000 * Check for ^C here now and then, so recursive :so can be broken.
4001 */
4002 line_breakcheck();
4003 break;
4004 }
4005
4006 if (have_read)
4007 return (char_u *)ga.ga_data;
4008
4009 vim_free(ga.ga_data);
4010 return NULL;
4011}
4012
Bram Moolenaar05159a02005-02-26 23:04:13 +00004013#if defined(FEAT_PROFILE) || defined(PROTO)
4014/*
4015 * Called when starting to read a script line.
4016 * "sourcing_lnum" must be correct!
4017 * When skipping lines it may not actually be executed, but we won't find out
4018 * until later and we need to store the time now.
4019 */
4020 void
4021script_line_start()
4022{
4023 scriptitem_T *si;
4024 sn_prl_T *pp;
4025
4026 if (current_SID <= 0 || current_SID > script_items.ga_len)
4027 return;
4028 si = &SCRIPT_ITEM(current_SID);
4029 if (si->sn_prof_on && sourcing_lnum >= 1)
4030 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004031 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004032 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004033 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004034 si->sn_prl_idx = sourcing_lnum - 1;
4035 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4036 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4037 {
4038 /* Zero counters for a line that was not used before. */
4039 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4040 pp->snp_count = 0;
4041 profile_zero(&pp->sn_prl_total);
4042 profile_zero(&pp->sn_prl_self);
4043 ++si->sn_prl_ga.ga_len;
4044 }
4045 si->sn_prl_execed = FALSE;
4046 profile_start(&si->sn_prl_start);
4047 profile_zero(&si->sn_prl_children);
4048 profile_get_wait(&si->sn_prl_wait);
4049 }
4050}
4051
4052/*
4053 * Called when actually executing a function line.
4054 */
4055 void
4056script_line_exec()
4057{
4058 scriptitem_T *si;
4059
4060 if (current_SID <= 0 || current_SID > script_items.ga_len)
4061 return;
4062 si = &SCRIPT_ITEM(current_SID);
4063 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4064 si->sn_prl_execed = TRUE;
4065}
4066
4067/*
4068 * Called when done with a function line.
4069 */
4070 void
4071script_line_end()
4072{
4073 scriptitem_T *si;
4074 sn_prl_T *pp;
4075
4076 if (current_SID <= 0 || current_SID > script_items.ga_len)
4077 return;
4078 si = &SCRIPT_ITEM(current_SID);
4079 if (si->sn_prof_on && si->sn_prl_idx >= 0
4080 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4081 {
4082 if (si->sn_prl_execed)
4083 {
4084 pp = &PRL_ITEM(si, si->sn_prl_idx);
4085 ++pp->snp_count;
4086 profile_end(&si->sn_prl_start);
4087 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004088 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004089 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4090 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004091 }
4092 si->sn_prl_idx = -1;
4093 }
4094}
4095#endif
4096
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097/*
4098 * ":scriptencoding": Set encoding conversion for a sourced script.
4099 * Without the multi-byte feature it's simply ignored.
4100 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101 void
4102ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004103 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104{
4105#ifdef FEAT_MBYTE
4106 struct source_cookie *sp;
4107 char_u *name;
4108
4109 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4110 {
4111 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4112 return;
4113 }
4114
4115 if (*eap->arg != NUL)
4116 {
4117 name = enc_canonize(eap->arg);
4118 if (name == NULL) /* out of memory */
4119 return;
4120 }
4121 else
4122 name = eap->arg;
4123
4124 /* Setup for conversion from the specified encoding to 'encoding'. */
4125 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4126 convert_setup(&sp->conv, name, p_enc);
4127
4128 if (name != eap->arg)
4129 vim_free(name);
4130#endif
4131}
4132
4133#if defined(FEAT_EVAL) || defined(PROTO)
4134/*
4135 * ":finish": Mark a sourced file as finished.
4136 */
4137 void
4138ex_finish(eap)
4139 exarg_T *eap;
4140{
4141 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4142 do_finish(eap, FALSE);
4143 else
4144 EMSG(_("E168: :finish used outside of a sourced file"));
4145}
4146
4147/*
4148 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4149 * Also called for a pending finish at the ":endtry" or after returning from
4150 * an extra do_cmdline(). "reanimate" is used in the latter case.
4151 */
4152 void
4153do_finish(eap, reanimate)
4154 exarg_T *eap;
4155 int reanimate;
4156{
4157 int idx;
4158
4159 if (reanimate)
4160 ((struct source_cookie *)getline_cookie(eap->getline,
4161 eap->cookie))->finished = FALSE;
4162
4163 /*
4164 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4165 * not in its finally clause (which then is to be executed next) is found.
4166 * In this case, make the ":finish" pending for execution at the ":endtry".
4167 * Otherwise, finish normally.
4168 */
4169 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4170 if (idx >= 0)
4171 {
4172 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4173 report_make_pending(CSTP_FINISH, NULL);
4174 }
4175 else
4176 ((struct source_cookie *)getline_cookie(eap->getline,
4177 eap->cookie))->finished = TRUE;
4178}
4179
4180
4181/*
4182 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4183 * message for missing ":endif".
4184 * Return FALSE when not sourcing a file.
4185 */
4186 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00004187source_finished(fgetline, cookie)
4188 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004189 void *cookie;
4190{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004191 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004193 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194}
4195#endif
4196
4197#if defined(FEAT_LISTCMDS) || defined(PROTO)
4198/*
4199 * ":checktime [buffer]"
4200 */
4201 void
4202ex_checktime(eap)
4203 exarg_T *eap;
4204{
4205 buf_T *buf;
4206 int save_no_check_timestamps = no_check_timestamps;
4207
4208 no_check_timestamps = 0;
4209 if (eap->addr_count == 0) /* default is all buffers */
4210 check_timestamps(FALSE);
4211 else
4212 {
4213 buf = buflist_findnr((int)eap->line2);
4214 if (buf != NULL) /* cannot happen? */
4215 (void)buf_check_timestamp(buf, FALSE);
4216 }
4217 no_check_timestamps = save_no_check_timestamps;
4218}
4219#endif
4220
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4222 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004223# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224static char *get_locale_val __ARGS((int what));
4225
4226 static char *
4227get_locale_val(what)
4228 int what;
4229{
4230 char *loc;
4231
4232 /* Obtain the locale value from the libraries. For DJGPP this is
4233 * redefined and it doesn't use the arguments. */
4234 loc = setlocale(what, NULL);
4235
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004236# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237 if (loc != NULL)
4238 {
4239 char_u *p;
4240
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004241 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4242 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004243 p = vim_strchr(loc, '=');
4244 if (p != NULL)
4245 {
4246 loc = ++p;
4247 while (*p != NUL) /* remove trailing newline */
4248 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004249 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250 {
4251 *p = NUL;
4252 break;
4253 }
4254 ++p;
4255 }
4256 }
4257 }
4258# endif
4259
4260 return loc;
4261}
4262#endif
4263
4264
4265#ifdef WIN32
4266/*
4267 * On MS-Windows locale names are strings like "German_Germany.1252", but
4268 * gettext expects "de". Try to translate one into another here for a few
4269 * supported languages.
4270 */
4271 static char_u *
4272gettext_lang(char_u *name)
4273{
4274 int i;
4275 static char *(mtable[]) = {
4276 "afrikaans", "af",
4277 "czech", "cs",
4278 "dutch", "nl",
4279 "german", "de",
4280 "english_united kingdom", "en_GB",
4281 "spanish", "es",
4282 "french", "fr",
4283 "italian", "it",
4284 "japanese", "ja",
4285 "korean", "ko",
4286 "norwegian", "no",
4287 "polish", "pl",
4288 "russian", "ru",
4289 "slovak", "sk",
4290 "swedish", "sv",
4291 "ukrainian", "uk",
4292 "chinese_china", "zh_CN",
4293 "chinese_taiwan", "zh_TW",
4294 NULL};
4295
4296 for (i = 0; mtable[i] != NULL; i += 2)
4297 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4298 return mtable[i + 1];
4299 return name;
4300}
4301#endif
4302
4303#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4304/*
4305 * Obtain the current messages language. Used to set the default for
4306 * 'helplang'. May return NULL or an empty string.
4307 */
4308 char_u *
4309get_mess_lang()
4310{
4311 char_u *p;
4312
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004313# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314# if defined(LC_MESSAGES)
4315 p = (char_u *)get_locale_val(LC_MESSAGES);
4316# else
4317 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004318 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4319 * and LC_MONETARY may be set differently for a Japanese working in the
4320 * US. */
4321 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004322# endif
4323# else
4324 p = mch_getenv((char_u *)"LC_ALL");
4325 if (p == NULL || *p == NUL)
4326 {
4327 p = mch_getenv((char_u *)"LC_MESSAGES");
4328 if (p == NULL || *p == NUL)
4329 p = mch_getenv((char_u *)"LANG");
4330 }
4331# endif
4332# ifdef WIN32
4333 p = gettext_lang(p);
4334# endif
4335 return p;
4336}
4337#endif
4338
Bram Moolenaardef9e822004-12-31 20:58:58 +00004339/* Complicated #if; matches with where get_mess_env() is used below. */
4340#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4341 && defined(LC_MESSAGES))) \
4342 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4343 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4344 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345static char_u *get_mess_env __ARGS((void));
4346
4347/*
4348 * Get the language used for messages from the environment.
4349 */
4350 static char_u *
4351get_mess_env()
4352{
4353 char_u *p;
4354
4355 p = mch_getenv((char_u *)"LC_ALL");
4356 if (p == NULL || *p == NUL)
4357 {
4358 p = mch_getenv((char_u *)"LC_MESSAGES");
4359 if (p == NULL || *p == NUL)
4360 {
4361 p = mch_getenv((char_u *)"LANG");
4362 if (p != NULL && VIM_ISDIGIT(*p))
4363 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004364# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365 if (p == NULL || *p == NUL)
4366 p = (char_u *)get_locale_val(LC_CTYPE);
4367# endif
4368 }
4369 }
4370 return p;
4371}
4372#endif
4373
4374#if defined(FEAT_EVAL) || defined(PROTO)
4375
4376/*
4377 * Set the "v:lang" variable according to the current locale setting.
4378 * Also do "v:lc_time"and "v:ctype".
4379 */
4380 void
4381set_lang_var()
4382{
4383 char_u *loc;
4384
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004385# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004386 loc = (char_u *)get_locale_val(LC_CTYPE);
4387# else
4388 /* setlocale() not supported: use the default value */
4389 loc = (char_u *)"C";
4390# endif
4391 set_vim_var_string(VV_CTYPE, loc, -1);
4392
4393 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4394 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004395# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004396 loc = (char_u *)get_locale_val(LC_MESSAGES);
4397# else
4398 loc = get_mess_env();
4399# endif
4400 set_vim_var_string(VV_LANG, loc, -1);
4401
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004402# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004403 loc = (char_u *)get_locale_val(LC_TIME);
4404# endif
4405 set_vim_var_string(VV_LC_TIME, loc, -1);
4406}
4407#endif
4408
4409#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4410 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4411/*
4412 * ":language": Set the language (locale).
4413 */
4414 void
4415ex_language(eap)
4416 exarg_T *eap;
4417{
4418 char *loc;
4419 char_u *p;
4420 char_u *name;
4421 int what = LC_ALL;
4422 char *whatstr = "";
4423#ifdef LC_MESSAGES
4424# define VIM_LC_MESSAGES LC_MESSAGES
4425#else
4426# define VIM_LC_MESSAGES 6789
4427#endif
4428
4429 name = eap->arg;
4430
4431 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4432 * Allow abbreviation, but require at least 3 characters to avoid
4433 * confusion with a two letter language name "me" or "ct". */
4434 p = skiptowhite(eap->arg);
4435 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4436 {
4437 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4438 {
4439 what = VIM_LC_MESSAGES;
4440 name = skipwhite(p);
4441 whatstr = "messages ";
4442 }
4443 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4444 {
4445 what = LC_CTYPE;
4446 name = skipwhite(p);
4447 whatstr = "ctype ";
4448 }
4449 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4450 {
4451 what = LC_TIME;
4452 name = skipwhite(p);
4453 whatstr = "time ";
4454 }
4455 }
4456
4457 if (*name == NUL)
4458 {
4459#ifndef LC_MESSAGES
4460 if (what == VIM_LC_MESSAGES)
4461 p = get_mess_env();
4462 else
4463#endif
4464 p = (char_u *)setlocale(what, NULL);
4465 if (p == NULL || *p == NUL)
4466 p = (char_u *)"Unknown";
4467 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4468 }
4469 else
4470 {
4471#ifndef LC_MESSAGES
4472 if (what == VIM_LC_MESSAGES)
4473 loc = "";
4474 else
4475#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004476 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004477 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004478#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4479 /* Make sure strtod() uses a decimal point, not a comma. */
4480 setlocale(LC_NUMERIC, "C");
4481#endif
4482 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004483 if (loc == NULL)
4484 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4485 else
4486 {
4487#ifdef HAVE_NL_MSG_CAT_CNTR
4488 /* Need to do this for GNU gettext, otherwise cached translations
4489 * will be used again. */
4490 extern int _nl_msg_cat_cntr;
4491
4492 ++_nl_msg_cat_cntr;
4493#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004494 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004495 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4496
4497 if (what != LC_TIME)
4498 {
4499 /* Tell gettext() what to translate to. It apparently doesn't
4500 * use the currently effective locale. Also do this when
4501 * FEAT_GETTEXT isn't defined, so that shell commands use this
4502 * value. */
4503 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004504 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004505 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004506
4507 /* Clear $LANGUAGE because GNU gettext uses it. */
4508 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004509# ifdef WIN32
4510 /* Apparently MS-Windows printf() may cause a crash when
4511 * we give it 8-bit text while it's expecting text in the
4512 * current locale. This call avoids that. */
4513 setlocale(LC_CTYPE, "C");
4514# endif
4515 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004516 if (what != LC_CTYPE)
4517 {
4518 char_u *mname;
4519#ifdef WIN32
4520 mname = gettext_lang(name);
4521#else
4522 mname = name;
4523#endif
4524 vim_setenv((char_u *)"LC_MESSAGES", mname);
4525#ifdef FEAT_MULTI_LANG
4526 set_helplang_default(mname);
4527#endif
4528 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529 }
4530
4531# ifdef FEAT_EVAL
4532 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4533 set_lang_var();
4534# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004535# ifdef FEAT_TITLE
4536 maketitle();
4537# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538 }
4539 }
4540}
4541
4542# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004543
4544static char_u **locales = NULL; /* Array of all available locales */
4545static int did_init_locales = FALSE;
4546
4547static void init_locales __ARGS((void));
4548static char_u **find_locales __ARGS((void));
4549
4550/*
4551 * Lazy initialization of all available locales.
4552 */
4553 static void
4554init_locales()
4555{
4556 if (!did_init_locales)
4557 {
4558 did_init_locales = TRUE;
4559 locales = find_locales();
4560 }
4561}
4562
4563/* Return an array of strings for all available locales + NULL for the
4564 * last element. Return NULL in case of error. */
4565 static char_u **
4566find_locales()
4567{
4568 garray_T locales_ga;
4569 char_u *loc;
4570
4571 /* Find all available locales by running command "locale -a". If this
4572 * doesn't work we won't have completion. */
4573 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004574 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004575 if (locale_a == NULL)
4576 return NULL;
4577 ga_init2(&locales_ga, sizeof(char_u *), 20);
4578
4579 /* Transform locale_a string where each locale is separated by "\n"
4580 * into an array of locale strings. */
4581 loc = (char_u *)strtok((char *)locale_a, "\n");
4582
4583 while (loc != NULL)
4584 {
4585 if (ga_grow(&locales_ga, 1) == FAIL)
4586 break;
4587 loc = vim_strsave(loc);
4588 if (loc == NULL)
4589 break;
4590
4591 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4592 loc = (char_u *)strtok(NULL, "\n");
4593 }
4594 vim_free(locale_a);
4595 if (ga_grow(&locales_ga, 1) == FAIL)
4596 {
4597 ga_clear(&locales_ga);
4598 return NULL;
4599 }
4600 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4601 return (char_u **)locales_ga.ga_data;
4602}
4603
4604# if defined(EXITFREE) || defined(PROTO)
4605 void
4606free_locales()
4607{
4608 int i;
4609 if (locales != NULL)
4610 {
4611 for (i = 0; locales[i] != NULL; i++)
4612 vim_free(locales[i]);
4613 vim_free(locales);
4614 locales = NULL;
4615 }
4616}
4617# endif
4618
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619/*
4620 * Function given to ExpandGeneric() to obtain the possible arguments of the
4621 * ":language" command.
4622 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623 char_u *
4624get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004625 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 int idx;
4627{
4628 if (idx == 0)
4629 return (char_u *)"messages";
4630 if (idx == 1)
4631 return (char_u *)"ctype";
4632 if (idx == 2)
4633 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004634
4635 init_locales();
4636 if (locales == NULL)
4637 return NULL;
4638 return locales[idx - 3];
4639}
4640
4641/*
4642 * Function given to ExpandGeneric() to obtain the available locales.
4643 */
4644 char_u *
4645get_locales(xp, idx)
4646 expand_T *xp UNUSED;
4647 int idx;
4648{
4649 init_locales();
4650 if (locales == NULL)
4651 return NULL;
4652 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653}
4654# endif
4655
4656#endif