blob: 5b113668d1d77be79c1111d73fba1e9474718044 [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;
2565 }
2566 }
2567 else if (*eap->arg == NUL)
2568 EMSG(_(e_argreq));
2569 else
2570 do_arglist(eap->arg, AL_DEL, 0);
2571#ifdef FEAT_TITLE
2572 maketitle();
2573#endif
2574}
2575
2576/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002577 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578 */
2579 void
2580ex_listdo(eap)
2581 exarg_T *eap;
2582{
2583 int i;
2584#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002585 win_T *wp;
2586 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002588 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 int next_fnum = 0;
2590#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2591 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002593 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002594#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002595 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002596 int qf_idx;
2597#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598
2599#ifndef FEAT_WINDOWS
2600 if (eap->cmdidx == CMD_windo)
2601 {
2602 ex_ni(eap);
2603 return;
2604 }
2605#endif
2606
2607#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002608 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002609 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2610 * great speed improvement. */
2611 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002613#ifdef FEAT_CLIPBOARD
2614 start_global_changes();
2615#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616
2617 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002618 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002619 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002620 || !check_changed(curbuf, CCGD_AW
2621 | (eap->forceit ? CCGD_FORCEIT : 0)
2622 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002625 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002627 wp = firstwin;
2628 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002629#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002630 switch (eap->cmdidx)
2631 {
2632#ifdef FEAT_WINDOWS
2633 case CMD_windo:
2634 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2635 i++;
2636 break;
2637 case CMD_tabdo:
2638 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2639 i++;
2640 break;
2641#endif
2642 case CMD_argdo:
2643 i = eap->line1 - 1;
2644 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002645 default:
2646 break;
2647 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648 /* set pcmark now */
2649 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002650 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002651 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002652 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002653 || !buf->b_p_bl); buf = buf->b_next)
2654 if (buf->b_fnum > eap->line2)
2655 {
2656 buf = NULL;
2657 break;
2658 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002659 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002660 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002661 }
2662#ifdef FEAT_QUICKFIX
2663 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2664 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2665 {
2666 qf_size = qf_get_size(eap);
2667 if (qf_size <= 0 || eap->line1 > qf_size)
2668 buf = NULL;
2669 else
2670 {
2671 ex_cc(eap);
2672
2673 buf = curbuf;
2674 i = eap->line1 - 1;
2675 if (eap->addr_count <= 0)
2676 /* default is all the quickfix/location list entries */
2677 eap->line2 = qf_size;
2678 }
2679 }
2680#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 else
2682 setpcmark();
2683 listcmd_busy = TRUE; /* avoids setting pcmark below */
2684
Bram Moolenaare25bb902015-02-27 20:33:37 +01002685 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686 {
2687 if (eap->cmdidx == CMD_argdo)
2688 {
2689 /* go to argument "i" */
2690 if (i == ARGCOUNT)
2691 break;
2692 /* Don't call do_argfile() when already there, it will try
2693 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002694 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002695 {
2696 /* Clear 'shm' to avoid that the file message overwrites
2697 * any output from the command. */
2698 p_shm_save = vim_strsave(p_shm);
2699 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002701 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2702 vim_free(p_shm_save);
2703 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002704 if (curwin->w_arg_idx != i)
2705 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002706 }
2707#ifdef FEAT_WINDOWS
2708 else if (eap->cmdidx == CMD_windo)
2709 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002710 /* go to window "wp" */
2711 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002713 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002714 if (curwin != wp)
2715 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002716 wp = curwin->w_next;
2717 }
2718 else if (eap->cmdidx == CMD_tabdo)
2719 {
2720 /* go to window "tp" */
2721 if (!valid_tabpage(tp))
2722 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002723 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002724 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725 }
2726#endif
2727 else if (eap->cmdidx == CMD_bufdo)
2728 {
2729 /* Remember the number of the next listed buffer, in case
2730 * ":bwipe" is used or autocommands do something strange. */
2731 next_fnum = -1;
2732 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2733 if (buf->b_p_bl)
2734 {
2735 next_fnum = buf->b_fnum;
2736 break;
2737 }
2738 }
2739
Bram Moolenaara162bc52015-01-07 16:54:21 +01002740 ++i;
2741
Bram Moolenaar071d4272004-06-13 20:20:40 +00002742 /* execute the command */
2743 do_cmdline(eap->arg, eap->getline, eap->cookie,
2744 DOCMD_VERBOSE + DOCMD_NOWAIT);
2745
2746 if (eap->cmdidx == CMD_bufdo)
2747 {
2748 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002749 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002750 break;
2751 /* Check if the buffer still exists. */
2752 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2753 if (buf->b_fnum == next_fnum)
2754 break;
2755 if (buf == NULL)
2756 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002757
2758 /* Go to the next buffer. Clear 'shm' to avoid that the file
2759 * message overwrites any output from the command. */
2760 p_shm_save = vim_strsave(p_shm);
2761 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002762 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002763 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2764 vim_free(p_shm_save);
2765
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002766 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002767 if (curbuf->b_fnum != next_fnum)
2768 break;
2769 }
2770
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002771#ifdef FEAT_QUICKFIX
2772 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2773 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2774 {
2775 if (i >= qf_size || i >= eap->line2)
2776 break;
2777
2778 qf_idx = qf_get_cur_idx(eap);
2779
2780 ex_cnext(eap);
2781
2782 /* If jumping to the next quickfix entry fails, quit here */
2783 if (qf_get_cur_idx(eap) == qf_idx)
2784 break;
2785 }
2786#endif
2787
Bram Moolenaar071d4272004-06-13 20:20:40 +00002788 if (eap->cmdidx == CMD_windo)
2789 {
2790 validate_cursor(); /* cursor may have moved */
2791#ifdef FEAT_SCROLLBIND
2792 /* required when 'scrollbind' has been set */
2793 if (curwin->w_p_scb)
2794 do_check_scrollbind(TRUE);
2795#endif
2796 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002797
2798#ifdef FEAT_WINDOWS
2799 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2800 if (i+1 > eap->line2)
2801 break;
2802#endif
2803 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2804 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002805 }
2806 listcmd_busy = FALSE;
2807 }
2808
2809#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002810 if (save_ei != NULL)
2811 {
2812 au_event_restore(save_ei);
2813 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2814 curbuf->b_fname, TRUE, curbuf);
2815 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002816#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002817#ifdef FEAT_CLIPBOARD
2818 end_global_changes();
2819#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820}
2821
2822/*
2823 * Add files[count] to the arglist of the current window after arg "after".
2824 * The file names in files[count] must have been allocated and are taken over.
2825 * Files[] itself is not taken over.
2826 * Returns index of first added argument. Returns -1 when failed (out of mem).
2827 */
2828 static int
2829alist_add_list(count, files, after)
2830 int count;
2831 char_u **files;
2832 int after; /* where to add: 0 = before first one */
2833{
2834 int i;
2835
2836 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2837 {
2838 if (after < 0)
2839 after = 0;
2840 if (after > ARGCOUNT)
2841 after = ARGCOUNT;
2842 if (after < ARGCOUNT)
2843 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2844 (ARGCOUNT - after) * sizeof(aentry_T));
2845 for (i = 0; i < count; ++i)
2846 {
2847 ARGLIST[after + i].ae_fname = files[i];
2848 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2849 }
2850 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851 if (curwin->w_arg_idx >= after)
2852 ++curwin->w_arg_idx;
2853 return after;
2854 }
2855
2856 for (i = 0; i < count; ++i)
2857 vim_free(files[i]);
2858 return -1;
2859}
2860
2861#endif /* FEAT_LISTCMDS */
2862
2863#ifdef FEAT_EVAL
2864/*
2865 * ":compiler[!] {name}"
2866 */
2867 void
2868ex_compiler(eap)
2869 exarg_T *eap;
2870{
2871 char_u *buf;
2872 char_u *old_cur_comp = NULL;
2873 char_u *p;
2874
2875 if (*eap->arg == NUL)
2876 {
2877 /* List all compiler scripts. */
2878 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2879 /* ) keep the indenter happy... */
2880 }
2881 else
2882 {
2883 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2884 if (buf != NULL)
2885 {
2886 if (eap->forceit)
2887 {
2888 /* ":compiler! {name}" sets global options */
2889 do_cmdline_cmd((char_u *)
2890 "command -nargs=* CompilerSet set <args>");
2891 }
2892 else
2893 {
2894 /* ":compiler! {name}" sets local options.
2895 * To remain backwards compatible "current_compiler" is always
2896 * used. A user's compiler plugin may set it, the distributed
2897 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002898 * "b:current_compiler" and restore "current_compiler".
2899 * Explicitly prepend "g:" to make it work in a function. */
2900 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901 if (old_cur_comp != NULL)
2902 old_cur_comp = vim_strsave(old_cur_comp);
2903 do_cmdline_cmd((char_u *)
2904 "command -nargs=* CompilerSet setlocal <args>");
2905 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002906 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002907 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908
2909 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002910 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002911 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2912 vim_free(buf);
2913
2914 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2915
2916 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002917 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002918 if (p != NULL)
2919 set_internal_string_var((char_u *)"b:current_compiler", p);
2920
2921 /* Restore "current_compiler" for ":compiler {name}". */
2922 if (!eap->forceit)
2923 {
2924 if (old_cur_comp != NULL)
2925 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002926 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002927 old_cur_comp);
2928 vim_free(old_cur_comp);
2929 }
2930 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002931 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932 }
2933 }
2934 }
2935}
2936#endif
2937
2938/*
2939 * ":runtime {name}"
2940 */
2941 void
2942ex_runtime(eap)
2943 exarg_T *eap;
2944{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002945 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946}
2947
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002948static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002949
2950 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002951source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002953 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002955 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956}
2957
2958/*
2959 * Source the file "name" from all directories in 'runtimepath'.
2960 * "name" can contain wildcards.
2961 * When "all" is TRUE, source all files, otherwise only the first one.
2962 * return FAIL when no file could be sourced, OK otherwise.
2963 */
2964 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002965source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002966 char_u *name;
2967 int all;
2968{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002969 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002970}
2971
2972/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002973 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2974 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002975 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2976 * used.
2977 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002978 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002979 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2980 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002981 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002982 */
2983 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002984do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002985 char_u *name;
2986 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002987 void (*callback)__ARGS((char_u *fname, void *ck));
2988 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002989{
2990 char_u *rtp;
2991 char_u *np;
2992 char_u *buf;
2993 char_u *rtp_copy;
2994 char_u *tail;
2995 int num_files;
2996 char_u **files;
2997 int i;
2998 int did_one = FALSE;
2999#ifdef AMIGA
3000 struct Process *proc = (struct Process *)FindTask(0L);
3001 APTR save_winptr = proc->pr_WindowPtr;
3002
3003 /* Avoid a requester here for a volume that doesn't exist. */
3004 proc->pr_WindowPtr = (APTR)-1L;
3005#endif
3006
3007 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3008 * value. */
3009 rtp_copy = vim_strsave(p_rtp);
3010 buf = alloc(MAXPATHL);
3011 if (buf != NULL && rtp_copy != NULL)
3012 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003013 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003014 {
3015 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003016 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003017 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003018 verbose_leave();
3019 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003020
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021 /* Loop over all entries in 'runtimepath'. */
3022 rtp = rtp_copy;
3023 while (*rtp != NUL && (all || !did_one))
3024 {
3025 /* Copy the path from 'runtimepath' to buf[]. */
3026 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003027 if (name == NULL)
3028 {
3029 (*callback)(buf, (void *) &cookie);
3030 if (!did_one)
3031 did_one = (cookie == NULL);
3032 }
3033 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034 {
3035 add_pathsep(buf);
3036 tail = buf + STRLEN(buf);
3037
3038 /* Loop over all patterns in "name" */
3039 np = name;
3040 while (*np != NUL && (all || !did_one))
3041 {
3042 /* Append the pattern from "name" to buf[]. */
3043 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3044 "\t ");
3045
3046 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003047 {
3048 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003049 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003050 verbose_leave();
3051 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052
3053 /* Expand wildcards, invoke the callback for each match. */
3054 if (gen_expand_wildcards(1, &buf, &num_files, &files,
3055 EW_FILE) == OK)
3056 {
3057 for (i = 0; i < num_files; ++i)
3058 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003059 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060 did_one = TRUE;
3061 if (!all)
3062 break;
3063 }
3064 FreeWild(num_files, files);
3065 }
3066 }
3067 }
3068 }
3069 }
3070 vim_free(buf);
3071 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003072 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003073 {
3074 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003075 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003076 verbose_leave();
3077 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003078
3079#ifdef AMIGA
3080 proc->pr_WindowPtr = save_winptr;
3081#endif
3082
3083 return did_one ? OK : FAIL;
3084}
3085
3086#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3087/*
3088 * ":options"
3089 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090 void
3091ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003092 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093{
3094 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3095}
3096#endif
3097
3098/*
3099 * ":source {fname}"
3100 */
3101 void
3102ex_source(eap)
3103 exarg_T *eap;
3104{
3105#ifdef FEAT_BROWSE
3106 if (cmdmod.browse)
3107 {
3108 char_u *fname = NULL;
3109
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003110 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003111 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3112 if (fname != NULL)
3113 {
3114 cmd_source(fname, eap);
3115 vim_free(fname);
3116 }
3117 }
3118 else
3119#endif
3120 cmd_source(eap->arg, eap);
3121}
3122
3123 static void
3124cmd_source(fname, eap)
3125 char_u *fname;
3126 exarg_T *eap;
3127{
3128 if (*fname == NUL)
3129 EMSG(_(e_argreq));
3130
Bram Moolenaar071d4272004-06-13 20:20:40 +00003131 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003132 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003133 * Need to execute the commands directly. This is required at least
3134 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 * - ":g" command busy
3136 * - after ":argdo", ":windo" or ":bufdo"
3137 * - another command follows
3138 * - inside a loop
3139 */
3140 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3141#ifdef FEAT_EVAL
3142 || eap->cstack->cs_idx >= 0
3143#endif
3144 );
3145
3146 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003147 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148 EMSG2(_(e_notopen), fname);
3149}
3150
3151/*
3152 * ":source" and associated commands.
3153 */
3154/*
3155 * Structure used to store info for each sourced file.
3156 * It is shared between do_source() and getsourceline().
3157 * This is required, because it needs to be handed to do_cmdline() and
3158 * sourcing can be done recursively.
3159 */
3160struct source_cookie
3161{
3162 FILE *fp; /* opened file for sourcing */
3163 char_u *nextline; /* if not NULL: line that was read ahead */
3164 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003165#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003166 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3167 int error; /* TRUE if LF found after CR-LF */
3168#endif
3169#ifdef FEAT_EVAL
3170 linenr_T breakpoint; /* next line with breakpoint or zero */
3171 char_u *fname; /* name of sourced file */
3172 int dbg_tick; /* debug_tick when breakpoint was set */
3173 int level; /* top nesting level of sourced file */
3174#endif
3175#ifdef FEAT_MBYTE
3176 vimconv_T conv; /* type of conversion */
3177#endif
3178};
3179
3180#ifdef FEAT_EVAL
3181/*
3182 * Return the address holding the next breakpoint line for a source cookie.
3183 */
3184 linenr_T *
3185source_breakpoint(cookie)
3186 void *cookie;
3187{
3188 return &((struct source_cookie *)cookie)->breakpoint;
3189}
3190
3191/*
3192 * Return the address holding the debug tick for a source cookie.
3193 */
3194 int *
3195source_dbg_tick(cookie)
3196 void *cookie;
3197{
3198 return &((struct source_cookie *)cookie)->dbg_tick;
3199}
3200
3201/*
3202 * Return the nesting level for a source cookie.
3203 */
3204 int
3205source_level(cookie)
3206 void *cookie;
3207{
3208 return ((struct source_cookie *)cookie)->level;
3209}
3210#endif
3211
3212static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
3213
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003214#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3215# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216static FILE *fopen_noinh_readbin __ARGS((char *filename));
3217
3218/*
3219 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003220 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221 */
3222 static FILE *
3223fopen_noinh_readbin(filename)
3224 char *filename;
3225{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003226# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003227 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3228# else
3229 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003230# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231
3232 if (fd_tmp == -1)
3233 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003234
3235# ifdef HAVE_FD_CLOEXEC
3236 {
3237 int fdflags = fcntl(fd_tmp, F_GETFD);
3238 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003239 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003240 }
3241# endif
3242
Bram Moolenaar071d4272004-06-13 20:20:40 +00003243 return fdopen(fd_tmp, READBIN);
3244}
3245#endif
3246
3247
3248/*
3249 * do_source: Read the file "fname" and execute its lines as EX commands.
3250 *
3251 * This function may be called recursively!
3252 *
3253 * return FAIL if file could not be opened, OK otherwise
3254 */
3255 int
3256do_source(fname, check_other, is_vimrc)
3257 char_u *fname;
3258 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003259 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260{
3261 struct source_cookie cookie;
3262 char_u *save_sourcing_name;
3263 linenr_T save_sourcing_lnum;
3264 char_u *p;
3265 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003266 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267 int retval = FAIL;
3268#ifdef FEAT_EVAL
3269 scid_T save_current_SID;
3270 static scid_T last_current_SID = 0;
3271 void *save_funccalp;
3272 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003273 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003274# ifdef UNIX
3275 struct stat st;
3276 int stat_ok;
3277# endif
3278#endif
3279#ifdef STARTUPTIME
3280 struct timeval tv_rel;
3281 struct timeval tv_start;
3282#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003283#ifdef FEAT_PROFILE
3284 proftime_T wait_start;
3285#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003286
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 if (p == NULL)
3289 return retval;
3290 fname_exp = fix_fname(p);
3291 vim_free(p);
3292 if (fname_exp == NULL)
3293 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294 if (mch_isdir(fname_exp))
3295 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003296 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003297 goto theend;
3298 }
3299
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003300#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003301 /* Apply SourceCmd autocommands, they should get the file and source it. */
3302 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3303 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3304 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003305 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003306# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003307 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003308# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003309 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003310# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003311 goto theend;
3312 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003313
3314 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003315 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3316#endif
3317
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003318#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3320#else
3321 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3322#endif
3323 if (cookie.fp == NULL && check_other)
3324 {
3325 /*
3326 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3327 * and ".exrc" by "_exrc" or vice versa.
3328 */
3329 p = gettail(fname_exp);
3330 if ((*p == '.' || *p == '_')
3331 && (STRICMP(p + 1, "vimrc") == 0
3332 || STRICMP(p + 1, "gvimrc") == 0
3333 || STRICMP(p + 1, "exrc") == 0))
3334 {
3335 if (*p == '_')
3336 *p = '.';
3337 else
3338 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003339#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3341#else
3342 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3343#endif
3344 }
3345 }
3346
3347 if (cookie.fp == NULL)
3348 {
3349 if (p_verbose > 0)
3350 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003351 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003353 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354 else
3355 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003356 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003357 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358 }
3359 goto theend;
3360 }
3361
3362 /*
3363 * The file exists.
3364 * - In verbose mode, give a message.
3365 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3366 */
3367 if (p_verbose > 1)
3368 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003369 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003371 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372 else
3373 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003374 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003375 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003376 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003377 if (is_vimrc == DOSO_VIMRC)
3378 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3379 else if (is_vimrc == DOSO_GVIMRC)
3380 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381
3382#ifdef USE_CRNL
3383 /* If no automatic file format: Set default to CR-NL. */
3384 if (*p_ffs == NUL)
3385 cookie.fileformat = EOL_DOS;
3386 else
3387 cookie.fileformat = EOL_UNKNOWN;
3388 cookie.error = FALSE;
3389#endif
3390
3391#ifdef USE_CR
3392 /* If no automatic file format: Set default to CR. */
3393 if (*p_ffs == NUL)
3394 cookie.fileformat = EOL_MAC;
3395 else
3396 cookie.fileformat = EOL_UNKNOWN;
3397 cookie.error = FALSE;
3398#endif
3399
3400 cookie.nextline = NULL;
3401 cookie.finished = FALSE;
3402
3403#ifdef FEAT_EVAL
3404 /*
3405 * Check if this script has a breakpoint.
3406 */
3407 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3408 cookie.fname = fname_exp;
3409 cookie.dbg_tick = debug_tick;
3410
3411 cookie.level = ex_nesting_level;
3412#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003413
3414 /*
3415 * Keep the sourcing name/lnum, for recursive calls.
3416 */
3417 save_sourcing_name = sourcing_name;
3418 sourcing_name = fname_exp;
3419 save_sourcing_lnum = sourcing_lnum;
3420 sourcing_lnum = 0;
3421
Bram Moolenaar73881402009-02-04 16:50:47 +00003422#ifdef FEAT_MBYTE
3423 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3424
3425 /* Read the first line so we can check for a UTF-8 BOM. */
3426 firstline = getsourceline(0, (void *)&cookie, 0);
3427 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3428 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3429 {
3430 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3431 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3432 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003433 if (p == NULL)
3434 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003435 if (p != NULL)
3436 {
3437 vim_free(firstline);
3438 firstline = p;
3439 }
3440 }
3441#endif
3442
Bram Moolenaar071d4272004-06-13 20:20:40 +00003443#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003444 if (time_fd != NULL)
3445 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003446#endif
3447
3448#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003449# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003450 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003451 prof_child_enter(&wait_start); /* entering a child now */
3452# endif
3453
3454 /* Don't use local function variables, if called from a function.
3455 * Also starts profiling timer for nested script. */
3456 save_funccalp = save_funccal();
3457
Bram Moolenaar071d4272004-06-13 20:20:40 +00003458 /*
3459 * Check if this script was sourced before to finds its SID.
3460 * If it's new, generate a new SID.
3461 */
3462 save_current_SID = current_SID;
3463# ifdef UNIX
3464 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3465# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003466 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3467 {
3468 si = &SCRIPT_ITEM(current_SID);
3469 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470 && (
3471# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003472 /* Compare dev/ino when possible, it catches symbolic
3473 * links. Also compare file names, the inode may change
3474 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003475 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003476 && (si->sn_dev == st.st_dev
3477 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003479 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003481 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482 if (current_SID == 0)
3483 {
3484 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003485 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3486 == FAIL)
3487 goto almosttheend;
3488 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003489 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003490 ++script_items.ga_len;
3491 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3492# ifdef FEAT_PROFILE
3493 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003494# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003495 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003496 si = &SCRIPT_ITEM(current_SID);
3497 si->sn_name = fname_exp;
3498 fname_exp = NULL;
3499# ifdef UNIX
3500 if (stat_ok)
3501 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003502 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003503 si->sn_dev = st.st_dev;
3504 si->sn_ino = st.st_ino;
3505 }
3506 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003507 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003508# endif
3509
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510 /* Allocate the local script variables to use for this script. */
3511 new_script_vars(current_SID);
3512 }
3513
Bram Moolenaar05159a02005-02-26 23:04:13 +00003514# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003515 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003516 {
3517 int forceit;
3518
3519 /* Check if we do profiling for this script. */
3520 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3521 {
3522 script_do_profile(si);
3523 si->sn_pr_force = forceit;
3524 }
3525 if (si->sn_prof_on)
3526 {
3527 ++si->sn_pr_count;
3528 profile_start(&si->sn_pr_start);
3529 profile_zero(&si->sn_pr_children);
3530 }
3531 }
3532# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003533#endif
3534
3535 /*
3536 * Call do_cmdline, which will call getsourceline() to get the lines.
3537 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003538 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003539 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003541
3542#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003543 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003544 {
3545 /* Get "si" again, "script_items" may have been reallocated. */
3546 si = &SCRIPT_ITEM(current_SID);
3547 if (si->sn_prof_on)
3548 {
3549 profile_end(&si->sn_pr_start);
3550 profile_sub_wait(&wait_start, &si->sn_pr_start);
3551 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003552 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3553 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003554 }
3555 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003556#endif
3557
3558 if (got_int)
3559 EMSG(_(e_interr));
3560 sourcing_name = save_sourcing_name;
3561 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003562 if (p_verbose > 1)
3563 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003564 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003565 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003566 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003567 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003568 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569 }
3570#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003571 if (time_fd != NULL)
3572 {
3573 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3574 time_msg((char *)IObuff, &tv_start);
3575 time_pop(&tv_rel);
3576 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003577#endif
3578
3579#ifdef FEAT_EVAL
3580 /*
3581 * After a "finish" in debug mode, need to break at first command of next
3582 * sourced file.
3583 */
3584 if (save_debug_break_level > ex_nesting_level
3585 && debug_break_level == ex_nesting_level)
3586 ++debug_break_level;
3587#endif
3588
Bram Moolenaar05159a02005-02-26 23:04:13 +00003589#ifdef FEAT_EVAL
3590almosttheend:
3591 current_SID = save_current_SID;
3592 restore_funccal(save_funccalp);
3593# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003594 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003595 prof_child_exit(&wait_start); /* leaving a child now */
3596# endif
3597#endif
3598 fclose(cookie.fp);
3599 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003600 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003601#ifdef FEAT_MBYTE
3602 convert_setup(&cookie.conv, NULL, NULL);
3603#endif
3604
Bram Moolenaar071d4272004-06-13 20:20:40 +00003605theend:
3606 vim_free(fname_exp);
3607 return retval;
3608}
3609
3610#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003611
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612/*
3613 * ":scriptnames"
3614 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003615 void
3616ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003617 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003618{
3619 int i;
3620
Bram Moolenaar05159a02005-02-26 23:04:13 +00003621 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3622 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003623 {
3624 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3625 NameBuff, MAXPATHL, TRUE);
3626 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003627 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628}
3629
3630# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3631/*
3632 * Fix slashes in the list of script names for 'shellslash'.
3633 */
3634 void
3635scriptnames_slash_adjust()
3636{
3637 int i;
3638
Bram Moolenaar05159a02005-02-26 23:04:13 +00003639 for (i = 1; i <= script_items.ga_len; ++i)
3640 if (SCRIPT_ITEM(i).sn_name != NULL)
3641 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003642}
3643# endif
3644
3645/*
3646 * Get a pointer to a script name. Used for ":verbose set".
3647 */
3648 char_u *
3649get_scriptname(id)
3650 scid_T id;
3651{
3652 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003653 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003654 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003655 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003656 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003657 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003658 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003659 return (char_u *)_("environment variable");
3660 if (id == SID_ERROR)
3661 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003662 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003664
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003665# if defined(EXITFREE) || defined(PROTO)
3666 void
3667free_scriptnames()
3668{
3669 int i;
3670
3671 for (i = script_items.ga_len; i > 0; --i)
3672 vim_free(SCRIPT_ITEM(i).sn_name);
3673 ga_clear(&script_items);
3674}
3675# endif
3676
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677#endif
3678
3679#if defined(USE_CR) || defined(PROTO)
3680
3681# if defined(__MSL__) && (__MSL__ >= 22)
3682/*
3683 * Newer version of the Metrowerks library handle DOS and UNIX files
3684 * without help.
3685 * Test with earlier versions, MSL 2.2 is the library supplied with
3686 * Codewarrior Pro 2.
3687 */
3688 char *
3689fgets_cr(s, n, stream)
3690 char *s;
3691 int n;
3692 FILE *stream;
3693{
3694 return fgets(s, n, stream);
3695}
3696# else
3697/*
3698 * Version of fgets() which also works for lines ending in a <CR> only
3699 * (Macintosh format).
3700 * For older versions of the Metrowerks library.
3701 * At least CodeWarrior 9 needed this code.
3702 */
3703 char *
3704fgets_cr(s, n, stream)
3705 char *s;
3706 int n;
3707 FILE *stream;
3708{
3709 int c = 0;
3710 int char_read = 0;
3711
3712 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3713 {
3714 c = fgetc(stream);
3715 s[char_read++] = c;
3716 /* If the file is in DOS format, we need to skip a NL after a CR. I
3717 * thought it was the other way around, but this appears to work... */
3718 if (c == '\n')
3719 {
3720 c = fgetc(stream);
3721 if (c != '\r')
3722 ungetc(c, stream);
3723 }
3724 }
3725
3726 s[char_read] = 0;
3727 if (char_read == 0)
3728 return NULL;
3729
3730 if (feof(stream) && char_read == 1)
3731 return NULL;
3732
3733 return s;
3734}
3735# endif
3736#endif
3737
3738/*
3739 * Get one full line from a sourced file.
3740 * Called by do_cmdline() when it's called from do_source().
3741 *
3742 * Return a pointer to the line in allocated memory.
3743 * Return NULL for end-of-file or some error.
3744 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745 char_u *
3746getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003747 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003748 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003749 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003750{
3751 struct source_cookie *sp = (struct source_cookie *)cookie;
3752 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003753 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754
3755#ifdef FEAT_EVAL
3756 /* If breakpoints have been added/deleted need to check for it. */
3757 if (sp->dbg_tick < debug_tick)
3758 {
3759 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3760 sp->dbg_tick = debug_tick;
3761 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003762# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003763 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003764 script_line_end();
3765# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003766#endif
3767 /*
3768 * Get current line. If there is a read-ahead line, use it, otherwise get
3769 * one now.
3770 */
3771 if (sp->finished)
3772 line = NULL;
3773 else if (sp->nextline == NULL)
3774 line = get_one_sourceline(sp);
3775 else
3776 {
3777 line = sp->nextline;
3778 sp->nextline = NULL;
3779 ++sourcing_lnum;
3780 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003781#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003782 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003783 script_line_start();
3784#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003785
3786 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3787 * contain the 'C' flag. */
3788 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3789 {
3790 /* compensate for the one line read-ahead */
3791 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003792
3793 /* Get the next line and concatenate it when it starts with a
3794 * backslash. We always need to read the next line, keep it in
3795 * sp->nextline. */
3796 sp->nextline = get_one_sourceline(sp);
3797 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003799 garray_T ga;
3800
Bram Moolenaarb549a732012-02-22 18:29:33 +01003801 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003802 ga_concat(&ga, line);
3803 ga_concat(&ga, p + 1);
3804 for (;;)
3805 {
3806 vim_free(sp->nextline);
3807 sp->nextline = get_one_sourceline(sp);
3808 if (sp->nextline == NULL)
3809 break;
3810 p = skipwhite(sp->nextline);
3811 if (*p != '\\')
3812 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003813 /* Adjust the growsize to the current length to speed up
3814 * concatenating many lines. */
3815 if (ga.ga_len > 400)
3816 {
3817 if (ga.ga_len > 8000)
3818 ga.ga_growsize = 8000;
3819 else
3820 ga.ga_growsize = ga.ga_len;
3821 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003822 ga_concat(&ga, p + 1);
3823 }
3824 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003826 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003827 }
3828 }
3829
3830#ifdef FEAT_MBYTE
3831 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3832 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003833 char_u *s;
3834
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 /* Convert the encoding of the script line. */
3836 s = string_convert(&sp->conv, line, NULL);
3837 if (s != NULL)
3838 {
3839 vim_free(line);
3840 line = s;
3841 }
3842 }
3843#endif
3844
3845#ifdef FEAT_EVAL
3846 /* Did we encounter a breakpoint? */
3847 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3848 {
3849 dbg_breakpoint(sp->fname, sourcing_lnum);
3850 /* Find next breakpoint. */
3851 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3852 sp->dbg_tick = debug_tick;
3853 }
3854#endif
3855
3856 return line;
3857}
3858
3859 static char_u *
3860get_one_sourceline(sp)
3861 struct source_cookie *sp;
3862{
3863 garray_T ga;
3864 int len;
3865 int c;
3866 char_u *buf;
3867#ifdef USE_CRNL
3868 int has_cr; /* CR-LF found */
3869#endif
3870#ifdef USE_CR
3871 char_u *scan;
3872#endif
3873 int have_read = FALSE;
3874
3875 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003876 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877
3878 /*
3879 * Loop until there is a finished line (or end-of-file).
3880 */
3881 sourcing_lnum++;
3882 for (;;)
3883 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003884 /* make room to read at least 120 (more) characters */
3885 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003886 break;
3887 buf = (char_u *)ga.ga_data;
3888
3889#ifdef USE_CR
3890 if (sp->fileformat == EOL_MAC)
3891 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003892 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3893 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003894 break;
3895 }
3896 else
3897#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003898 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3899 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003901 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003902#ifdef USE_CRNL
3903 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3904 * CTRL-Z by its own, or after a NL. */
3905 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3906 && sp->fileformat == EOL_DOS
3907 && buf[len - 1] == Ctrl_Z)
3908 {
3909 buf[len - 1] = NUL;
3910 break;
3911 }
3912#endif
3913
3914#ifdef USE_CR
3915 /* If the read doesn't stop on a new line, and there's
3916 * some CR then we assume a Mac format */
3917 if (sp->fileformat == EOL_UNKNOWN)
3918 {
3919 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3920 sp->fileformat = EOL_MAC;
3921 else
3922 sp->fileformat = EOL_UNIX;
3923 }
3924
3925 if (sp->fileformat == EOL_MAC)
3926 {
3927 scan = vim_strchr(buf, '\r');
3928
3929 if (scan != NULL)
3930 {
3931 *scan = '\n';
3932 if (*(scan + 1) != 0)
3933 {
3934 *(scan + 1) = 0;
3935 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3936 }
3937 }
3938 len = STRLEN(buf);
3939 }
3940#endif
3941
3942 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003943 ga.ga_len = len;
3944
3945 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003946 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003947 continue;
3948
3949 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3950 {
3951#ifdef USE_CRNL
3952 has_cr = (len >= 2 && buf[len - 2] == '\r');
3953 if (sp->fileformat == EOL_UNKNOWN)
3954 {
3955 if (has_cr)
3956 sp->fileformat = EOL_DOS;
3957 else
3958 sp->fileformat = EOL_UNIX;
3959 }
3960
3961 if (sp->fileformat == EOL_DOS)
3962 {
3963 if (has_cr) /* replace trailing CR */
3964 {
3965 buf[len - 2] = '\n';
3966 --len;
3967 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003968 }
3969 else /* lines like ":map xx yy^M" will have failed */
3970 {
3971 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003972 {
3973 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003974 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003975 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003976 sp->error = TRUE;
3977 sp->fileformat = EOL_UNIX;
3978 }
3979 }
3980#endif
3981 /* The '\n' is escaped if there is an odd number of ^V's just
3982 * before it, first set "c" just before the 'V's and then check
3983 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3984 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3985 ;
3986 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3987 {
3988 sourcing_lnum++;
3989 continue;
3990 }
3991
3992 buf[len - 1] = NUL; /* remove the NL */
3993 }
3994
3995 /*
3996 * Check for ^C here now and then, so recursive :so can be broken.
3997 */
3998 line_breakcheck();
3999 break;
4000 }
4001
4002 if (have_read)
4003 return (char_u *)ga.ga_data;
4004
4005 vim_free(ga.ga_data);
4006 return NULL;
4007}
4008
Bram Moolenaar05159a02005-02-26 23:04:13 +00004009#if defined(FEAT_PROFILE) || defined(PROTO)
4010/*
4011 * Called when starting to read a script line.
4012 * "sourcing_lnum" must be correct!
4013 * When skipping lines it may not actually be executed, but we won't find out
4014 * until later and we need to store the time now.
4015 */
4016 void
4017script_line_start()
4018{
4019 scriptitem_T *si;
4020 sn_prl_T *pp;
4021
4022 if (current_SID <= 0 || current_SID > script_items.ga_len)
4023 return;
4024 si = &SCRIPT_ITEM(current_SID);
4025 if (si->sn_prof_on && sourcing_lnum >= 1)
4026 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004027 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004028 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004029 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004030 si->sn_prl_idx = sourcing_lnum - 1;
4031 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4032 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4033 {
4034 /* Zero counters for a line that was not used before. */
4035 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4036 pp->snp_count = 0;
4037 profile_zero(&pp->sn_prl_total);
4038 profile_zero(&pp->sn_prl_self);
4039 ++si->sn_prl_ga.ga_len;
4040 }
4041 si->sn_prl_execed = FALSE;
4042 profile_start(&si->sn_prl_start);
4043 profile_zero(&si->sn_prl_children);
4044 profile_get_wait(&si->sn_prl_wait);
4045 }
4046}
4047
4048/*
4049 * Called when actually executing a function line.
4050 */
4051 void
4052script_line_exec()
4053{
4054 scriptitem_T *si;
4055
4056 if (current_SID <= 0 || current_SID > script_items.ga_len)
4057 return;
4058 si = &SCRIPT_ITEM(current_SID);
4059 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4060 si->sn_prl_execed = TRUE;
4061}
4062
4063/*
4064 * Called when done with a function line.
4065 */
4066 void
4067script_line_end()
4068{
4069 scriptitem_T *si;
4070 sn_prl_T *pp;
4071
4072 if (current_SID <= 0 || current_SID > script_items.ga_len)
4073 return;
4074 si = &SCRIPT_ITEM(current_SID);
4075 if (si->sn_prof_on && si->sn_prl_idx >= 0
4076 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4077 {
4078 if (si->sn_prl_execed)
4079 {
4080 pp = &PRL_ITEM(si, si->sn_prl_idx);
4081 ++pp->snp_count;
4082 profile_end(&si->sn_prl_start);
4083 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004084 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004085 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4086 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004087 }
4088 si->sn_prl_idx = -1;
4089 }
4090}
4091#endif
4092
Bram Moolenaar071d4272004-06-13 20:20:40 +00004093/*
4094 * ":scriptencoding": Set encoding conversion for a sourced script.
4095 * Without the multi-byte feature it's simply ignored.
4096 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097 void
4098ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004099 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004100{
4101#ifdef FEAT_MBYTE
4102 struct source_cookie *sp;
4103 char_u *name;
4104
4105 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4106 {
4107 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4108 return;
4109 }
4110
4111 if (*eap->arg != NUL)
4112 {
4113 name = enc_canonize(eap->arg);
4114 if (name == NULL) /* out of memory */
4115 return;
4116 }
4117 else
4118 name = eap->arg;
4119
4120 /* Setup for conversion from the specified encoding to 'encoding'. */
4121 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4122 convert_setup(&sp->conv, name, p_enc);
4123
4124 if (name != eap->arg)
4125 vim_free(name);
4126#endif
4127}
4128
4129#if defined(FEAT_EVAL) || defined(PROTO)
4130/*
4131 * ":finish": Mark a sourced file as finished.
4132 */
4133 void
4134ex_finish(eap)
4135 exarg_T *eap;
4136{
4137 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4138 do_finish(eap, FALSE);
4139 else
4140 EMSG(_("E168: :finish used outside of a sourced file"));
4141}
4142
4143/*
4144 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4145 * Also called for a pending finish at the ":endtry" or after returning from
4146 * an extra do_cmdline(). "reanimate" is used in the latter case.
4147 */
4148 void
4149do_finish(eap, reanimate)
4150 exarg_T *eap;
4151 int reanimate;
4152{
4153 int idx;
4154
4155 if (reanimate)
4156 ((struct source_cookie *)getline_cookie(eap->getline,
4157 eap->cookie))->finished = FALSE;
4158
4159 /*
4160 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4161 * not in its finally clause (which then is to be executed next) is found.
4162 * In this case, make the ":finish" pending for execution at the ":endtry".
4163 * Otherwise, finish normally.
4164 */
4165 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4166 if (idx >= 0)
4167 {
4168 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4169 report_make_pending(CSTP_FINISH, NULL);
4170 }
4171 else
4172 ((struct source_cookie *)getline_cookie(eap->getline,
4173 eap->cookie))->finished = TRUE;
4174}
4175
4176
4177/*
4178 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4179 * message for missing ":endif".
4180 * Return FALSE when not sourcing a file.
4181 */
4182 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00004183source_finished(fgetline, cookie)
4184 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004185 void *cookie;
4186{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004187 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004188 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004189 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004190}
4191#endif
4192
4193#if defined(FEAT_LISTCMDS) || defined(PROTO)
4194/*
4195 * ":checktime [buffer]"
4196 */
4197 void
4198ex_checktime(eap)
4199 exarg_T *eap;
4200{
4201 buf_T *buf;
4202 int save_no_check_timestamps = no_check_timestamps;
4203
4204 no_check_timestamps = 0;
4205 if (eap->addr_count == 0) /* default is all buffers */
4206 check_timestamps(FALSE);
4207 else
4208 {
4209 buf = buflist_findnr((int)eap->line2);
4210 if (buf != NULL) /* cannot happen? */
4211 (void)buf_check_timestamp(buf, FALSE);
4212 }
4213 no_check_timestamps = save_no_check_timestamps;
4214}
4215#endif
4216
Bram Moolenaar071d4272004-06-13 20:20:40 +00004217#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4218 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004219# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220static char *get_locale_val __ARGS((int what));
4221
4222 static char *
4223get_locale_val(what)
4224 int what;
4225{
4226 char *loc;
4227
4228 /* Obtain the locale value from the libraries. For DJGPP this is
4229 * redefined and it doesn't use the arguments. */
4230 loc = setlocale(what, NULL);
4231
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004232# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233 if (loc != NULL)
4234 {
4235 char_u *p;
4236
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004237 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4238 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004239 p = vim_strchr(loc, '=');
4240 if (p != NULL)
4241 {
4242 loc = ++p;
4243 while (*p != NUL) /* remove trailing newline */
4244 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004245 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004246 {
4247 *p = NUL;
4248 break;
4249 }
4250 ++p;
4251 }
4252 }
4253 }
4254# endif
4255
4256 return loc;
4257}
4258#endif
4259
4260
4261#ifdef WIN32
4262/*
4263 * On MS-Windows locale names are strings like "German_Germany.1252", but
4264 * gettext expects "de". Try to translate one into another here for a few
4265 * supported languages.
4266 */
4267 static char_u *
4268gettext_lang(char_u *name)
4269{
4270 int i;
4271 static char *(mtable[]) = {
4272 "afrikaans", "af",
4273 "czech", "cs",
4274 "dutch", "nl",
4275 "german", "de",
4276 "english_united kingdom", "en_GB",
4277 "spanish", "es",
4278 "french", "fr",
4279 "italian", "it",
4280 "japanese", "ja",
4281 "korean", "ko",
4282 "norwegian", "no",
4283 "polish", "pl",
4284 "russian", "ru",
4285 "slovak", "sk",
4286 "swedish", "sv",
4287 "ukrainian", "uk",
4288 "chinese_china", "zh_CN",
4289 "chinese_taiwan", "zh_TW",
4290 NULL};
4291
4292 for (i = 0; mtable[i] != NULL; i += 2)
4293 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4294 return mtable[i + 1];
4295 return name;
4296}
4297#endif
4298
4299#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4300/*
4301 * Obtain the current messages language. Used to set the default for
4302 * 'helplang'. May return NULL or an empty string.
4303 */
4304 char_u *
4305get_mess_lang()
4306{
4307 char_u *p;
4308
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004309# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004310# if defined(LC_MESSAGES)
4311 p = (char_u *)get_locale_val(LC_MESSAGES);
4312# else
4313 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004314 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4315 * and LC_MONETARY may be set differently for a Japanese working in the
4316 * US. */
4317 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004318# endif
4319# else
4320 p = mch_getenv((char_u *)"LC_ALL");
4321 if (p == NULL || *p == NUL)
4322 {
4323 p = mch_getenv((char_u *)"LC_MESSAGES");
4324 if (p == NULL || *p == NUL)
4325 p = mch_getenv((char_u *)"LANG");
4326 }
4327# endif
4328# ifdef WIN32
4329 p = gettext_lang(p);
4330# endif
4331 return p;
4332}
4333#endif
4334
Bram Moolenaardef9e822004-12-31 20:58:58 +00004335/* Complicated #if; matches with where get_mess_env() is used below. */
4336#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4337 && defined(LC_MESSAGES))) \
4338 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4339 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4340 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341static char_u *get_mess_env __ARGS((void));
4342
4343/*
4344 * Get the language used for messages from the environment.
4345 */
4346 static char_u *
4347get_mess_env()
4348{
4349 char_u *p;
4350
4351 p = mch_getenv((char_u *)"LC_ALL");
4352 if (p == NULL || *p == NUL)
4353 {
4354 p = mch_getenv((char_u *)"LC_MESSAGES");
4355 if (p == NULL || *p == NUL)
4356 {
4357 p = mch_getenv((char_u *)"LANG");
4358 if (p != NULL && VIM_ISDIGIT(*p))
4359 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004360# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361 if (p == NULL || *p == NUL)
4362 p = (char_u *)get_locale_val(LC_CTYPE);
4363# endif
4364 }
4365 }
4366 return p;
4367}
4368#endif
4369
4370#if defined(FEAT_EVAL) || defined(PROTO)
4371
4372/*
4373 * Set the "v:lang" variable according to the current locale setting.
4374 * Also do "v:lc_time"and "v:ctype".
4375 */
4376 void
4377set_lang_var()
4378{
4379 char_u *loc;
4380
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004381# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382 loc = (char_u *)get_locale_val(LC_CTYPE);
4383# else
4384 /* setlocale() not supported: use the default value */
4385 loc = (char_u *)"C";
4386# endif
4387 set_vim_var_string(VV_CTYPE, loc, -1);
4388
4389 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4390 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004391# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004392 loc = (char_u *)get_locale_val(LC_MESSAGES);
4393# else
4394 loc = get_mess_env();
4395# endif
4396 set_vim_var_string(VV_LANG, loc, -1);
4397
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004398# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004399 loc = (char_u *)get_locale_val(LC_TIME);
4400# endif
4401 set_vim_var_string(VV_LC_TIME, loc, -1);
4402}
4403#endif
4404
4405#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4406 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4407/*
4408 * ":language": Set the language (locale).
4409 */
4410 void
4411ex_language(eap)
4412 exarg_T *eap;
4413{
4414 char *loc;
4415 char_u *p;
4416 char_u *name;
4417 int what = LC_ALL;
4418 char *whatstr = "";
4419#ifdef LC_MESSAGES
4420# define VIM_LC_MESSAGES LC_MESSAGES
4421#else
4422# define VIM_LC_MESSAGES 6789
4423#endif
4424
4425 name = eap->arg;
4426
4427 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4428 * Allow abbreviation, but require at least 3 characters to avoid
4429 * confusion with a two letter language name "me" or "ct". */
4430 p = skiptowhite(eap->arg);
4431 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4432 {
4433 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4434 {
4435 what = VIM_LC_MESSAGES;
4436 name = skipwhite(p);
4437 whatstr = "messages ";
4438 }
4439 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4440 {
4441 what = LC_CTYPE;
4442 name = skipwhite(p);
4443 whatstr = "ctype ";
4444 }
4445 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4446 {
4447 what = LC_TIME;
4448 name = skipwhite(p);
4449 whatstr = "time ";
4450 }
4451 }
4452
4453 if (*name == NUL)
4454 {
4455#ifndef LC_MESSAGES
4456 if (what == VIM_LC_MESSAGES)
4457 p = get_mess_env();
4458 else
4459#endif
4460 p = (char_u *)setlocale(what, NULL);
4461 if (p == NULL || *p == NUL)
4462 p = (char_u *)"Unknown";
4463 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4464 }
4465 else
4466 {
4467#ifndef LC_MESSAGES
4468 if (what == VIM_LC_MESSAGES)
4469 loc = "";
4470 else
4471#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004472 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004473 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004474#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4475 /* Make sure strtod() uses a decimal point, not a comma. */
4476 setlocale(LC_NUMERIC, "C");
4477#endif
4478 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479 if (loc == NULL)
4480 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4481 else
4482 {
4483#ifdef HAVE_NL_MSG_CAT_CNTR
4484 /* Need to do this for GNU gettext, otherwise cached translations
4485 * will be used again. */
4486 extern int _nl_msg_cat_cntr;
4487
4488 ++_nl_msg_cat_cntr;
4489#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004490 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4492
4493 if (what != LC_TIME)
4494 {
4495 /* Tell gettext() what to translate to. It apparently doesn't
4496 * use the currently effective locale. Also do this when
4497 * FEAT_GETTEXT isn't defined, so that shell commands use this
4498 * value. */
4499 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004500 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004502
4503 /* Clear $LANGUAGE because GNU gettext uses it. */
4504 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004505# ifdef WIN32
4506 /* Apparently MS-Windows printf() may cause a crash when
4507 * we give it 8-bit text while it's expecting text in the
4508 * current locale. This call avoids that. */
4509 setlocale(LC_CTYPE, "C");
4510# endif
4511 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004512 if (what != LC_CTYPE)
4513 {
4514 char_u *mname;
4515#ifdef WIN32
4516 mname = gettext_lang(name);
4517#else
4518 mname = name;
4519#endif
4520 vim_setenv((char_u *)"LC_MESSAGES", mname);
4521#ifdef FEAT_MULTI_LANG
4522 set_helplang_default(mname);
4523#endif
4524 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525 }
4526
4527# ifdef FEAT_EVAL
4528 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4529 set_lang_var();
4530# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004531# ifdef FEAT_TITLE
4532 maketitle();
4533# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 }
4535 }
4536}
4537
4538# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004539
4540static char_u **locales = NULL; /* Array of all available locales */
4541static int did_init_locales = FALSE;
4542
4543static void init_locales __ARGS((void));
4544static char_u **find_locales __ARGS((void));
4545
4546/*
4547 * Lazy initialization of all available locales.
4548 */
4549 static void
4550init_locales()
4551{
4552 if (!did_init_locales)
4553 {
4554 did_init_locales = TRUE;
4555 locales = find_locales();
4556 }
4557}
4558
4559/* Return an array of strings for all available locales + NULL for the
4560 * last element. Return NULL in case of error. */
4561 static char_u **
4562find_locales()
4563{
4564 garray_T locales_ga;
4565 char_u *loc;
4566
4567 /* Find all available locales by running command "locale -a". If this
4568 * doesn't work we won't have completion. */
4569 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004570 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004571 if (locale_a == NULL)
4572 return NULL;
4573 ga_init2(&locales_ga, sizeof(char_u *), 20);
4574
4575 /* Transform locale_a string where each locale is separated by "\n"
4576 * into an array of locale strings. */
4577 loc = (char_u *)strtok((char *)locale_a, "\n");
4578
4579 while (loc != NULL)
4580 {
4581 if (ga_grow(&locales_ga, 1) == FAIL)
4582 break;
4583 loc = vim_strsave(loc);
4584 if (loc == NULL)
4585 break;
4586
4587 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4588 loc = (char_u *)strtok(NULL, "\n");
4589 }
4590 vim_free(locale_a);
4591 if (ga_grow(&locales_ga, 1) == FAIL)
4592 {
4593 ga_clear(&locales_ga);
4594 return NULL;
4595 }
4596 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4597 return (char_u **)locales_ga.ga_data;
4598}
4599
4600# if defined(EXITFREE) || defined(PROTO)
4601 void
4602free_locales()
4603{
4604 int i;
4605 if (locales != NULL)
4606 {
4607 for (i = 0; locales[i] != NULL; i++)
4608 vim_free(locales[i]);
4609 vim_free(locales);
4610 locales = NULL;
4611 }
4612}
4613# endif
4614
Bram Moolenaar071d4272004-06-13 20:20:40 +00004615/*
4616 * Function given to ExpandGeneric() to obtain the possible arguments of the
4617 * ":language" command.
4618 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619 char_u *
4620get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004621 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622 int idx;
4623{
4624 if (idx == 0)
4625 return (char_u *)"messages";
4626 if (idx == 1)
4627 return (char_u *)"ctype";
4628 if (idx == 2)
4629 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004630
4631 init_locales();
4632 if (locales == NULL)
4633 return NULL;
4634 return locales[idx - 3];
4635}
4636
4637/*
4638 * Function given to ExpandGeneric() to obtain the available locales.
4639 */
4640 char_u *
4641get_locales(xp, idx)
4642 expand_T *xp UNUSED;
4643 int idx;
4644{
4645 init_locales();
4646 if (locales == NULL)
4647 return NULL;
4648 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649}
4650# endif
4651
4652#endif