blob: 676cf117b42af4404dfafffde23b879112c31d62 [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);
2150 if (i == FAIL)
2151 return FAIL;
2152 if (exp_count == 0)
2153 {
2154 EMSG(_(e_nomatch));
2155 return FAIL;
2156 }
2157
2158#ifdef FEAT_LISTCMDS
2159 if (what == AL_ADD)
2160 {
2161 (void)alist_add_list(exp_count, exp_files, after);
2162 vim_free(exp_files);
2163 }
2164 else /* what == AL_SET */
2165#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002166 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002167 }
2168
2169 alist_check_arg_idx();
2170
2171 return OK;
2172}
2173
2174/*
2175 * Check the validity of the arg_idx for each other window.
2176 */
2177 static void
2178alist_check_arg_idx()
2179{
2180#ifdef FEAT_WINDOWS
2181 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002182 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183
Bram Moolenaarf740b292006-02-16 22:11:02 +00002184 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185 if (win->w_alist == curwin->w_alist)
2186 check_arg_idx(win);
2187#else
2188 check_arg_idx(curwin);
2189#endif
2190}
2191
2192/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002193 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002194 * index.
2195 */
2196 static int
2197editing_arg_idx(win)
2198 win_T *win;
2199{
2200 return !(win->w_arg_idx >= WARGCOUNT(win)
2201 || (win->w_buffer->b_fnum
2202 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2203 && (win->w_buffer->b_ffname == NULL
2204 || !(fullpathcmp(
2205 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2206 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2207}
2208
2209/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002210 * Check if window "win" is editing the w_arg_idx file in its argument list.
2211 */
2212 void
2213check_arg_idx(win)
2214 win_T *win;
2215{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002216 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217 {
2218 /* We are not editing the current entry in the argument list.
2219 * Set "arg_had_last" if we are editing the last one. */
2220 win->w_arg_idx_invalid = TRUE;
2221 if (win->w_arg_idx != WARGCOUNT(win) - 1
2222 && arg_had_last == FALSE
2223#ifdef FEAT_WINDOWS
2224 && ALIST(win) == &global_alist
2225#endif
2226 && GARGCOUNT > 0
2227 && win->w_arg_idx < GARGCOUNT
2228 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2229 || (win->w_buffer->b_ffname != NULL
2230 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2231 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2232 arg_had_last = TRUE;
2233 }
2234 else
2235 {
2236 /* We are editing the current entry in the argument list.
2237 * Set "arg_had_last" if it's also the last one */
2238 win->w_arg_idx_invalid = FALSE;
2239 if (win->w_arg_idx == WARGCOUNT(win) - 1
2240#ifdef FEAT_WINDOWS
2241 && win->w_alist == &global_alist
2242#endif
2243 )
2244 arg_had_last = TRUE;
2245 }
2246}
2247
2248/*
2249 * ":args", ":argslocal" and ":argsglobal".
2250 */
2251 void
2252ex_args(eap)
2253 exarg_T *eap;
2254{
2255 int i;
2256
2257 if (eap->cmdidx != CMD_args)
2258 {
2259#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2260 alist_unlink(ALIST(curwin));
2261 if (eap->cmdidx == CMD_argglobal)
2262 ALIST(curwin) = &global_alist;
2263 else /* eap->cmdidx == CMD_arglocal */
2264 alist_new();
2265#else
2266 ex_ni(eap);
2267 return;
2268#endif
2269 }
2270
2271 if (!ends_excmd(*eap->arg))
2272 {
2273 /*
2274 * ":args file ..": define new argument list, handle like ":next"
2275 * Also for ":argslocal file .." and ":argsglobal file ..".
2276 */
2277 ex_next(eap);
2278 }
2279 else
2280#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2281 if (eap->cmdidx == CMD_args)
2282#endif
2283 {
2284 /*
2285 * ":args": list arguments.
2286 */
2287 if (ARGCOUNT > 0)
2288 {
2289 /* Overwrite the command, for a short list there is no scrolling
2290 * required and no wait_return(). */
2291 gotocmdline(TRUE);
2292 for (i = 0; i < ARGCOUNT; ++i)
2293 {
2294 if (i == curwin->w_arg_idx)
2295 msg_putchar('[');
2296 msg_outtrans(alist_name(&ARGLIST[i]));
2297 if (i == curwin->w_arg_idx)
2298 msg_putchar(']');
2299 msg_putchar(' ');
2300 }
2301 }
2302 }
2303#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2304 else if (eap->cmdidx == CMD_arglocal)
2305 {
2306 garray_T *gap = &curwin->w_alist->al_ga;
2307
2308 /*
2309 * ":argslocal": make a local copy of the global argument list.
2310 */
2311 if (ga_grow(gap, GARGCOUNT) == OK)
2312 for (i = 0; i < GARGCOUNT; ++i)
2313 if (GARGLIST[i].ae_fname != NULL)
2314 {
2315 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2316 vim_strsave(GARGLIST[i].ae_fname);
2317 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2318 GARGLIST[i].ae_fnum;
2319 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 }
2321 }
2322#endif
2323}
2324
2325/*
2326 * ":previous", ":sprevious", ":Next" and ":sNext".
2327 */
2328 void
2329ex_previous(eap)
2330 exarg_T *eap;
2331{
2332 /* If past the last one already, go to the last one. */
2333 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2334 do_argfile(eap, ARGCOUNT - 1);
2335 else
2336 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2337}
2338
2339/*
2340 * ":rewind", ":first", ":sfirst" and ":srewind".
2341 */
2342 void
2343ex_rewind(eap)
2344 exarg_T *eap;
2345{
2346 do_argfile(eap, 0);
2347}
2348
2349/*
2350 * ":last" and ":slast".
2351 */
2352 void
2353ex_last(eap)
2354 exarg_T *eap;
2355{
2356 do_argfile(eap, ARGCOUNT - 1);
2357}
2358
2359/*
2360 * ":argument" and ":sargument".
2361 */
2362 void
2363ex_argument(eap)
2364 exarg_T *eap;
2365{
2366 int i;
2367
2368 if (eap->addr_count > 0)
2369 i = eap->line2 - 1;
2370 else
2371 i = curwin->w_arg_idx;
2372 do_argfile(eap, i);
2373}
2374
2375/*
2376 * Edit file "argn" of the argument lists.
2377 */
2378 void
2379do_argfile(eap, argn)
2380 exarg_T *eap;
2381 int argn;
2382{
2383 int other;
2384 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002385 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002386
2387 if (argn < 0 || argn >= ARGCOUNT)
2388 {
2389 if (ARGCOUNT <= 1)
2390 EMSG(_("E163: There is only one file to edit"));
2391 else if (argn < 0)
2392 EMSG(_("E164: Cannot go before first file"));
2393 else
2394 EMSG(_("E165: Cannot go beyond last file"));
2395 }
2396 else
2397 {
2398 setpcmark();
2399#ifdef FEAT_GUI
2400 need_mouse_correct = TRUE;
2401#endif
2402
2403#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002404 /* split window or create new tab page first */
2405 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406 {
2407 if (win_split(0, 0) == FAIL)
2408 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002409 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002410 }
2411 else
2412#endif
2413 {
2414 /*
2415 * if 'hidden' set, only check for changed file when re-editing
2416 * the same buffer
2417 */
2418 other = TRUE;
2419 if (P_HID(curbuf))
2420 {
2421 p = fix_fname(alist_name(&ARGLIST[argn]));
2422 other = otherfile(p);
2423 vim_free(p);
2424 }
2425 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002426 && check_changed(curbuf, CCGD_AW
2427 | (other ? 0 : CCGD_MULTWIN)
2428 | (eap->forceit ? CCGD_FORCEIT : 0)
2429 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430 return;
2431 }
2432
2433 curwin->w_arg_idx = argn;
2434 if (argn == ARGCOUNT - 1
2435#ifdef FEAT_WINDOWS
2436 && curwin->w_alist == &global_alist
2437#endif
2438 )
2439 arg_had_last = TRUE;
2440
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002441 /* Edit the file; always use the last known line number.
2442 * When it fails (e.g. Abort for already edited file) restore the
2443 * argument index. */
2444 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002445 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002446 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2447 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002448 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002449 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002450 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451 setmark('\'');
2452 }
2453}
2454
2455/*
2456 * ":next", and commands that behave like it.
2457 */
2458 void
2459ex_next(eap)
2460 exarg_T *eap;
2461{
2462 int i;
2463
2464 /*
2465 * check for changed buffer now, if this fails the argument list is not
2466 * redefined.
2467 */
2468 if ( P_HID(curbuf)
2469 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002470 || !check_changed(curbuf, CCGD_AW
2471 | (eap->forceit ? CCGD_FORCEIT : 0)
2472 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002473 {
2474 if (*eap->arg != NUL) /* redefine file list */
2475 {
2476 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2477 return;
2478 i = 0;
2479 }
2480 else
2481 i = curwin->w_arg_idx + (int)eap->line2;
2482 do_argfile(eap, i);
2483 }
2484}
2485
2486#ifdef FEAT_LISTCMDS
2487/*
2488 * ":argedit"
2489 */
2490 void
2491ex_argedit(eap)
2492 exarg_T *eap;
2493{
2494 int fnum;
2495 int i;
2496 char_u *s;
2497
2498 /* Add the argument to the buffer list and get the buffer number. */
2499 fnum = buflist_add(eap->arg, BLN_LISTED);
2500
2501 /* Check if this argument is already in the argument list. */
2502 for (i = 0; i < ARGCOUNT; ++i)
2503 if (ARGLIST[i].ae_fnum == fnum)
2504 break;
2505 if (i == ARGCOUNT)
2506 {
2507 /* Can't find it, add it to the argument list. */
2508 s = vim_strsave(eap->arg);
2509 if (s == NULL)
2510 return;
2511 i = alist_add_list(1, &s,
2512 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2513 if (i < 0)
2514 return;
2515 curwin->w_arg_idx = i;
2516 }
2517
2518 alist_check_arg_idx();
2519
2520 /* Edit the argument. */
2521 do_argfile(eap, i);
2522}
2523
2524/*
2525 * ":argadd"
2526 */
2527 void
2528ex_argadd(eap)
2529 exarg_T *eap;
2530{
2531 do_arglist(eap->arg, AL_ADD,
2532 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2533#ifdef FEAT_TITLE
2534 maketitle();
2535#endif
2536}
2537
2538/*
2539 * ":argdelete"
2540 */
2541 void
2542ex_argdelete(eap)
2543 exarg_T *eap;
2544{
2545 int i;
2546 int n;
2547
2548 if (eap->addr_count > 0)
2549 {
2550 /* ":1,4argdel": Delete all arguments in the range. */
2551 if (eap->line2 > ARGCOUNT)
2552 eap->line2 = ARGCOUNT;
2553 n = eap->line2 - eap->line1 + 1;
2554 if (*eap->arg != NUL || n <= 0)
2555 EMSG(_(e_invarg));
2556 else
2557 {
2558 for (i = eap->line1; i <= eap->line2; ++i)
2559 vim_free(ARGLIST[i - 1].ae_fname);
2560 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2561 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2562 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002563 if (curwin->w_arg_idx >= eap->line2)
2564 curwin->w_arg_idx -= n;
2565 else if (curwin->w_arg_idx > eap->line1)
2566 curwin->w_arg_idx = eap->line1;
2567 }
2568 }
2569 else if (*eap->arg == NUL)
2570 EMSG(_(e_argreq));
2571 else
2572 do_arglist(eap->arg, AL_DEL, 0);
2573#ifdef FEAT_TITLE
2574 maketitle();
2575#endif
2576}
2577
2578/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002579 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580 */
2581 void
2582ex_listdo(eap)
2583 exarg_T *eap;
2584{
2585 int i;
2586#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002587 win_T *wp;
2588 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002590 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002591 int next_fnum = 0;
2592#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2593 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002595 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002596#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002597 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002598 int qf_idx;
2599#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002600
2601#ifndef FEAT_WINDOWS
2602 if (eap->cmdidx == CMD_windo)
2603 {
2604 ex_ni(eap);
2605 return;
2606 }
2607#endif
2608
2609#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002610 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002611 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2612 * great speed improvement. */
2613 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002615#ifdef FEAT_CLIPBOARD
2616 start_global_changes();
2617#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618
2619 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002620 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002621 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002622 || !check_changed(curbuf, CCGD_AW
2623 | (eap->forceit ? CCGD_FORCEIT : 0)
2624 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002625 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002627 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002629 wp = firstwin;
2630 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002631#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002632 switch (eap->cmdidx)
2633 {
2634#ifdef FEAT_WINDOWS
2635 case CMD_windo:
2636 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2637 i++;
2638 break;
2639 case CMD_tabdo:
2640 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2641 i++;
2642 break;
2643#endif
2644 case CMD_argdo:
2645 i = eap->line1 - 1;
2646 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002647 default:
2648 break;
2649 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650 /* set pcmark now */
2651 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002652 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002653 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002654 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002655 || !buf->b_p_bl); buf = buf->b_next)
2656 if (buf->b_fnum > eap->line2)
2657 {
2658 buf = NULL;
2659 break;
2660 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002661 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002662 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002663 }
2664#ifdef FEAT_QUICKFIX
2665 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2666 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2667 {
2668 qf_size = qf_get_size(eap);
2669 if (qf_size <= 0 || eap->line1 > qf_size)
2670 buf = NULL;
2671 else
2672 {
2673 ex_cc(eap);
2674
2675 buf = curbuf;
2676 i = eap->line1 - 1;
2677 if (eap->addr_count <= 0)
2678 /* default is all the quickfix/location list entries */
2679 eap->line2 = qf_size;
2680 }
2681 }
2682#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002683 else
2684 setpcmark();
2685 listcmd_busy = TRUE; /* avoids setting pcmark below */
2686
Bram Moolenaare25bb902015-02-27 20:33:37 +01002687 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688 {
2689 if (eap->cmdidx == CMD_argdo)
2690 {
2691 /* go to argument "i" */
2692 if (i == ARGCOUNT)
2693 break;
2694 /* Don't call do_argfile() when already there, it will try
2695 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002696 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002697 {
2698 /* Clear 'shm' to avoid that the file message overwrites
2699 * any output from the command. */
2700 p_shm_save = vim_strsave(p_shm);
2701 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002703 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2704 vim_free(p_shm_save);
2705 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002706 if (curwin->w_arg_idx != i)
2707 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 }
2709#ifdef FEAT_WINDOWS
2710 else if (eap->cmdidx == CMD_windo)
2711 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002712 /* go to window "wp" */
2713 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002715 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002716 if (curwin != wp)
2717 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002718 wp = curwin->w_next;
2719 }
2720 else if (eap->cmdidx == CMD_tabdo)
2721 {
2722 /* go to window "tp" */
2723 if (!valid_tabpage(tp))
2724 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002725 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002726 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727 }
2728#endif
2729 else if (eap->cmdidx == CMD_bufdo)
2730 {
2731 /* Remember the number of the next listed buffer, in case
2732 * ":bwipe" is used or autocommands do something strange. */
2733 next_fnum = -1;
2734 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2735 if (buf->b_p_bl)
2736 {
2737 next_fnum = buf->b_fnum;
2738 break;
2739 }
2740 }
2741
Bram Moolenaara162bc52015-01-07 16:54:21 +01002742 ++i;
2743
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744 /* execute the command */
2745 do_cmdline(eap->arg, eap->getline, eap->cookie,
2746 DOCMD_VERBOSE + DOCMD_NOWAIT);
2747
2748 if (eap->cmdidx == CMD_bufdo)
2749 {
2750 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002751 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002752 break;
2753 /* Check if the buffer still exists. */
2754 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2755 if (buf->b_fnum == next_fnum)
2756 break;
2757 if (buf == NULL)
2758 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002759
2760 /* Go to the next buffer. Clear 'shm' to avoid that the file
2761 * message overwrites any output from the command. */
2762 p_shm_save = vim_strsave(p_shm);
2763 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002765 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2766 vim_free(p_shm_save);
2767
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002768 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769 if (curbuf->b_fnum != next_fnum)
2770 break;
2771 }
2772
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002773#ifdef FEAT_QUICKFIX
2774 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2775 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2776 {
2777 if (i >= qf_size || i >= eap->line2)
2778 break;
2779
2780 qf_idx = qf_get_cur_idx(eap);
2781
2782 ex_cnext(eap);
2783
2784 /* If jumping to the next quickfix entry fails, quit here */
2785 if (qf_get_cur_idx(eap) == qf_idx)
2786 break;
2787 }
2788#endif
2789
Bram Moolenaar071d4272004-06-13 20:20:40 +00002790 if (eap->cmdidx == CMD_windo)
2791 {
2792 validate_cursor(); /* cursor may have moved */
2793#ifdef FEAT_SCROLLBIND
2794 /* required when 'scrollbind' has been set */
2795 if (curwin->w_p_scb)
2796 do_check_scrollbind(TRUE);
2797#endif
2798 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002799
2800#ifdef FEAT_WINDOWS
2801 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2802 if (i+1 > eap->line2)
2803 break;
2804#endif
2805 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2806 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807 }
2808 listcmd_busy = FALSE;
2809 }
2810
2811#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002812 if (save_ei != NULL)
2813 {
2814 au_event_restore(save_ei);
2815 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2816 curbuf->b_fname, TRUE, curbuf);
2817 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002818#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002819#ifdef FEAT_CLIPBOARD
2820 end_global_changes();
2821#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822}
2823
2824/*
2825 * Add files[count] to the arglist of the current window after arg "after".
2826 * The file names in files[count] must have been allocated and are taken over.
2827 * Files[] itself is not taken over.
2828 * Returns index of first added argument. Returns -1 when failed (out of mem).
2829 */
2830 static int
2831alist_add_list(count, files, after)
2832 int count;
2833 char_u **files;
2834 int after; /* where to add: 0 = before first one */
2835{
2836 int i;
2837
2838 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2839 {
2840 if (after < 0)
2841 after = 0;
2842 if (after > ARGCOUNT)
2843 after = ARGCOUNT;
2844 if (after < ARGCOUNT)
2845 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2846 (ARGCOUNT - after) * sizeof(aentry_T));
2847 for (i = 0; i < count; ++i)
2848 {
2849 ARGLIST[after + i].ae_fname = files[i];
2850 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2851 }
2852 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002853 if (curwin->w_arg_idx >= after)
2854 ++curwin->w_arg_idx;
2855 return after;
2856 }
2857
2858 for (i = 0; i < count; ++i)
2859 vim_free(files[i]);
2860 return -1;
2861}
2862
2863#endif /* FEAT_LISTCMDS */
2864
2865#ifdef FEAT_EVAL
2866/*
2867 * ":compiler[!] {name}"
2868 */
2869 void
2870ex_compiler(eap)
2871 exarg_T *eap;
2872{
2873 char_u *buf;
2874 char_u *old_cur_comp = NULL;
2875 char_u *p;
2876
2877 if (*eap->arg == NUL)
2878 {
2879 /* List all compiler scripts. */
2880 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2881 /* ) keep the indenter happy... */
2882 }
2883 else
2884 {
2885 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2886 if (buf != NULL)
2887 {
2888 if (eap->forceit)
2889 {
2890 /* ":compiler! {name}" sets global options */
2891 do_cmdline_cmd((char_u *)
2892 "command -nargs=* CompilerSet set <args>");
2893 }
2894 else
2895 {
2896 /* ":compiler! {name}" sets local options.
2897 * To remain backwards compatible "current_compiler" is always
2898 * used. A user's compiler plugin may set it, the distributed
2899 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002900 * "b:current_compiler" and restore "current_compiler".
2901 * Explicitly prepend "g:" to make it work in a function. */
2902 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002903 if (old_cur_comp != NULL)
2904 old_cur_comp = vim_strsave(old_cur_comp);
2905 do_cmdline_cmd((char_u *)
2906 "command -nargs=* CompilerSet setlocal <args>");
2907 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002908 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002909 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910
2911 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002912 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2914 vim_free(buf);
2915
2916 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2917
2918 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002919 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920 if (p != NULL)
2921 set_internal_string_var((char_u *)"b:current_compiler", p);
2922
2923 /* Restore "current_compiler" for ":compiler {name}". */
2924 if (!eap->forceit)
2925 {
2926 if (old_cur_comp != NULL)
2927 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002928 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002929 old_cur_comp);
2930 vim_free(old_cur_comp);
2931 }
2932 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002933 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934 }
2935 }
2936 }
2937}
2938#endif
2939
2940/*
2941 * ":runtime {name}"
2942 */
2943 void
2944ex_runtime(eap)
2945 exarg_T *eap;
2946{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002947 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948}
2949
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002950static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951
2952 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002953source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002955 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002957 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958}
2959
2960/*
2961 * Source the file "name" from all directories in 'runtimepath'.
2962 * "name" can contain wildcards.
2963 * When "all" is TRUE, source all files, otherwise only the first one.
2964 * return FAIL when no file could be sourced, OK otherwise.
2965 */
2966 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002967source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002968 char_u *name;
2969 int all;
2970{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002971 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002972}
2973
2974/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002975 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2976 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002977 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2978 * used.
2979 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002980 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002981 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2982 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002983 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002984 */
2985 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002986do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987 char_u *name;
2988 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002989 void (*callback)__ARGS((char_u *fname, void *ck));
2990 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002991{
2992 char_u *rtp;
2993 char_u *np;
2994 char_u *buf;
2995 char_u *rtp_copy;
2996 char_u *tail;
2997 int num_files;
2998 char_u **files;
2999 int i;
3000 int did_one = FALSE;
3001#ifdef AMIGA
3002 struct Process *proc = (struct Process *)FindTask(0L);
3003 APTR save_winptr = proc->pr_WindowPtr;
3004
3005 /* Avoid a requester here for a volume that doesn't exist. */
3006 proc->pr_WindowPtr = (APTR)-1L;
3007#endif
3008
3009 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3010 * value. */
3011 rtp_copy = vim_strsave(p_rtp);
3012 buf = alloc(MAXPATHL);
3013 if (buf != NULL && rtp_copy != NULL)
3014 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003015 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003016 {
3017 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003018 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003019 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003020 verbose_leave();
3021 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003022
Bram Moolenaar071d4272004-06-13 20:20:40 +00003023 /* Loop over all entries in 'runtimepath'. */
3024 rtp = rtp_copy;
3025 while (*rtp != NUL && (all || !did_one))
3026 {
3027 /* Copy the path from 'runtimepath' to buf[]. */
3028 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003029 if (name == NULL)
3030 {
3031 (*callback)(buf, (void *) &cookie);
3032 if (!did_one)
3033 did_one = (cookie == NULL);
3034 }
3035 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036 {
3037 add_pathsep(buf);
3038 tail = buf + STRLEN(buf);
3039
3040 /* Loop over all patterns in "name" */
3041 np = name;
3042 while (*np != NUL && (all || !did_one))
3043 {
3044 /* Append the pattern from "name" to buf[]. */
3045 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3046 "\t ");
3047
3048 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003049 {
3050 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003051 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003052 verbose_leave();
3053 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003054
3055 /* Expand wildcards, invoke the callback for each match. */
3056 if (gen_expand_wildcards(1, &buf, &num_files, &files,
3057 EW_FILE) == OK)
3058 {
3059 for (i = 0; i < num_files; ++i)
3060 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003061 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062 did_one = TRUE;
3063 if (!all)
3064 break;
3065 }
3066 FreeWild(num_files, files);
3067 }
3068 }
3069 }
3070 }
3071 }
3072 vim_free(buf);
3073 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003074 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003075 {
3076 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003077 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003078 verbose_leave();
3079 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003080
3081#ifdef AMIGA
3082 proc->pr_WindowPtr = save_winptr;
3083#endif
3084
3085 return did_one ? OK : FAIL;
3086}
3087
3088#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3089/*
3090 * ":options"
3091 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092 void
3093ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003094 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003095{
3096 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3097}
3098#endif
3099
3100/*
3101 * ":source {fname}"
3102 */
3103 void
3104ex_source(eap)
3105 exarg_T *eap;
3106{
3107#ifdef FEAT_BROWSE
3108 if (cmdmod.browse)
3109 {
3110 char_u *fname = NULL;
3111
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003112 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003113 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3114 if (fname != NULL)
3115 {
3116 cmd_source(fname, eap);
3117 vim_free(fname);
3118 }
3119 }
3120 else
3121#endif
3122 cmd_source(eap->arg, eap);
3123}
3124
3125 static void
3126cmd_source(fname, eap)
3127 char_u *fname;
3128 exarg_T *eap;
3129{
3130 if (*fname == NUL)
3131 EMSG(_(e_argreq));
3132
Bram Moolenaar071d4272004-06-13 20:20:40 +00003133 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003134 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003135 * Need to execute the commands directly. This is required at least
3136 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003137 * - ":g" command busy
3138 * - after ":argdo", ":windo" or ":bufdo"
3139 * - another command follows
3140 * - inside a loop
3141 */
3142 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3143#ifdef FEAT_EVAL
3144 || eap->cstack->cs_idx >= 0
3145#endif
3146 );
3147
3148 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003149 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150 EMSG2(_(e_notopen), fname);
3151}
3152
3153/*
3154 * ":source" and associated commands.
3155 */
3156/*
3157 * Structure used to store info for each sourced file.
3158 * It is shared between do_source() and getsourceline().
3159 * This is required, because it needs to be handed to do_cmdline() and
3160 * sourcing can be done recursively.
3161 */
3162struct source_cookie
3163{
3164 FILE *fp; /* opened file for sourcing */
3165 char_u *nextline; /* if not NULL: line that was read ahead */
3166 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003167#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3169 int error; /* TRUE if LF found after CR-LF */
3170#endif
3171#ifdef FEAT_EVAL
3172 linenr_T breakpoint; /* next line with breakpoint or zero */
3173 char_u *fname; /* name of sourced file */
3174 int dbg_tick; /* debug_tick when breakpoint was set */
3175 int level; /* top nesting level of sourced file */
3176#endif
3177#ifdef FEAT_MBYTE
3178 vimconv_T conv; /* type of conversion */
3179#endif
3180};
3181
3182#ifdef FEAT_EVAL
3183/*
3184 * Return the address holding the next breakpoint line for a source cookie.
3185 */
3186 linenr_T *
3187source_breakpoint(cookie)
3188 void *cookie;
3189{
3190 return &((struct source_cookie *)cookie)->breakpoint;
3191}
3192
3193/*
3194 * Return the address holding the debug tick for a source cookie.
3195 */
3196 int *
3197source_dbg_tick(cookie)
3198 void *cookie;
3199{
3200 return &((struct source_cookie *)cookie)->dbg_tick;
3201}
3202
3203/*
3204 * Return the nesting level for a source cookie.
3205 */
3206 int
3207source_level(cookie)
3208 void *cookie;
3209{
3210 return ((struct source_cookie *)cookie)->level;
3211}
3212#endif
3213
3214static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
3215
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003216#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3217# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003218static FILE *fopen_noinh_readbin __ARGS((char *filename));
3219
3220/*
3221 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003222 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223 */
3224 static FILE *
3225fopen_noinh_readbin(filename)
3226 char *filename;
3227{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003228# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003229 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3230# else
3231 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003232# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003233
3234 if (fd_tmp == -1)
3235 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003236
3237# ifdef HAVE_FD_CLOEXEC
3238 {
3239 int fdflags = fcntl(fd_tmp, F_GETFD);
3240 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003241 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003242 }
3243# endif
3244
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245 return fdopen(fd_tmp, READBIN);
3246}
3247#endif
3248
3249
3250/*
3251 * do_source: Read the file "fname" and execute its lines as EX commands.
3252 *
3253 * This function may be called recursively!
3254 *
3255 * return FAIL if file could not be opened, OK otherwise
3256 */
3257 int
3258do_source(fname, check_other, is_vimrc)
3259 char_u *fname;
3260 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003261 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262{
3263 struct source_cookie cookie;
3264 char_u *save_sourcing_name;
3265 linenr_T save_sourcing_lnum;
3266 char_u *p;
3267 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003268 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269 int retval = FAIL;
3270#ifdef FEAT_EVAL
3271 scid_T save_current_SID;
3272 static scid_T last_current_SID = 0;
3273 void *save_funccalp;
3274 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003275 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003276# ifdef UNIX
3277 struct stat st;
3278 int stat_ok;
3279# endif
3280#endif
3281#ifdef STARTUPTIME
3282 struct timeval tv_rel;
3283 struct timeval tv_start;
3284#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003285#ifdef FEAT_PROFILE
3286 proftime_T wait_start;
3287#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290 if (p == NULL)
3291 return retval;
3292 fname_exp = fix_fname(p);
3293 vim_free(p);
3294 if (fname_exp == NULL)
3295 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296 if (mch_isdir(fname_exp))
3297 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003298 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299 goto theend;
3300 }
3301
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003302#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003303 /* Apply SourceCmd autocommands, they should get the file and source it. */
3304 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3305 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3306 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003307 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003308# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003309 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003310# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003311 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003312# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003313 goto theend;
3314 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003315
3316 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003317 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3318#endif
3319
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003320#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3322#else
3323 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3324#endif
3325 if (cookie.fp == NULL && check_other)
3326 {
3327 /*
3328 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3329 * and ".exrc" by "_exrc" or vice versa.
3330 */
3331 p = gettail(fname_exp);
3332 if ((*p == '.' || *p == '_')
3333 && (STRICMP(p + 1, "vimrc") == 0
3334 || STRICMP(p + 1, "gvimrc") == 0
3335 || STRICMP(p + 1, "exrc") == 0))
3336 {
3337 if (*p == '_')
3338 *p = '.';
3339 else
3340 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003341#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3343#else
3344 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3345#endif
3346 }
3347 }
3348
3349 if (cookie.fp == NULL)
3350 {
3351 if (p_verbose > 0)
3352 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003353 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003355 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356 else
3357 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003358 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003359 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003360 }
3361 goto theend;
3362 }
3363
3364 /*
3365 * The file exists.
3366 * - In verbose mode, give a message.
3367 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3368 */
3369 if (p_verbose > 1)
3370 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003371 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003373 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003374 else
3375 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003376 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003377 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003378 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003379 if (is_vimrc == DOSO_VIMRC)
3380 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3381 else if (is_vimrc == DOSO_GVIMRC)
3382 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383
3384#ifdef USE_CRNL
3385 /* If no automatic file format: Set default to CR-NL. */
3386 if (*p_ffs == NUL)
3387 cookie.fileformat = EOL_DOS;
3388 else
3389 cookie.fileformat = EOL_UNKNOWN;
3390 cookie.error = FALSE;
3391#endif
3392
3393#ifdef USE_CR
3394 /* If no automatic file format: Set default to CR. */
3395 if (*p_ffs == NUL)
3396 cookie.fileformat = EOL_MAC;
3397 else
3398 cookie.fileformat = EOL_UNKNOWN;
3399 cookie.error = FALSE;
3400#endif
3401
3402 cookie.nextline = NULL;
3403 cookie.finished = FALSE;
3404
3405#ifdef FEAT_EVAL
3406 /*
3407 * Check if this script has a breakpoint.
3408 */
3409 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3410 cookie.fname = fname_exp;
3411 cookie.dbg_tick = debug_tick;
3412
3413 cookie.level = ex_nesting_level;
3414#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003415
3416 /*
3417 * Keep the sourcing name/lnum, for recursive calls.
3418 */
3419 save_sourcing_name = sourcing_name;
3420 sourcing_name = fname_exp;
3421 save_sourcing_lnum = sourcing_lnum;
3422 sourcing_lnum = 0;
3423
Bram Moolenaar73881402009-02-04 16:50:47 +00003424#ifdef FEAT_MBYTE
3425 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3426
3427 /* Read the first line so we can check for a UTF-8 BOM. */
3428 firstline = getsourceline(0, (void *)&cookie, 0);
3429 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3430 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3431 {
3432 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3433 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3434 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003435 if (p == NULL)
3436 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003437 if (p != NULL)
3438 {
3439 vim_free(firstline);
3440 firstline = p;
3441 }
3442 }
3443#endif
3444
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003446 if (time_fd != NULL)
3447 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448#endif
3449
3450#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003451# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003452 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003453 prof_child_enter(&wait_start); /* entering a child now */
3454# endif
3455
3456 /* Don't use local function variables, if called from a function.
3457 * Also starts profiling timer for nested script. */
3458 save_funccalp = save_funccal();
3459
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460 /*
3461 * Check if this script was sourced before to finds its SID.
3462 * If it's new, generate a new SID.
3463 */
3464 save_current_SID = current_SID;
3465# ifdef UNIX
3466 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3467# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003468 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3469 {
3470 si = &SCRIPT_ITEM(current_SID);
3471 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003472 && (
3473# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003474 /* Compare dev/ino when possible, it catches symbolic
3475 * links. Also compare file names, the inode may change
3476 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003477 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003478 && (si->sn_dev == st.st_dev
3479 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003481 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003483 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484 if (current_SID == 0)
3485 {
3486 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003487 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3488 == FAIL)
3489 goto almosttheend;
3490 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003492 ++script_items.ga_len;
3493 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3494# ifdef FEAT_PROFILE
3495 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003496# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003497 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003498 si = &SCRIPT_ITEM(current_SID);
3499 si->sn_name = fname_exp;
3500 fname_exp = NULL;
3501# ifdef UNIX
3502 if (stat_ok)
3503 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003504 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003505 si->sn_dev = st.st_dev;
3506 si->sn_ino = st.st_ino;
3507 }
3508 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003509 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003510# endif
3511
Bram Moolenaar071d4272004-06-13 20:20:40 +00003512 /* Allocate the local script variables to use for this script. */
3513 new_script_vars(current_SID);
3514 }
3515
Bram Moolenaar05159a02005-02-26 23:04:13 +00003516# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003517 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003518 {
3519 int forceit;
3520
3521 /* Check if we do profiling for this script. */
3522 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3523 {
3524 script_do_profile(si);
3525 si->sn_pr_force = forceit;
3526 }
3527 if (si->sn_prof_on)
3528 {
3529 ++si->sn_pr_count;
3530 profile_start(&si->sn_pr_start);
3531 profile_zero(&si->sn_pr_children);
3532 }
3533 }
3534# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003535#endif
3536
3537 /*
3538 * Call do_cmdline, which will call getsourceline() to get the lines.
3539 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003540 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003543
3544#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003545 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003546 {
3547 /* Get "si" again, "script_items" may have been reallocated. */
3548 si = &SCRIPT_ITEM(current_SID);
3549 if (si->sn_prof_on)
3550 {
3551 profile_end(&si->sn_pr_start);
3552 profile_sub_wait(&wait_start, &si->sn_pr_start);
3553 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003554 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3555 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003556 }
3557 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003558#endif
3559
3560 if (got_int)
3561 EMSG(_(e_interr));
3562 sourcing_name = save_sourcing_name;
3563 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003564 if (p_verbose > 1)
3565 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003566 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003567 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003568 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003569 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003570 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571 }
3572#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003573 if (time_fd != NULL)
3574 {
3575 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3576 time_msg((char *)IObuff, &tv_start);
3577 time_pop(&tv_rel);
3578 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003579#endif
3580
3581#ifdef FEAT_EVAL
3582 /*
3583 * After a "finish" in debug mode, need to break at first command of next
3584 * sourced file.
3585 */
3586 if (save_debug_break_level > ex_nesting_level
3587 && debug_break_level == ex_nesting_level)
3588 ++debug_break_level;
3589#endif
3590
Bram Moolenaar05159a02005-02-26 23:04:13 +00003591#ifdef FEAT_EVAL
3592almosttheend:
3593 current_SID = save_current_SID;
3594 restore_funccal(save_funccalp);
3595# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003596 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003597 prof_child_exit(&wait_start); /* leaving a child now */
3598# endif
3599#endif
3600 fclose(cookie.fp);
3601 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003602 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003603#ifdef FEAT_MBYTE
3604 convert_setup(&cookie.conv, NULL, NULL);
3605#endif
3606
Bram Moolenaar071d4272004-06-13 20:20:40 +00003607theend:
3608 vim_free(fname_exp);
3609 return retval;
3610}
3611
3612#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003613
Bram Moolenaar071d4272004-06-13 20:20:40 +00003614/*
3615 * ":scriptnames"
3616 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617 void
3618ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003619 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003620{
3621 int i;
3622
Bram Moolenaar05159a02005-02-26 23:04:13 +00003623 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3624 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003625 {
3626 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3627 NameBuff, MAXPATHL, TRUE);
3628 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003629 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630}
3631
3632# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3633/*
3634 * Fix slashes in the list of script names for 'shellslash'.
3635 */
3636 void
3637scriptnames_slash_adjust()
3638{
3639 int i;
3640
Bram Moolenaar05159a02005-02-26 23:04:13 +00003641 for (i = 1; i <= script_items.ga_len; ++i)
3642 if (SCRIPT_ITEM(i).sn_name != NULL)
3643 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003644}
3645# endif
3646
3647/*
3648 * Get a pointer to a script name. Used for ":verbose set".
3649 */
3650 char_u *
3651get_scriptname(id)
3652 scid_T id;
3653{
3654 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003655 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003656 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003657 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003658 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003659 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003660 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003661 return (char_u *)_("environment variable");
3662 if (id == SID_ERROR)
3663 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003664 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003666
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003667# if defined(EXITFREE) || defined(PROTO)
3668 void
3669free_scriptnames()
3670{
3671 int i;
3672
3673 for (i = script_items.ga_len; i > 0; --i)
3674 vim_free(SCRIPT_ITEM(i).sn_name);
3675 ga_clear(&script_items);
3676}
3677# endif
3678
Bram Moolenaar071d4272004-06-13 20:20:40 +00003679#endif
3680
3681#if defined(USE_CR) || defined(PROTO)
3682
3683# if defined(__MSL__) && (__MSL__ >= 22)
3684/*
3685 * Newer version of the Metrowerks library handle DOS and UNIX files
3686 * without help.
3687 * Test with earlier versions, MSL 2.2 is the library supplied with
3688 * Codewarrior Pro 2.
3689 */
3690 char *
3691fgets_cr(s, n, stream)
3692 char *s;
3693 int n;
3694 FILE *stream;
3695{
3696 return fgets(s, n, stream);
3697}
3698# else
3699/*
3700 * Version of fgets() which also works for lines ending in a <CR> only
3701 * (Macintosh format).
3702 * For older versions of the Metrowerks library.
3703 * At least CodeWarrior 9 needed this code.
3704 */
3705 char *
3706fgets_cr(s, n, stream)
3707 char *s;
3708 int n;
3709 FILE *stream;
3710{
3711 int c = 0;
3712 int char_read = 0;
3713
3714 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3715 {
3716 c = fgetc(stream);
3717 s[char_read++] = c;
3718 /* If the file is in DOS format, we need to skip a NL after a CR. I
3719 * thought it was the other way around, but this appears to work... */
3720 if (c == '\n')
3721 {
3722 c = fgetc(stream);
3723 if (c != '\r')
3724 ungetc(c, stream);
3725 }
3726 }
3727
3728 s[char_read] = 0;
3729 if (char_read == 0)
3730 return NULL;
3731
3732 if (feof(stream) && char_read == 1)
3733 return NULL;
3734
3735 return s;
3736}
3737# endif
3738#endif
3739
3740/*
3741 * Get one full line from a sourced file.
3742 * Called by do_cmdline() when it's called from do_source().
3743 *
3744 * Return a pointer to the line in allocated memory.
3745 * Return NULL for end-of-file or some error.
3746 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003747 char_u *
3748getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003749 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003750 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003751 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003752{
3753 struct source_cookie *sp = (struct source_cookie *)cookie;
3754 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003755 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003756
3757#ifdef FEAT_EVAL
3758 /* If breakpoints have been added/deleted need to check for it. */
3759 if (sp->dbg_tick < debug_tick)
3760 {
3761 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3762 sp->dbg_tick = debug_tick;
3763 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003764# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003765 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003766 script_line_end();
3767# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003768#endif
3769 /*
3770 * Get current line. If there is a read-ahead line, use it, otherwise get
3771 * one now.
3772 */
3773 if (sp->finished)
3774 line = NULL;
3775 else if (sp->nextline == NULL)
3776 line = get_one_sourceline(sp);
3777 else
3778 {
3779 line = sp->nextline;
3780 sp->nextline = NULL;
3781 ++sourcing_lnum;
3782 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003783#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003784 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003785 script_line_start();
3786#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003787
3788 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3789 * contain the 'C' flag. */
3790 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3791 {
3792 /* compensate for the one line read-ahead */
3793 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003794
3795 /* Get the next line and concatenate it when it starts with a
3796 * backslash. We always need to read the next line, keep it in
3797 * sp->nextline. */
3798 sp->nextline = get_one_sourceline(sp);
3799 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003800 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003801 garray_T ga;
3802
Bram Moolenaarb549a732012-02-22 18:29:33 +01003803 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003804 ga_concat(&ga, line);
3805 ga_concat(&ga, p + 1);
3806 for (;;)
3807 {
3808 vim_free(sp->nextline);
3809 sp->nextline = get_one_sourceline(sp);
3810 if (sp->nextline == NULL)
3811 break;
3812 p = skipwhite(sp->nextline);
3813 if (*p != '\\')
3814 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003815 /* Adjust the growsize to the current length to speed up
3816 * concatenating many lines. */
3817 if (ga.ga_len > 400)
3818 {
3819 if (ga.ga_len > 8000)
3820 ga.ga_growsize = 8000;
3821 else
3822 ga.ga_growsize = ga.ga_len;
3823 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003824 ga_concat(&ga, p + 1);
3825 }
3826 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003827 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003828 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829 }
3830 }
3831
3832#ifdef FEAT_MBYTE
3833 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3834 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003835 char_u *s;
3836
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 /* Convert the encoding of the script line. */
3838 s = string_convert(&sp->conv, line, NULL);
3839 if (s != NULL)
3840 {
3841 vim_free(line);
3842 line = s;
3843 }
3844 }
3845#endif
3846
3847#ifdef FEAT_EVAL
3848 /* Did we encounter a breakpoint? */
3849 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3850 {
3851 dbg_breakpoint(sp->fname, sourcing_lnum);
3852 /* Find next breakpoint. */
3853 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3854 sp->dbg_tick = debug_tick;
3855 }
3856#endif
3857
3858 return line;
3859}
3860
3861 static char_u *
3862get_one_sourceline(sp)
3863 struct source_cookie *sp;
3864{
3865 garray_T ga;
3866 int len;
3867 int c;
3868 char_u *buf;
3869#ifdef USE_CRNL
3870 int has_cr; /* CR-LF found */
3871#endif
3872#ifdef USE_CR
3873 char_u *scan;
3874#endif
3875 int have_read = FALSE;
3876
3877 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003878 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003879
3880 /*
3881 * Loop until there is a finished line (or end-of-file).
3882 */
3883 sourcing_lnum++;
3884 for (;;)
3885 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003886 /* make room to read at least 120 (more) characters */
3887 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888 break;
3889 buf = (char_u *)ga.ga_data;
3890
3891#ifdef USE_CR
3892 if (sp->fileformat == EOL_MAC)
3893 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003894 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3895 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896 break;
3897 }
3898 else
3899#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003900 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3901 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003902 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003903 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003904#ifdef USE_CRNL
3905 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3906 * CTRL-Z by its own, or after a NL. */
3907 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3908 && sp->fileformat == EOL_DOS
3909 && buf[len - 1] == Ctrl_Z)
3910 {
3911 buf[len - 1] = NUL;
3912 break;
3913 }
3914#endif
3915
3916#ifdef USE_CR
3917 /* If the read doesn't stop on a new line, and there's
3918 * some CR then we assume a Mac format */
3919 if (sp->fileformat == EOL_UNKNOWN)
3920 {
3921 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3922 sp->fileformat = EOL_MAC;
3923 else
3924 sp->fileformat = EOL_UNIX;
3925 }
3926
3927 if (sp->fileformat == EOL_MAC)
3928 {
3929 scan = vim_strchr(buf, '\r');
3930
3931 if (scan != NULL)
3932 {
3933 *scan = '\n';
3934 if (*(scan + 1) != 0)
3935 {
3936 *(scan + 1) = 0;
3937 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3938 }
3939 }
3940 len = STRLEN(buf);
3941 }
3942#endif
3943
3944 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003945 ga.ga_len = len;
3946
3947 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003948 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003949 continue;
3950
3951 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3952 {
3953#ifdef USE_CRNL
3954 has_cr = (len >= 2 && buf[len - 2] == '\r');
3955 if (sp->fileformat == EOL_UNKNOWN)
3956 {
3957 if (has_cr)
3958 sp->fileformat = EOL_DOS;
3959 else
3960 sp->fileformat = EOL_UNIX;
3961 }
3962
3963 if (sp->fileformat == EOL_DOS)
3964 {
3965 if (has_cr) /* replace trailing CR */
3966 {
3967 buf[len - 2] = '\n';
3968 --len;
3969 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003970 }
3971 else /* lines like ":map xx yy^M" will have failed */
3972 {
3973 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003974 {
3975 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003976 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003977 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003978 sp->error = TRUE;
3979 sp->fileformat = EOL_UNIX;
3980 }
3981 }
3982#endif
3983 /* The '\n' is escaped if there is an odd number of ^V's just
3984 * before it, first set "c" just before the 'V's and then check
3985 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3986 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3987 ;
3988 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3989 {
3990 sourcing_lnum++;
3991 continue;
3992 }
3993
3994 buf[len - 1] = NUL; /* remove the NL */
3995 }
3996
3997 /*
3998 * Check for ^C here now and then, so recursive :so can be broken.
3999 */
4000 line_breakcheck();
4001 break;
4002 }
4003
4004 if (have_read)
4005 return (char_u *)ga.ga_data;
4006
4007 vim_free(ga.ga_data);
4008 return NULL;
4009}
4010
Bram Moolenaar05159a02005-02-26 23:04:13 +00004011#if defined(FEAT_PROFILE) || defined(PROTO)
4012/*
4013 * Called when starting to read a script line.
4014 * "sourcing_lnum" must be correct!
4015 * When skipping lines it may not actually be executed, but we won't find out
4016 * until later and we need to store the time now.
4017 */
4018 void
4019script_line_start()
4020{
4021 scriptitem_T *si;
4022 sn_prl_T *pp;
4023
4024 if (current_SID <= 0 || current_SID > script_items.ga_len)
4025 return;
4026 si = &SCRIPT_ITEM(current_SID);
4027 if (si->sn_prof_on && sourcing_lnum >= 1)
4028 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004029 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004030 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004031 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004032 si->sn_prl_idx = sourcing_lnum - 1;
4033 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4034 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4035 {
4036 /* Zero counters for a line that was not used before. */
4037 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4038 pp->snp_count = 0;
4039 profile_zero(&pp->sn_prl_total);
4040 profile_zero(&pp->sn_prl_self);
4041 ++si->sn_prl_ga.ga_len;
4042 }
4043 si->sn_prl_execed = FALSE;
4044 profile_start(&si->sn_prl_start);
4045 profile_zero(&si->sn_prl_children);
4046 profile_get_wait(&si->sn_prl_wait);
4047 }
4048}
4049
4050/*
4051 * Called when actually executing a function line.
4052 */
4053 void
4054script_line_exec()
4055{
4056 scriptitem_T *si;
4057
4058 if (current_SID <= 0 || current_SID > script_items.ga_len)
4059 return;
4060 si = &SCRIPT_ITEM(current_SID);
4061 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4062 si->sn_prl_execed = TRUE;
4063}
4064
4065/*
4066 * Called when done with a function line.
4067 */
4068 void
4069script_line_end()
4070{
4071 scriptitem_T *si;
4072 sn_prl_T *pp;
4073
4074 if (current_SID <= 0 || current_SID > script_items.ga_len)
4075 return;
4076 si = &SCRIPT_ITEM(current_SID);
4077 if (si->sn_prof_on && si->sn_prl_idx >= 0
4078 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4079 {
4080 if (si->sn_prl_execed)
4081 {
4082 pp = &PRL_ITEM(si, si->sn_prl_idx);
4083 ++pp->snp_count;
4084 profile_end(&si->sn_prl_start);
4085 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004086 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004087 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4088 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004089 }
4090 si->sn_prl_idx = -1;
4091 }
4092}
4093#endif
4094
Bram Moolenaar071d4272004-06-13 20:20:40 +00004095/*
4096 * ":scriptencoding": Set encoding conversion for a sourced script.
4097 * Without the multi-byte feature it's simply ignored.
4098 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004099 void
4100ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004101 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004102{
4103#ifdef FEAT_MBYTE
4104 struct source_cookie *sp;
4105 char_u *name;
4106
4107 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4108 {
4109 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4110 return;
4111 }
4112
4113 if (*eap->arg != NUL)
4114 {
4115 name = enc_canonize(eap->arg);
4116 if (name == NULL) /* out of memory */
4117 return;
4118 }
4119 else
4120 name = eap->arg;
4121
4122 /* Setup for conversion from the specified encoding to 'encoding'. */
4123 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4124 convert_setup(&sp->conv, name, p_enc);
4125
4126 if (name != eap->arg)
4127 vim_free(name);
4128#endif
4129}
4130
4131#if defined(FEAT_EVAL) || defined(PROTO)
4132/*
4133 * ":finish": Mark a sourced file as finished.
4134 */
4135 void
4136ex_finish(eap)
4137 exarg_T *eap;
4138{
4139 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4140 do_finish(eap, FALSE);
4141 else
4142 EMSG(_("E168: :finish used outside of a sourced file"));
4143}
4144
4145/*
4146 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4147 * Also called for a pending finish at the ":endtry" or after returning from
4148 * an extra do_cmdline(). "reanimate" is used in the latter case.
4149 */
4150 void
4151do_finish(eap, reanimate)
4152 exarg_T *eap;
4153 int reanimate;
4154{
4155 int idx;
4156
4157 if (reanimate)
4158 ((struct source_cookie *)getline_cookie(eap->getline,
4159 eap->cookie))->finished = FALSE;
4160
4161 /*
4162 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4163 * not in its finally clause (which then is to be executed next) is found.
4164 * In this case, make the ":finish" pending for execution at the ":endtry".
4165 * Otherwise, finish normally.
4166 */
4167 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4168 if (idx >= 0)
4169 {
4170 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4171 report_make_pending(CSTP_FINISH, NULL);
4172 }
4173 else
4174 ((struct source_cookie *)getline_cookie(eap->getline,
4175 eap->cookie))->finished = TRUE;
4176}
4177
4178
4179/*
4180 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4181 * message for missing ":endif".
4182 * Return FALSE when not sourcing a file.
4183 */
4184 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00004185source_finished(fgetline, cookie)
4186 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187 void *cookie;
4188{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004189 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004190 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004191 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192}
4193#endif
4194
4195#if defined(FEAT_LISTCMDS) || defined(PROTO)
4196/*
4197 * ":checktime [buffer]"
4198 */
4199 void
4200ex_checktime(eap)
4201 exarg_T *eap;
4202{
4203 buf_T *buf;
4204 int save_no_check_timestamps = no_check_timestamps;
4205
4206 no_check_timestamps = 0;
4207 if (eap->addr_count == 0) /* default is all buffers */
4208 check_timestamps(FALSE);
4209 else
4210 {
4211 buf = buflist_findnr((int)eap->line2);
4212 if (buf != NULL) /* cannot happen? */
4213 (void)buf_check_timestamp(buf, FALSE);
4214 }
4215 no_check_timestamps = save_no_check_timestamps;
4216}
4217#endif
4218
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4220 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004221# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004222static char *get_locale_val __ARGS((int what));
4223
4224 static char *
4225get_locale_val(what)
4226 int what;
4227{
4228 char *loc;
4229
4230 /* Obtain the locale value from the libraries. For DJGPP this is
4231 * redefined and it doesn't use the arguments. */
4232 loc = setlocale(what, NULL);
4233
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004234# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235 if (loc != NULL)
4236 {
4237 char_u *p;
4238
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004239 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4240 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241 p = vim_strchr(loc, '=');
4242 if (p != NULL)
4243 {
4244 loc = ++p;
4245 while (*p != NUL) /* remove trailing newline */
4246 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004247 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004248 {
4249 *p = NUL;
4250 break;
4251 }
4252 ++p;
4253 }
4254 }
4255 }
4256# endif
4257
4258 return loc;
4259}
4260#endif
4261
4262
4263#ifdef WIN32
4264/*
4265 * On MS-Windows locale names are strings like "German_Germany.1252", but
4266 * gettext expects "de". Try to translate one into another here for a few
4267 * supported languages.
4268 */
4269 static char_u *
4270gettext_lang(char_u *name)
4271{
4272 int i;
4273 static char *(mtable[]) = {
4274 "afrikaans", "af",
4275 "czech", "cs",
4276 "dutch", "nl",
4277 "german", "de",
4278 "english_united kingdom", "en_GB",
4279 "spanish", "es",
4280 "french", "fr",
4281 "italian", "it",
4282 "japanese", "ja",
4283 "korean", "ko",
4284 "norwegian", "no",
4285 "polish", "pl",
4286 "russian", "ru",
4287 "slovak", "sk",
4288 "swedish", "sv",
4289 "ukrainian", "uk",
4290 "chinese_china", "zh_CN",
4291 "chinese_taiwan", "zh_TW",
4292 NULL};
4293
4294 for (i = 0; mtable[i] != NULL; i += 2)
4295 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4296 return mtable[i + 1];
4297 return name;
4298}
4299#endif
4300
4301#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4302/*
4303 * Obtain the current messages language. Used to set the default for
4304 * 'helplang'. May return NULL or an empty string.
4305 */
4306 char_u *
4307get_mess_lang()
4308{
4309 char_u *p;
4310
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004311# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312# if defined(LC_MESSAGES)
4313 p = (char_u *)get_locale_val(LC_MESSAGES);
4314# else
4315 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004316 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4317 * and LC_MONETARY may be set differently for a Japanese working in the
4318 * US. */
4319 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320# endif
4321# else
4322 p = mch_getenv((char_u *)"LC_ALL");
4323 if (p == NULL || *p == NUL)
4324 {
4325 p = mch_getenv((char_u *)"LC_MESSAGES");
4326 if (p == NULL || *p == NUL)
4327 p = mch_getenv((char_u *)"LANG");
4328 }
4329# endif
4330# ifdef WIN32
4331 p = gettext_lang(p);
4332# endif
4333 return p;
4334}
4335#endif
4336
Bram Moolenaardef9e822004-12-31 20:58:58 +00004337/* Complicated #if; matches with where get_mess_env() is used below. */
4338#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4339 && defined(LC_MESSAGES))) \
4340 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4341 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4342 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004343static char_u *get_mess_env __ARGS((void));
4344
4345/*
4346 * Get the language used for messages from the environment.
4347 */
4348 static char_u *
4349get_mess_env()
4350{
4351 char_u *p;
4352
4353 p = mch_getenv((char_u *)"LC_ALL");
4354 if (p == NULL || *p == NUL)
4355 {
4356 p = mch_getenv((char_u *)"LC_MESSAGES");
4357 if (p == NULL || *p == NUL)
4358 {
4359 p = mch_getenv((char_u *)"LANG");
4360 if (p != NULL && VIM_ISDIGIT(*p))
4361 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004362# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363 if (p == NULL || *p == NUL)
4364 p = (char_u *)get_locale_val(LC_CTYPE);
4365# endif
4366 }
4367 }
4368 return p;
4369}
4370#endif
4371
4372#if defined(FEAT_EVAL) || defined(PROTO)
4373
4374/*
4375 * Set the "v:lang" variable according to the current locale setting.
4376 * Also do "v:lc_time"and "v:ctype".
4377 */
4378 void
4379set_lang_var()
4380{
4381 char_u *loc;
4382
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004383# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004384 loc = (char_u *)get_locale_val(LC_CTYPE);
4385# else
4386 /* setlocale() not supported: use the default value */
4387 loc = (char_u *)"C";
4388# endif
4389 set_vim_var_string(VV_CTYPE, loc, -1);
4390
4391 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4392 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004393# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394 loc = (char_u *)get_locale_val(LC_MESSAGES);
4395# else
4396 loc = get_mess_env();
4397# endif
4398 set_vim_var_string(VV_LANG, loc, -1);
4399
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004400# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004401 loc = (char_u *)get_locale_val(LC_TIME);
4402# endif
4403 set_vim_var_string(VV_LC_TIME, loc, -1);
4404}
4405#endif
4406
4407#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4408 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4409/*
4410 * ":language": Set the language (locale).
4411 */
4412 void
4413ex_language(eap)
4414 exarg_T *eap;
4415{
4416 char *loc;
4417 char_u *p;
4418 char_u *name;
4419 int what = LC_ALL;
4420 char *whatstr = "";
4421#ifdef LC_MESSAGES
4422# define VIM_LC_MESSAGES LC_MESSAGES
4423#else
4424# define VIM_LC_MESSAGES 6789
4425#endif
4426
4427 name = eap->arg;
4428
4429 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4430 * Allow abbreviation, but require at least 3 characters to avoid
4431 * confusion with a two letter language name "me" or "ct". */
4432 p = skiptowhite(eap->arg);
4433 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4434 {
4435 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4436 {
4437 what = VIM_LC_MESSAGES;
4438 name = skipwhite(p);
4439 whatstr = "messages ";
4440 }
4441 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4442 {
4443 what = LC_CTYPE;
4444 name = skipwhite(p);
4445 whatstr = "ctype ";
4446 }
4447 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4448 {
4449 what = LC_TIME;
4450 name = skipwhite(p);
4451 whatstr = "time ";
4452 }
4453 }
4454
4455 if (*name == NUL)
4456 {
4457#ifndef LC_MESSAGES
4458 if (what == VIM_LC_MESSAGES)
4459 p = get_mess_env();
4460 else
4461#endif
4462 p = (char_u *)setlocale(what, NULL);
4463 if (p == NULL || *p == NUL)
4464 p = (char_u *)"Unknown";
4465 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4466 }
4467 else
4468 {
4469#ifndef LC_MESSAGES
4470 if (what == VIM_LC_MESSAGES)
4471 loc = "";
4472 else
4473#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004474 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004476#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4477 /* Make sure strtod() uses a decimal point, not a comma. */
4478 setlocale(LC_NUMERIC, "C");
4479#endif
4480 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004481 if (loc == NULL)
4482 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4483 else
4484 {
4485#ifdef HAVE_NL_MSG_CAT_CNTR
4486 /* Need to do this for GNU gettext, otherwise cached translations
4487 * will be used again. */
4488 extern int _nl_msg_cat_cntr;
4489
4490 ++_nl_msg_cat_cntr;
4491#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004492 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004493 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4494
4495 if (what != LC_TIME)
4496 {
4497 /* Tell gettext() what to translate to. It apparently doesn't
4498 * use the currently effective locale. Also do this when
4499 * FEAT_GETTEXT isn't defined, so that shell commands use this
4500 * value. */
4501 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004502 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004504
4505 /* Clear $LANGUAGE because GNU gettext uses it. */
4506 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004507# ifdef WIN32
4508 /* Apparently MS-Windows printf() may cause a crash when
4509 * we give it 8-bit text while it's expecting text in the
4510 * current locale. This call avoids that. */
4511 setlocale(LC_CTYPE, "C");
4512# endif
4513 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004514 if (what != LC_CTYPE)
4515 {
4516 char_u *mname;
4517#ifdef WIN32
4518 mname = gettext_lang(name);
4519#else
4520 mname = name;
4521#endif
4522 vim_setenv((char_u *)"LC_MESSAGES", mname);
4523#ifdef FEAT_MULTI_LANG
4524 set_helplang_default(mname);
4525#endif
4526 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004527 }
4528
4529# ifdef FEAT_EVAL
4530 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4531 set_lang_var();
4532# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004533# ifdef FEAT_TITLE
4534 maketitle();
4535# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004536 }
4537 }
4538}
4539
4540# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004541
4542static char_u **locales = NULL; /* Array of all available locales */
4543static int did_init_locales = FALSE;
4544
4545static void init_locales __ARGS((void));
4546static char_u **find_locales __ARGS((void));
4547
4548/*
4549 * Lazy initialization of all available locales.
4550 */
4551 static void
4552init_locales()
4553{
4554 if (!did_init_locales)
4555 {
4556 did_init_locales = TRUE;
4557 locales = find_locales();
4558 }
4559}
4560
4561/* Return an array of strings for all available locales + NULL for the
4562 * last element. Return NULL in case of error. */
4563 static char_u **
4564find_locales()
4565{
4566 garray_T locales_ga;
4567 char_u *loc;
4568
4569 /* Find all available locales by running command "locale -a". If this
4570 * doesn't work we won't have completion. */
4571 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004572 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004573 if (locale_a == NULL)
4574 return NULL;
4575 ga_init2(&locales_ga, sizeof(char_u *), 20);
4576
4577 /* Transform locale_a string where each locale is separated by "\n"
4578 * into an array of locale strings. */
4579 loc = (char_u *)strtok((char *)locale_a, "\n");
4580
4581 while (loc != NULL)
4582 {
4583 if (ga_grow(&locales_ga, 1) == FAIL)
4584 break;
4585 loc = vim_strsave(loc);
4586 if (loc == NULL)
4587 break;
4588
4589 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4590 loc = (char_u *)strtok(NULL, "\n");
4591 }
4592 vim_free(locale_a);
4593 if (ga_grow(&locales_ga, 1) == FAIL)
4594 {
4595 ga_clear(&locales_ga);
4596 return NULL;
4597 }
4598 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4599 return (char_u **)locales_ga.ga_data;
4600}
4601
4602# if defined(EXITFREE) || defined(PROTO)
4603 void
4604free_locales()
4605{
4606 int i;
4607 if (locales != NULL)
4608 {
4609 for (i = 0; locales[i] != NULL; i++)
4610 vim_free(locales[i]);
4611 vim_free(locales);
4612 locales = NULL;
4613 }
4614}
4615# endif
4616
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617/*
4618 * Function given to ExpandGeneric() to obtain the possible arguments of the
4619 * ":language" command.
4620 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004621 char_u *
4622get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004623 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004624 int idx;
4625{
4626 if (idx == 0)
4627 return (char_u *)"messages";
4628 if (idx == 1)
4629 return (char_u *)"ctype";
4630 if (idx == 2)
4631 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004632
4633 init_locales();
4634 if (locales == NULL)
4635 return NULL;
4636 return locales[idx - 3];
4637}
4638
4639/*
4640 * Function given to ExpandGeneric() to obtain the available locales.
4641 */
4642 char_u *
4643get_locales(xp, idx)
4644 expand_T *xp UNUSED;
4645 int idx;
4646{
4647 init_locales();
4648 if (locales == NULL)
4649 return NULL;
4650 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004651}
4652# endif
4653
4654#endif