blob: 59bf945894a073671586806f6336c52850923f59 [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;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002839 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840
2841 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2842 {
2843 if (after < 0)
2844 after = 0;
2845 if (after > ARGCOUNT)
2846 after = ARGCOUNT;
2847 if (after < ARGCOUNT)
2848 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2849 (ARGCOUNT - after) * sizeof(aentry_T));
2850 for (i = 0; i < count; ++i)
2851 {
2852 ARGLIST[after + i].ae_fname = files[i];
2853 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2854 }
2855 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002856 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2857 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002858 return after;
2859 }
2860
2861 for (i = 0; i < count; ++i)
2862 vim_free(files[i]);
2863 return -1;
2864}
2865
2866#endif /* FEAT_LISTCMDS */
2867
2868#ifdef FEAT_EVAL
2869/*
2870 * ":compiler[!] {name}"
2871 */
2872 void
2873ex_compiler(eap)
2874 exarg_T *eap;
2875{
2876 char_u *buf;
2877 char_u *old_cur_comp = NULL;
2878 char_u *p;
2879
2880 if (*eap->arg == NUL)
2881 {
2882 /* List all compiler scripts. */
2883 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2884 /* ) keep the indenter happy... */
2885 }
2886 else
2887 {
2888 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2889 if (buf != NULL)
2890 {
2891 if (eap->forceit)
2892 {
2893 /* ":compiler! {name}" sets global options */
2894 do_cmdline_cmd((char_u *)
2895 "command -nargs=* CompilerSet set <args>");
2896 }
2897 else
2898 {
2899 /* ":compiler! {name}" sets local options.
2900 * To remain backwards compatible "current_compiler" is always
2901 * used. A user's compiler plugin may set it, the distributed
2902 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002903 * "b:current_compiler" and restore "current_compiler".
2904 * Explicitly prepend "g:" to make it work in a function. */
2905 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906 if (old_cur_comp != NULL)
2907 old_cur_comp = vim_strsave(old_cur_comp);
2908 do_cmdline_cmd((char_u *)
2909 "command -nargs=* CompilerSet setlocal <args>");
2910 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002911 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002912 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913
2914 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002915 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2917 vim_free(buf);
2918
2919 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2920
2921 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002922 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 if (p != NULL)
2924 set_internal_string_var((char_u *)"b:current_compiler", p);
2925
2926 /* Restore "current_compiler" for ":compiler {name}". */
2927 if (!eap->forceit)
2928 {
2929 if (old_cur_comp != NULL)
2930 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002931 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932 old_cur_comp);
2933 vim_free(old_cur_comp);
2934 }
2935 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002936 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 }
2938 }
2939 }
2940}
2941#endif
2942
2943/*
2944 * ":runtime {name}"
2945 */
2946 void
2947ex_runtime(eap)
2948 exarg_T *eap;
2949{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002950 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951}
2952
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002953static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954
2955 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002956source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002957 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002958 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002960 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002961}
2962
2963/*
2964 * Source the file "name" from all directories in 'runtimepath'.
2965 * "name" can contain wildcards.
2966 * When "all" is TRUE, source all files, otherwise only the first one.
2967 * return FAIL when no file could be sourced, OK otherwise.
2968 */
2969 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002970source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971 char_u *name;
2972 int all;
2973{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002974 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002975}
2976
2977/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002978 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2979 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002980 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2981 * used.
2982 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002983 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002984 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2985 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002986 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987 */
2988 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002989do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990 char_u *name;
2991 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002992 void (*callback)__ARGS((char_u *fname, void *ck));
2993 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002994{
2995 char_u *rtp;
2996 char_u *np;
2997 char_u *buf;
2998 char_u *rtp_copy;
2999 char_u *tail;
3000 int num_files;
3001 char_u **files;
3002 int i;
3003 int did_one = FALSE;
3004#ifdef AMIGA
3005 struct Process *proc = (struct Process *)FindTask(0L);
3006 APTR save_winptr = proc->pr_WindowPtr;
3007
3008 /* Avoid a requester here for a volume that doesn't exist. */
3009 proc->pr_WindowPtr = (APTR)-1L;
3010#endif
3011
3012 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3013 * value. */
3014 rtp_copy = vim_strsave(p_rtp);
3015 buf = alloc(MAXPATHL);
3016 if (buf != NULL && rtp_copy != NULL)
3017 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003018 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003019 {
3020 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003021 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003023 verbose_leave();
3024 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003025
Bram Moolenaar071d4272004-06-13 20:20:40 +00003026 /* Loop over all entries in 'runtimepath'. */
3027 rtp = rtp_copy;
3028 while (*rtp != NUL && (all || !did_one))
3029 {
3030 /* Copy the path from 'runtimepath' to buf[]. */
3031 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003032 if (name == NULL)
3033 {
3034 (*callback)(buf, (void *) &cookie);
3035 if (!did_one)
3036 did_one = (cookie == NULL);
3037 }
3038 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003039 {
3040 add_pathsep(buf);
3041 tail = buf + STRLEN(buf);
3042
3043 /* Loop over all patterns in "name" */
3044 np = name;
3045 while (*np != NUL && (all || !did_one))
3046 {
3047 /* Append the pattern from "name" to buf[]. */
3048 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3049 "\t ");
3050
3051 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003052 {
3053 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003054 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003055 verbose_leave();
3056 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057
3058 /* Expand wildcards, invoke the callback for each match. */
3059 if (gen_expand_wildcards(1, &buf, &num_files, &files,
3060 EW_FILE) == OK)
3061 {
3062 for (i = 0; i < num_files; ++i)
3063 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003064 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065 did_one = TRUE;
3066 if (!all)
3067 break;
3068 }
3069 FreeWild(num_files, files);
3070 }
3071 }
3072 }
3073 }
3074 }
3075 vim_free(buf);
3076 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003077 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003078 {
3079 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003080 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003081 verbose_leave();
3082 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083
3084#ifdef AMIGA
3085 proc->pr_WindowPtr = save_winptr;
3086#endif
3087
3088 return did_one ? OK : FAIL;
3089}
3090
3091#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3092/*
3093 * ":options"
3094 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003095 void
3096ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003097 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098{
3099 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3100}
3101#endif
3102
3103/*
3104 * ":source {fname}"
3105 */
3106 void
3107ex_source(eap)
3108 exarg_T *eap;
3109{
3110#ifdef FEAT_BROWSE
3111 if (cmdmod.browse)
3112 {
3113 char_u *fname = NULL;
3114
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003115 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3117 if (fname != NULL)
3118 {
3119 cmd_source(fname, eap);
3120 vim_free(fname);
3121 }
3122 }
3123 else
3124#endif
3125 cmd_source(eap->arg, eap);
3126}
3127
3128 static void
3129cmd_source(fname, eap)
3130 char_u *fname;
3131 exarg_T *eap;
3132{
3133 if (*fname == NUL)
3134 EMSG(_(e_argreq));
3135
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003137 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003138 * Need to execute the commands directly. This is required at least
3139 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003140 * - ":g" command busy
3141 * - after ":argdo", ":windo" or ":bufdo"
3142 * - another command follows
3143 * - inside a loop
3144 */
3145 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3146#ifdef FEAT_EVAL
3147 || eap->cstack->cs_idx >= 0
3148#endif
3149 );
3150
3151 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003152 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153 EMSG2(_(e_notopen), fname);
3154}
3155
3156/*
3157 * ":source" and associated commands.
3158 */
3159/*
3160 * Structure used to store info for each sourced file.
3161 * It is shared between do_source() and getsourceline().
3162 * This is required, because it needs to be handed to do_cmdline() and
3163 * sourcing can be done recursively.
3164 */
3165struct source_cookie
3166{
3167 FILE *fp; /* opened file for sourcing */
3168 char_u *nextline; /* if not NULL: line that was read ahead */
3169 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003170#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003171 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3172 int error; /* TRUE if LF found after CR-LF */
3173#endif
3174#ifdef FEAT_EVAL
3175 linenr_T breakpoint; /* next line with breakpoint or zero */
3176 char_u *fname; /* name of sourced file */
3177 int dbg_tick; /* debug_tick when breakpoint was set */
3178 int level; /* top nesting level of sourced file */
3179#endif
3180#ifdef FEAT_MBYTE
3181 vimconv_T conv; /* type of conversion */
3182#endif
3183};
3184
3185#ifdef FEAT_EVAL
3186/*
3187 * Return the address holding the next breakpoint line for a source cookie.
3188 */
3189 linenr_T *
3190source_breakpoint(cookie)
3191 void *cookie;
3192{
3193 return &((struct source_cookie *)cookie)->breakpoint;
3194}
3195
3196/*
3197 * Return the address holding the debug tick for a source cookie.
3198 */
3199 int *
3200source_dbg_tick(cookie)
3201 void *cookie;
3202{
3203 return &((struct source_cookie *)cookie)->dbg_tick;
3204}
3205
3206/*
3207 * Return the nesting level for a source cookie.
3208 */
3209 int
3210source_level(cookie)
3211 void *cookie;
3212{
3213 return ((struct source_cookie *)cookie)->level;
3214}
3215#endif
3216
3217static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
3218
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003219#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3220# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221static FILE *fopen_noinh_readbin __ARGS((char *filename));
3222
3223/*
3224 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003225 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 */
3227 static FILE *
3228fopen_noinh_readbin(filename)
3229 char *filename;
3230{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003231# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003232 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3233# else
3234 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003235# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236
3237 if (fd_tmp == -1)
3238 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003239
3240# ifdef HAVE_FD_CLOEXEC
3241 {
3242 int fdflags = fcntl(fd_tmp, F_GETFD);
3243 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003244 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003245 }
3246# endif
3247
Bram Moolenaar071d4272004-06-13 20:20:40 +00003248 return fdopen(fd_tmp, READBIN);
3249}
3250#endif
3251
3252
3253/*
3254 * do_source: Read the file "fname" and execute its lines as EX commands.
3255 *
3256 * This function may be called recursively!
3257 *
3258 * return FAIL if file could not be opened, OK otherwise
3259 */
3260 int
3261do_source(fname, check_other, is_vimrc)
3262 char_u *fname;
3263 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003264 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265{
3266 struct source_cookie cookie;
3267 char_u *save_sourcing_name;
3268 linenr_T save_sourcing_lnum;
3269 char_u *p;
3270 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003271 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272 int retval = FAIL;
3273#ifdef FEAT_EVAL
3274 scid_T save_current_SID;
3275 static scid_T last_current_SID = 0;
3276 void *save_funccalp;
3277 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003278 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003279# ifdef UNIX
3280 struct stat st;
3281 int stat_ok;
3282# endif
3283#endif
3284#ifdef STARTUPTIME
3285 struct timeval tv_rel;
3286 struct timeval tv_start;
3287#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003288#ifdef FEAT_PROFILE
3289 proftime_T wait_start;
3290#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003293 if (p == NULL)
3294 return retval;
3295 fname_exp = fix_fname(p);
3296 vim_free(p);
3297 if (fname_exp == NULL)
3298 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299 if (mch_isdir(fname_exp))
3300 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003301 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302 goto theend;
3303 }
3304
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003305#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003306 /* Apply SourceCmd autocommands, they should get the file and source it. */
3307 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3308 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3309 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003310 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003311# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003312 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003313# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003314 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003315# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003316 goto theend;
3317 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003318
3319 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003320 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3321#endif
3322
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003323#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3325#else
3326 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3327#endif
3328 if (cookie.fp == NULL && check_other)
3329 {
3330 /*
3331 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3332 * and ".exrc" by "_exrc" or vice versa.
3333 */
3334 p = gettail(fname_exp);
3335 if ((*p == '.' || *p == '_')
3336 && (STRICMP(p + 1, "vimrc") == 0
3337 || STRICMP(p + 1, "gvimrc") == 0
3338 || STRICMP(p + 1, "exrc") == 0))
3339 {
3340 if (*p == '_')
3341 *p = '.';
3342 else
3343 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003344#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3346#else
3347 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3348#endif
3349 }
3350 }
3351
3352 if (cookie.fp == NULL)
3353 {
3354 if (p_verbose > 0)
3355 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003356 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003357 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003358 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003359 else
3360 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003361 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003362 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363 }
3364 goto theend;
3365 }
3366
3367 /*
3368 * The file exists.
3369 * - In verbose mode, give a message.
3370 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3371 */
3372 if (p_verbose > 1)
3373 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003374 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003376 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377 else
3378 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003379 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003380 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003382 if (is_vimrc == DOSO_VIMRC)
3383 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3384 else if (is_vimrc == DOSO_GVIMRC)
3385 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003386
3387#ifdef USE_CRNL
3388 /* If no automatic file format: Set default to CR-NL. */
3389 if (*p_ffs == NUL)
3390 cookie.fileformat = EOL_DOS;
3391 else
3392 cookie.fileformat = EOL_UNKNOWN;
3393 cookie.error = FALSE;
3394#endif
3395
3396#ifdef USE_CR
3397 /* If no automatic file format: Set default to CR. */
3398 if (*p_ffs == NUL)
3399 cookie.fileformat = EOL_MAC;
3400 else
3401 cookie.fileformat = EOL_UNKNOWN;
3402 cookie.error = FALSE;
3403#endif
3404
3405 cookie.nextline = NULL;
3406 cookie.finished = FALSE;
3407
3408#ifdef FEAT_EVAL
3409 /*
3410 * Check if this script has a breakpoint.
3411 */
3412 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3413 cookie.fname = fname_exp;
3414 cookie.dbg_tick = debug_tick;
3415
3416 cookie.level = ex_nesting_level;
3417#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003418
3419 /*
3420 * Keep the sourcing name/lnum, for recursive calls.
3421 */
3422 save_sourcing_name = sourcing_name;
3423 sourcing_name = fname_exp;
3424 save_sourcing_lnum = sourcing_lnum;
3425 sourcing_lnum = 0;
3426
Bram Moolenaar73881402009-02-04 16:50:47 +00003427#ifdef FEAT_MBYTE
3428 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3429
3430 /* Read the first line so we can check for a UTF-8 BOM. */
3431 firstline = getsourceline(0, (void *)&cookie, 0);
3432 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3433 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3434 {
3435 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3436 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3437 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003438 if (p == NULL)
3439 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003440 if (p != NULL)
3441 {
3442 vim_free(firstline);
3443 firstline = p;
3444 }
3445 }
3446#endif
3447
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003449 if (time_fd != NULL)
3450 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003451#endif
3452
3453#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003454# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003455 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003456 prof_child_enter(&wait_start); /* entering a child now */
3457# endif
3458
3459 /* Don't use local function variables, if called from a function.
3460 * Also starts profiling timer for nested script. */
3461 save_funccalp = save_funccal();
3462
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463 /*
3464 * Check if this script was sourced before to finds its SID.
3465 * If it's new, generate a new SID.
3466 */
3467 save_current_SID = current_SID;
3468# ifdef UNIX
3469 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3470# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003471 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3472 {
3473 si = &SCRIPT_ITEM(current_SID);
3474 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003475 && (
3476# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003477 /* Compare dev/ino when possible, it catches symbolic
3478 * links. Also compare file names, the inode may change
3479 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003480 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003481 && (si->sn_dev == st.st_dev
3482 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003483# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003484 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003485 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003486 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003487 if (current_SID == 0)
3488 {
3489 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003490 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3491 == FAIL)
3492 goto almosttheend;
3493 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003494 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003495 ++script_items.ga_len;
3496 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3497# ifdef FEAT_PROFILE
3498 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003499# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003500 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003501 si = &SCRIPT_ITEM(current_SID);
3502 si->sn_name = fname_exp;
3503 fname_exp = NULL;
3504# ifdef UNIX
3505 if (stat_ok)
3506 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003507 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003508 si->sn_dev = st.st_dev;
3509 si->sn_ino = st.st_ino;
3510 }
3511 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003512 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003513# endif
3514
Bram Moolenaar071d4272004-06-13 20:20:40 +00003515 /* Allocate the local script variables to use for this script. */
3516 new_script_vars(current_SID);
3517 }
3518
Bram Moolenaar05159a02005-02-26 23:04:13 +00003519# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003520 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003521 {
3522 int forceit;
3523
3524 /* Check if we do profiling for this script. */
3525 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3526 {
3527 script_do_profile(si);
3528 si->sn_pr_force = forceit;
3529 }
3530 if (si->sn_prof_on)
3531 {
3532 ++si->sn_pr_count;
3533 profile_start(&si->sn_pr_start);
3534 profile_zero(&si->sn_pr_children);
3535 }
3536 }
3537# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538#endif
3539
3540 /*
3541 * Call do_cmdline, which will call getsourceline() to get the lines.
3542 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003543 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003545 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003546
3547#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003548 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003549 {
3550 /* Get "si" again, "script_items" may have been reallocated. */
3551 si = &SCRIPT_ITEM(current_SID);
3552 if (si->sn_prof_on)
3553 {
3554 profile_end(&si->sn_pr_start);
3555 profile_sub_wait(&wait_start, &si->sn_pr_start);
3556 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003557 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3558 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003559 }
3560 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003561#endif
3562
3563 if (got_int)
3564 EMSG(_(e_interr));
3565 sourcing_name = save_sourcing_name;
3566 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003567 if (p_verbose > 1)
3568 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003569 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003570 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003572 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003573 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003574 }
3575#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003576 if (time_fd != NULL)
3577 {
3578 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3579 time_msg((char *)IObuff, &tv_start);
3580 time_pop(&tv_rel);
3581 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582#endif
3583
3584#ifdef FEAT_EVAL
3585 /*
3586 * After a "finish" in debug mode, need to break at first command of next
3587 * sourced file.
3588 */
3589 if (save_debug_break_level > ex_nesting_level
3590 && debug_break_level == ex_nesting_level)
3591 ++debug_break_level;
3592#endif
3593
Bram Moolenaar05159a02005-02-26 23:04:13 +00003594#ifdef FEAT_EVAL
3595almosttheend:
3596 current_SID = save_current_SID;
3597 restore_funccal(save_funccalp);
3598# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003599 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003600 prof_child_exit(&wait_start); /* leaving a child now */
3601# endif
3602#endif
3603 fclose(cookie.fp);
3604 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003605 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003606#ifdef FEAT_MBYTE
3607 convert_setup(&cookie.conv, NULL, NULL);
3608#endif
3609
Bram Moolenaar071d4272004-06-13 20:20:40 +00003610theend:
3611 vim_free(fname_exp);
3612 return retval;
3613}
3614
3615#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003616
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617/*
3618 * ":scriptnames"
3619 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003620 void
3621ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003622 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003623{
3624 int i;
3625
Bram Moolenaar05159a02005-02-26 23:04:13 +00003626 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3627 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003628 {
3629 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3630 NameBuff, MAXPATHL, TRUE);
3631 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003632 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003633}
3634
3635# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3636/*
3637 * Fix slashes in the list of script names for 'shellslash'.
3638 */
3639 void
3640scriptnames_slash_adjust()
3641{
3642 int i;
3643
Bram Moolenaar05159a02005-02-26 23:04:13 +00003644 for (i = 1; i <= script_items.ga_len; ++i)
3645 if (SCRIPT_ITEM(i).sn_name != NULL)
3646 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003647}
3648# endif
3649
3650/*
3651 * Get a pointer to a script name. Used for ":verbose set".
3652 */
3653 char_u *
3654get_scriptname(id)
3655 scid_T id;
3656{
3657 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003658 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003660 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003662 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003664 return (char_u *)_("environment variable");
3665 if (id == SID_ERROR)
3666 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003667 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003669
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003670# if defined(EXITFREE) || defined(PROTO)
3671 void
3672free_scriptnames()
3673{
3674 int i;
3675
3676 for (i = script_items.ga_len; i > 0; --i)
3677 vim_free(SCRIPT_ITEM(i).sn_name);
3678 ga_clear(&script_items);
3679}
3680# endif
3681
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682#endif
3683
3684#if defined(USE_CR) || defined(PROTO)
3685
3686# if defined(__MSL__) && (__MSL__ >= 22)
3687/*
3688 * Newer version of the Metrowerks library handle DOS and UNIX files
3689 * without help.
3690 * Test with earlier versions, MSL 2.2 is the library supplied with
3691 * Codewarrior Pro 2.
3692 */
3693 char *
3694fgets_cr(s, n, stream)
3695 char *s;
3696 int n;
3697 FILE *stream;
3698{
3699 return fgets(s, n, stream);
3700}
3701# else
3702/*
3703 * Version of fgets() which also works for lines ending in a <CR> only
3704 * (Macintosh format).
3705 * For older versions of the Metrowerks library.
3706 * At least CodeWarrior 9 needed this code.
3707 */
3708 char *
3709fgets_cr(s, n, stream)
3710 char *s;
3711 int n;
3712 FILE *stream;
3713{
3714 int c = 0;
3715 int char_read = 0;
3716
3717 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3718 {
3719 c = fgetc(stream);
3720 s[char_read++] = c;
3721 /* If the file is in DOS format, we need to skip a NL after a CR. I
3722 * thought it was the other way around, but this appears to work... */
3723 if (c == '\n')
3724 {
3725 c = fgetc(stream);
3726 if (c != '\r')
3727 ungetc(c, stream);
3728 }
3729 }
3730
3731 s[char_read] = 0;
3732 if (char_read == 0)
3733 return NULL;
3734
3735 if (feof(stream) && char_read == 1)
3736 return NULL;
3737
3738 return s;
3739}
3740# endif
3741#endif
3742
3743/*
3744 * Get one full line from a sourced file.
3745 * Called by do_cmdline() when it's called from do_source().
3746 *
3747 * Return a pointer to the line in allocated memory.
3748 * Return NULL for end-of-file or some error.
3749 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003750 char_u *
3751getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003752 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003754 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755{
3756 struct source_cookie *sp = (struct source_cookie *)cookie;
3757 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003758 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003759
3760#ifdef FEAT_EVAL
3761 /* If breakpoints have been added/deleted need to check for it. */
3762 if (sp->dbg_tick < debug_tick)
3763 {
3764 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3765 sp->dbg_tick = debug_tick;
3766 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003767# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003768 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003769 script_line_end();
3770# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771#endif
3772 /*
3773 * Get current line. If there is a read-ahead line, use it, otherwise get
3774 * one now.
3775 */
3776 if (sp->finished)
3777 line = NULL;
3778 else if (sp->nextline == NULL)
3779 line = get_one_sourceline(sp);
3780 else
3781 {
3782 line = sp->nextline;
3783 sp->nextline = NULL;
3784 ++sourcing_lnum;
3785 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003786#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003787 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003788 script_line_start();
3789#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790
3791 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3792 * contain the 'C' flag. */
3793 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3794 {
3795 /* compensate for the one line read-ahead */
3796 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003797
3798 /* Get the next line and concatenate it when it starts with a
3799 * backslash. We always need to read the next line, keep it in
3800 * sp->nextline. */
3801 sp->nextline = get_one_sourceline(sp);
3802 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003803 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003804 garray_T ga;
3805
Bram Moolenaarb549a732012-02-22 18:29:33 +01003806 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003807 ga_concat(&ga, line);
3808 ga_concat(&ga, p + 1);
3809 for (;;)
3810 {
3811 vim_free(sp->nextline);
3812 sp->nextline = get_one_sourceline(sp);
3813 if (sp->nextline == NULL)
3814 break;
3815 p = skipwhite(sp->nextline);
3816 if (*p != '\\')
3817 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003818 /* Adjust the growsize to the current length to speed up
3819 * concatenating many lines. */
3820 if (ga.ga_len > 400)
3821 {
3822 if (ga.ga_len > 8000)
3823 ga.ga_growsize = 8000;
3824 else
3825 ga.ga_growsize = ga.ga_len;
3826 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003827 ga_concat(&ga, p + 1);
3828 }
3829 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003831 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832 }
3833 }
3834
3835#ifdef FEAT_MBYTE
3836 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3837 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003838 char_u *s;
3839
Bram Moolenaar071d4272004-06-13 20:20:40 +00003840 /* Convert the encoding of the script line. */
3841 s = string_convert(&sp->conv, line, NULL);
3842 if (s != NULL)
3843 {
3844 vim_free(line);
3845 line = s;
3846 }
3847 }
3848#endif
3849
3850#ifdef FEAT_EVAL
3851 /* Did we encounter a breakpoint? */
3852 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3853 {
3854 dbg_breakpoint(sp->fname, sourcing_lnum);
3855 /* Find next breakpoint. */
3856 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3857 sp->dbg_tick = debug_tick;
3858 }
3859#endif
3860
3861 return line;
3862}
3863
3864 static char_u *
3865get_one_sourceline(sp)
3866 struct source_cookie *sp;
3867{
3868 garray_T ga;
3869 int len;
3870 int c;
3871 char_u *buf;
3872#ifdef USE_CRNL
3873 int has_cr; /* CR-LF found */
3874#endif
3875#ifdef USE_CR
3876 char_u *scan;
3877#endif
3878 int have_read = FALSE;
3879
3880 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003881 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003882
3883 /*
3884 * Loop until there is a finished line (or end-of-file).
3885 */
3886 sourcing_lnum++;
3887 for (;;)
3888 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003889 /* make room to read at least 120 (more) characters */
3890 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003891 break;
3892 buf = (char_u *)ga.ga_data;
3893
3894#ifdef USE_CR
3895 if (sp->fileformat == EOL_MAC)
3896 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003897 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3898 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003899 break;
3900 }
3901 else
3902#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003903 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3904 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003906 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003907#ifdef USE_CRNL
3908 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3909 * CTRL-Z by its own, or after a NL. */
3910 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3911 && sp->fileformat == EOL_DOS
3912 && buf[len - 1] == Ctrl_Z)
3913 {
3914 buf[len - 1] = NUL;
3915 break;
3916 }
3917#endif
3918
3919#ifdef USE_CR
3920 /* If the read doesn't stop on a new line, and there's
3921 * some CR then we assume a Mac format */
3922 if (sp->fileformat == EOL_UNKNOWN)
3923 {
3924 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3925 sp->fileformat = EOL_MAC;
3926 else
3927 sp->fileformat = EOL_UNIX;
3928 }
3929
3930 if (sp->fileformat == EOL_MAC)
3931 {
3932 scan = vim_strchr(buf, '\r');
3933
3934 if (scan != NULL)
3935 {
3936 *scan = '\n';
3937 if (*(scan + 1) != 0)
3938 {
3939 *(scan + 1) = 0;
3940 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3941 }
3942 }
3943 len = STRLEN(buf);
3944 }
3945#endif
3946
3947 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948 ga.ga_len = len;
3949
3950 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003951 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003952 continue;
3953
3954 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3955 {
3956#ifdef USE_CRNL
3957 has_cr = (len >= 2 && buf[len - 2] == '\r');
3958 if (sp->fileformat == EOL_UNKNOWN)
3959 {
3960 if (has_cr)
3961 sp->fileformat = EOL_DOS;
3962 else
3963 sp->fileformat = EOL_UNIX;
3964 }
3965
3966 if (sp->fileformat == EOL_DOS)
3967 {
3968 if (has_cr) /* replace trailing CR */
3969 {
3970 buf[len - 2] = '\n';
3971 --len;
3972 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003973 }
3974 else /* lines like ":map xx yy^M" will have failed */
3975 {
3976 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003977 {
3978 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003979 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003980 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003981 sp->error = TRUE;
3982 sp->fileformat = EOL_UNIX;
3983 }
3984 }
3985#endif
3986 /* The '\n' is escaped if there is an odd number of ^V's just
3987 * before it, first set "c" just before the 'V's and then check
3988 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3989 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3990 ;
3991 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3992 {
3993 sourcing_lnum++;
3994 continue;
3995 }
3996
3997 buf[len - 1] = NUL; /* remove the NL */
3998 }
3999
4000 /*
4001 * Check for ^C here now and then, so recursive :so can be broken.
4002 */
4003 line_breakcheck();
4004 break;
4005 }
4006
4007 if (have_read)
4008 return (char_u *)ga.ga_data;
4009
4010 vim_free(ga.ga_data);
4011 return NULL;
4012}
4013
Bram Moolenaar05159a02005-02-26 23:04:13 +00004014#if defined(FEAT_PROFILE) || defined(PROTO)
4015/*
4016 * Called when starting to read a script line.
4017 * "sourcing_lnum" must be correct!
4018 * When skipping lines it may not actually be executed, but we won't find out
4019 * until later and we need to store the time now.
4020 */
4021 void
4022script_line_start()
4023{
4024 scriptitem_T *si;
4025 sn_prl_T *pp;
4026
4027 if (current_SID <= 0 || current_SID > script_items.ga_len)
4028 return;
4029 si = &SCRIPT_ITEM(current_SID);
4030 if (si->sn_prof_on && sourcing_lnum >= 1)
4031 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004032 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004033 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004034 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004035 si->sn_prl_idx = sourcing_lnum - 1;
4036 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4037 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4038 {
4039 /* Zero counters for a line that was not used before. */
4040 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4041 pp->snp_count = 0;
4042 profile_zero(&pp->sn_prl_total);
4043 profile_zero(&pp->sn_prl_self);
4044 ++si->sn_prl_ga.ga_len;
4045 }
4046 si->sn_prl_execed = FALSE;
4047 profile_start(&si->sn_prl_start);
4048 profile_zero(&si->sn_prl_children);
4049 profile_get_wait(&si->sn_prl_wait);
4050 }
4051}
4052
4053/*
4054 * Called when actually executing a function line.
4055 */
4056 void
4057script_line_exec()
4058{
4059 scriptitem_T *si;
4060
4061 if (current_SID <= 0 || current_SID > script_items.ga_len)
4062 return;
4063 si = &SCRIPT_ITEM(current_SID);
4064 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4065 si->sn_prl_execed = TRUE;
4066}
4067
4068/*
4069 * Called when done with a function line.
4070 */
4071 void
4072script_line_end()
4073{
4074 scriptitem_T *si;
4075 sn_prl_T *pp;
4076
4077 if (current_SID <= 0 || current_SID > script_items.ga_len)
4078 return;
4079 si = &SCRIPT_ITEM(current_SID);
4080 if (si->sn_prof_on && si->sn_prl_idx >= 0
4081 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4082 {
4083 if (si->sn_prl_execed)
4084 {
4085 pp = &PRL_ITEM(si, si->sn_prl_idx);
4086 ++pp->snp_count;
4087 profile_end(&si->sn_prl_start);
4088 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004089 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004090 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4091 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004092 }
4093 si->sn_prl_idx = -1;
4094 }
4095}
4096#endif
4097
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098/*
4099 * ":scriptencoding": Set encoding conversion for a sourced script.
4100 * Without the multi-byte feature it's simply ignored.
4101 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004102 void
4103ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004104 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004105{
4106#ifdef FEAT_MBYTE
4107 struct source_cookie *sp;
4108 char_u *name;
4109
4110 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4111 {
4112 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4113 return;
4114 }
4115
4116 if (*eap->arg != NUL)
4117 {
4118 name = enc_canonize(eap->arg);
4119 if (name == NULL) /* out of memory */
4120 return;
4121 }
4122 else
4123 name = eap->arg;
4124
4125 /* Setup for conversion from the specified encoding to 'encoding'. */
4126 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4127 convert_setup(&sp->conv, name, p_enc);
4128
4129 if (name != eap->arg)
4130 vim_free(name);
4131#endif
4132}
4133
4134#if defined(FEAT_EVAL) || defined(PROTO)
4135/*
4136 * ":finish": Mark a sourced file as finished.
4137 */
4138 void
4139ex_finish(eap)
4140 exarg_T *eap;
4141{
4142 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4143 do_finish(eap, FALSE);
4144 else
4145 EMSG(_("E168: :finish used outside of a sourced file"));
4146}
4147
4148/*
4149 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4150 * Also called for a pending finish at the ":endtry" or after returning from
4151 * an extra do_cmdline(). "reanimate" is used in the latter case.
4152 */
4153 void
4154do_finish(eap, reanimate)
4155 exarg_T *eap;
4156 int reanimate;
4157{
4158 int idx;
4159
4160 if (reanimate)
4161 ((struct source_cookie *)getline_cookie(eap->getline,
4162 eap->cookie))->finished = FALSE;
4163
4164 /*
4165 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4166 * not in its finally clause (which then is to be executed next) is found.
4167 * In this case, make the ":finish" pending for execution at the ":endtry".
4168 * Otherwise, finish normally.
4169 */
4170 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4171 if (idx >= 0)
4172 {
4173 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4174 report_make_pending(CSTP_FINISH, NULL);
4175 }
4176 else
4177 ((struct source_cookie *)getline_cookie(eap->getline,
4178 eap->cookie))->finished = TRUE;
4179}
4180
4181
4182/*
4183 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4184 * message for missing ":endif".
4185 * Return FALSE when not sourcing a file.
4186 */
4187 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00004188source_finished(fgetline, cookie)
4189 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004190 void *cookie;
4191{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004192 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004193 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004194 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004195}
4196#endif
4197
4198#if defined(FEAT_LISTCMDS) || defined(PROTO)
4199/*
4200 * ":checktime [buffer]"
4201 */
4202 void
4203ex_checktime(eap)
4204 exarg_T *eap;
4205{
4206 buf_T *buf;
4207 int save_no_check_timestamps = no_check_timestamps;
4208
4209 no_check_timestamps = 0;
4210 if (eap->addr_count == 0) /* default is all buffers */
4211 check_timestamps(FALSE);
4212 else
4213 {
4214 buf = buflist_findnr((int)eap->line2);
4215 if (buf != NULL) /* cannot happen? */
4216 (void)buf_check_timestamp(buf, FALSE);
4217 }
4218 no_check_timestamps = save_no_check_timestamps;
4219}
4220#endif
4221
Bram Moolenaar071d4272004-06-13 20:20:40 +00004222#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4223 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004224# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225static char *get_locale_val __ARGS((int what));
4226
4227 static char *
4228get_locale_val(what)
4229 int what;
4230{
4231 char *loc;
4232
4233 /* Obtain the locale value from the libraries. For DJGPP this is
4234 * redefined and it doesn't use the arguments. */
4235 loc = setlocale(what, NULL);
4236
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004237# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004238 if (loc != NULL)
4239 {
4240 char_u *p;
4241
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004242 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4243 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004244 p = vim_strchr(loc, '=');
4245 if (p != NULL)
4246 {
4247 loc = ++p;
4248 while (*p != NUL) /* remove trailing newline */
4249 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004250 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004251 {
4252 *p = NUL;
4253 break;
4254 }
4255 ++p;
4256 }
4257 }
4258 }
4259# endif
4260
4261 return loc;
4262}
4263#endif
4264
4265
4266#ifdef WIN32
4267/*
4268 * On MS-Windows locale names are strings like "German_Germany.1252", but
4269 * gettext expects "de". Try to translate one into another here for a few
4270 * supported languages.
4271 */
4272 static char_u *
4273gettext_lang(char_u *name)
4274{
4275 int i;
4276 static char *(mtable[]) = {
4277 "afrikaans", "af",
4278 "czech", "cs",
4279 "dutch", "nl",
4280 "german", "de",
4281 "english_united kingdom", "en_GB",
4282 "spanish", "es",
4283 "french", "fr",
4284 "italian", "it",
4285 "japanese", "ja",
4286 "korean", "ko",
4287 "norwegian", "no",
4288 "polish", "pl",
4289 "russian", "ru",
4290 "slovak", "sk",
4291 "swedish", "sv",
4292 "ukrainian", "uk",
4293 "chinese_china", "zh_CN",
4294 "chinese_taiwan", "zh_TW",
4295 NULL};
4296
4297 for (i = 0; mtable[i] != NULL; i += 2)
4298 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4299 return mtable[i + 1];
4300 return name;
4301}
4302#endif
4303
4304#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4305/*
4306 * Obtain the current messages language. Used to set the default for
4307 * 'helplang'. May return NULL or an empty string.
4308 */
4309 char_u *
4310get_mess_lang()
4311{
4312 char_u *p;
4313
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004314# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004315# if defined(LC_MESSAGES)
4316 p = (char_u *)get_locale_val(LC_MESSAGES);
4317# else
4318 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004319 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4320 * and LC_MONETARY may be set differently for a Japanese working in the
4321 * US. */
4322 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323# endif
4324# else
4325 p = mch_getenv((char_u *)"LC_ALL");
4326 if (p == NULL || *p == NUL)
4327 {
4328 p = mch_getenv((char_u *)"LC_MESSAGES");
4329 if (p == NULL || *p == NUL)
4330 p = mch_getenv((char_u *)"LANG");
4331 }
4332# endif
4333# ifdef WIN32
4334 p = gettext_lang(p);
4335# endif
4336 return p;
4337}
4338#endif
4339
Bram Moolenaardef9e822004-12-31 20:58:58 +00004340/* Complicated #if; matches with where get_mess_env() is used below. */
4341#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4342 && defined(LC_MESSAGES))) \
4343 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4344 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4345 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346static char_u *get_mess_env __ARGS((void));
4347
4348/*
4349 * Get the language used for messages from the environment.
4350 */
4351 static char_u *
4352get_mess_env()
4353{
4354 char_u *p;
4355
4356 p = mch_getenv((char_u *)"LC_ALL");
4357 if (p == NULL || *p == NUL)
4358 {
4359 p = mch_getenv((char_u *)"LC_MESSAGES");
4360 if (p == NULL || *p == NUL)
4361 {
4362 p = mch_getenv((char_u *)"LANG");
4363 if (p != NULL && VIM_ISDIGIT(*p))
4364 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004365# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004366 if (p == NULL || *p == NUL)
4367 p = (char_u *)get_locale_val(LC_CTYPE);
4368# endif
4369 }
4370 }
4371 return p;
4372}
4373#endif
4374
4375#if defined(FEAT_EVAL) || defined(PROTO)
4376
4377/*
4378 * Set the "v:lang" variable according to the current locale setting.
4379 * Also do "v:lc_time"and "v:ctype".
4380 */
4381 void
4382set_lang_var()
4383{
4384 char_u *loc;
4385
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004386# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004387 loc = (char_u *)get_locale_val(LC_CTYPE);
4388# else
4389 /* setlocale() not supported: use the default value */
4390 loc = (char_u *)"C";
4391# endif
4392 set_vim_var_string(VV_CTYPE, loc, -1);
4393
4394 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4395 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004396# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397 loc = (char_u *)get_locale_val(LC_MESSAGES);
4398# else
4399 loc = get_mess_env();
4400# endif
4401 set_vim_var_string(VV_LANG, loc, -1);
4402
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004403# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004404 loc = (char_u *)get_locale_val(LC_TIME);
4405# endif
4406 set_vim_var_string(VV_LC_TIME, loc, -1);
4407}
4408#endif
4409
4410#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4411 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4412/*
4413 * ":language": Set the language (locale).
4414 */
4415 void
4416ex_language(eap)
4417 exarg_T *eap;
4418{
4419 char *loc;
4420 char_u *p;
4421 char_u *name;
4422 int what = LC_ALL;
4423 char *whatstr = "";
4424#ifdef LC_MESSAGES
4425# define VIM_LC_MESSAGES LC_MESSAGES
4426#else
4427# define VIM_LC_MESSAGES 6789
4428#endif
4429
4430 name = eap->arg;
4431
4432 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4433 * Allow abbreviation, but require at least 3 characters to avoid
4434 * confusion with a two letter language name "me" or "ct". */
4435 p = skiptowhite(eap->arg);
4436 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4437 {
4438 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4439 {
4440 what = VIM_LC_MESSAGES;
4441 name = skipwhite(p);
4442 whatstr = "messages ";
4443 }
4444 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4445 {
4446 what = LC_CTYPE;
4447 name = skipwhite(p);
4448 whatstr = "ctype ";
4449 }
4450 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4451 {
4452 what = LC_TIME;
4453 name = skipwhite(p);
4454 whatstr = "time ";
4455 }
4456 }
4457
4458 if (*name == NUL)
4459 {
4460#ifndef LC_MESSAGES
4461 if (what == VIM_LC_MESSAGES)
4462 p = get_mess_env();
4463 else
4464#endif
4465 p = (char_u *)setlocale(what, NULL);
4466 if (p == NULL || *p == NUL)
4467 p = (char_u *)"Unknown";
4468 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4469 }
4470 else
4471 {
4472#ifndef LC_MESSAGES
4473 if (what == VIM_LC_MESSAGES)
4474 loc = "";
4475 else
4476#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004477 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004478 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004479#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4480 /* Make sure strtod() uses a decimal point, not a comma. */
4481 setlocale(LC_NUMERIC, "C");
4482#endif
4483 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004484 if (loc == NULL)
4485 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4486 else
4487 {
4488#ifdef HAVE_NL_MSG_CAT_CNTR
4489 /* Need to do this for GNU gettext, otherwise cached translations
4490 * will be used again. */
4491 extern int _nl_msg_cat_cntr;
4492
4493 ++_nl_msg_cat_cntr;
4494#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004495 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4497
4498 if (what != LC_TIME)
4499 {
4500 /* Tell gettext() what to translate to. It apparently doesn't
4501 * use the currently effective locale. Also do this when
4502 * FEAT_GETTEXT isn't defined, so that shell commands use this
4503 * value. */
4504 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004505 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004506 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004507
4508 /* Clear $LANGUAGE because GNU gettext uses it. */
4509 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004510# ifdef WIN32
4511 /* Apparently MS-Windows printf() may cause a crash when
4512 * we give it 8-bit text while it's expecting text in the
4513 * current locale. This call avoids that. */
4514 setlocale(LC_CTYPE, "C");
4515# endif
4516 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004517 if (what != LC_CTYPE)
4518 {
4519 char_u *mname;
4520#ifdef WIN32
4521 mname = gettext_lang(name);
4522#else
4523 mname = name;
4524#endif
4525 vim_setenv((char_u *)"LC_MESSAGES", mname);
4526#ifdef FEAT_MULTI_LANG
4527 set_helplang_default(mname);
4528#endif
4529 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530 }
4531
4532# ifdef FEAT_EVAL
4533 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4534 set_lang_var();
4535# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004536# ifdef FEAT_TITLE
4537 maketitle();
4538# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539 }
4540 }
4541}
4542
4543# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004544
4545static char_u **locales = NULL; /* Array of all available locales */
4546static int did_init_locales = FALSE;
4547
4548static void init_locales __ARGS((void));
4549static char_u **find_locales __ARGS((void));
4550
4551/*
4552 * Lazy initialization of all available locales.
4553 */
4554 static void
4555init_locales()
4556{
4557 if (!did_init_locales)
4558 {
4559 did_init_locales = TRUE;
4560 locales = find_locales();
4561 }
4562}
4563
4564/* Return an array of strings for all available locales + NULL for the
4565 * last element. Return NULL in case of error. */
4566 static char_u **
4567find_locales()
4568{
4569 garray_T locales_ga;
4570 char_u *loc;
4571
4572 /* Find all available locales by running command "locale -a". If this
4573 * doesn't work we won't have completion. */
4574 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004575 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004576 if (locale_a == NULL)
4577 return NULL;
4578 ga_init2(&locales_ga, sizeof(char_u *), 20);
4579
4580 /* Transform locale_a string where each locale is separated by "\n"
4581 * into an array of locale strings. */
4582 loc = (char_u *)strtok((char *)locale_a, "\n");
4583
4584 while (loc != NULL)
4585 {
4586 if (ga_grow(&locales_ga, 1) == FAIL)
4587 break;
4588 loc = vim_strsave(loc);
4589 if (loc == NULL)
4590 break;
4591
4592 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4593 loc = (char_u *)strtok(NULL, "\n");
4594 }
4595 vim_free(locale_a);
4596 if (ga_grow(&locales_ga, 1) == FAIL)
4597 {
4598 ga_clear(&locales_ga);
4599 return NULL;
4600 }
4601 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4602 return (char_u **)locales_ga.ga_data;
4603}
4604
4605# if defined(EXITFREE) || defined(PROTO)
4606 void
4607free_locales()
4608{
4609 int i;
4610 if (locales != NULL)
4611 {
4612 for (i = 0; locales[i] != NULL; i++)
4613 vim_free(locales[i]);
4614 vim_free(locales);
4615 locales = NULL;
4616 }
4617}
4618# endif
4619
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620/*
4621 * Function given to ExpandGeneric() to obtain the possible arguments of the
4622 * ":language" command.
4623 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004624 char_u *
4625get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004626 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 int idx;
4628{
4629 if (idx == 0)
4630 return (char_u *)"messages";
4631 if (idx == 1)
4632 return (char_u *)"ctype";
4633 if (idx == 2)
4634 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004635
4636 init_locales();
4637 if (locales == NULL)
4638 return NULL;
4639 return locales[idx - 3];
4640}
4641
4642/*
4643 * Function given to ExpandGeneric() to obtain the available locales.
4644 */
4645 char_u *
4646get_locales(xp, idx)
4647 expand_T *xp UNUSED;
4648 int idx;
4649{
4650 init_locales();
4651 if (locales == NULL)
4652 return NULL;
4653 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654}
4655# endif
4656
4657#endif