blob: 611a363392844c858c8ba25c2aa7413afd21f8c4 [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. */
71
72/*
73 * do_debug(): Debug mode.
74 * Repeatedly get Ex commands, until told to continue normal execution.
75 */
76 void
77do_debug(cmd)
78 char_u *cmd;
79{
80 int save_msg_scroll = msg_scroll;
81 int save_State = State;
82 int save_did_emsg = did_emsg;
83 int save_cmd_silent = cmd_silent;
84 int save_msg_silent = msg_silent;
85 int save_emsg_silent = emsg_silent;
86 int save_redir_off = redir_off;
87 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000088 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000089 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000090# ifdef FEAT_EX_EXTRA
91 int save_ex_normal_busy;
92# endif
93 int n;
94 char_u *cmdline = NULL;
95 char_u *p;
96 char *tail = NULL;
97 static int last_cmd = 0;
98#define CMD_CONT 1
99#define CMD_NEXT 2
100#define CMD_STEP 3
101#define CMD_FINISH 4
102#define CMD_QUIT 5
103#define CMD_INTERRUPT 6
104
105#ifdef ALWAYS_USE_GUI
106 /* Can't do this when there is no terminal for input/output. */
107 if (!gui.in_use)
108 {
109 /* Break as soon as possible. */
110 debug_break_level = 9999;
111 return;
112 }
113#endif
114
115 /* Make sure we are in raw mode and start termcap mode. Might have side
116 * effects... */
117 settmode(TMODE_RAW);
118 starttermcap();
119
120 ++RedrawingDisabled; /* don't redisplay the window */
121 ++no_wait_return; /* don't wait for return */
122 did_emsg = FALSE; /* don't use error from debugged stuff */
123 cmd_silent = FALSE; /* display commands */
124 msg_silent = FALSE; /* display messages */
125 emsg_silent = FALSE; /* display error messages */
126 redir_off = TRUE; /* don't redirect debug commands */
127
128 State = NORMAL;
129#ifdef FEAT_SNIFF
130 want_sniff_request = 0; /* No K_SNIFF wanted */
131#endif
132
133 if (!debug_did_msg)
134 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
135 if (sourcing_name != NULL)
136 msg(sourcing_name);
137 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000138 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141
142 /*
143 * Repeat getting a command and executing it.
144 */
145 for (;;)
146 {
147 msg_scroll = TRUE;
148 need_wait_return = FALSE;
149#ifdef FEAT_SNIFF
150 ProcessSniffRequests();
151#endif
152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157# ifdef FEAT_EX_EXTRA
158 save_ex_normal_busy = ex_normal_busy;
159 ex_normal_busy = 0;
160# endif
161 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000164 typeahead_saved = TRUE;
165 save_ignore_script = ignore_script;
166 ignore_script = TRUE;
167 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000169 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000171 if (typeahead_saved)
172 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000174 ignore_script = save_ignore_script;
175 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176# ifdef FEAT_EX_EXTRA
177 ex_normal_busy = save_ex_normal_busy;
178# endif
179
180 cmdline_row = msg_row;
181 if (cmdline != NULL)
182 {
183 /* If this is a debug command, set "last_cmd".
184 * If not, reset "last_cmd".
185 * For a blank line use previous command. */
186 p = skipwhite(cmdline);
187 if (*p != NUL)
188 {
189 switch (*p)
190 {
191 case 'c': last_cmd = CMD_CONT;
192 tail = "ont";
193 break;
194 case 'n': last_cmd = CMD_NEXT;
195 tail = "ext";
196 break;
197 case 's': last_cmd = CMD_STEP;
198 tail = "tep";
199 break;
200 case 'f': last_cmd = CMD_FINISH;
201 tail = "inish";
202 break;
203 case 'q': last_cmd = CMD_QUIT;
204 tail = "uit";
205 break;
206 case 'i': last_cmd = CMD_INTERRUPT;
207 tail = "nterrupt";
208 break;
209 default: last_cmd = 0;
210 }
211 if (last_cmd != 0)
212 {
213 /* Check that the tail matches. */
214 ++p;
215 while (*p != NUL && *p == *tail)
216 {
217 ++p;
218 ++tail;
219 }
220 if (ASCII_ISALPHA(*p))
221 last_cmd = 0;
222 }
223 }
224
225 if (last_cmd != 0)
226 {
227 /* Execute debug command: decided where to break next and
228 * return. */
229 switch (last_cmd)
230 {
231 case CMD_CONT:
232 debug_break_level = -1;
233 break;
234 case CMD_NEXT:
235 debug_break_level = ex_nesting_level;
236 break;
237 case CMD_STEP:
238 debug_break_level = 9999;
239 break;
240 case CMD_FINISH:
241 debug_break_level = ex_nesting_level - 1;
242 break;
243 case CMD_QUIT:
244 got_int = TRUE;
245 debug_break_level = -1;
246 break;
247 case CMD_INTERRUPT:
248 got_int = TRUE;
249 debug_break_level = 9999;
250 /* Do not repeat ">interrupt" cmd, continue stepping. */
251 last_cmd = CMD_STEP;
252 break;
253 }
254 break;
255 }
256
257 /* don't debug this command */
258 n = debug_break_level;
259 debug_break_level = -1;
260 (void)do_cmdline(cmdline, getexline, NULL,
261 DOCMD_VERBOSE|DOCMD_EXCRESET);
262 debug_break_level = n;
263
264 vim_free(cmdline);
265 }
266 lines_left = Rows - 1;
267 }
268 vim_free(cmdline);
269
270 --RedrawingDisabled;
271 --no_wait_return;
272 redraw_all_later(NOT_VALID);
273 need_wait_return = FALSE;
274 msg_scroll = save_msg_scroll;
275 lines_left = Rows - 1;
276 State = save_State;
277 did_emsg = save_did_emsg;
278 cmd_silent = save_cmd_silent;
279 msg_silent = save_msg_silent;
280 emsg_silent = save_emsg_silent;
281 redir_off = save_redir_off;
282
283 /* Only print the message again when typing a command before coming back
284 * here. */
285 debug_did_msg = TRUE;
286}
287
288/*
289 * ":debug".
290 */
291 void
292ex_debug(eap)
293 exarg_T *eap;
294{
295 int debug_break_level_save = debug_break_level;
296
297 debug_break_level = 9999;
298 do_cmdline_cmd(eap->arg);
299 debug_break_level = debug_break_level_save;
300}
301
302static char_u *debug_breakpoint_name = NULL;
303static linenr_T debug_breakpoint_lnum;
304
305/*
306 * When debugging or a breakpoint is set on a skipped command, no debug prompt
307 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
308 * debug_skipped_name is then set to the source name in the breakpoint case. If
309 * a skipped command decides itself that a debug prompt should be displayed, it
310 * can do so by calling dbg_check_skipped().
311 */
312static int debug_skipped;
313static char_u *debug_skipped_name;
314
315/*
316 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
317 * at or below the break level. But only when the line is actually
318 * executed. Return TRUE and set breakpoint_name for skipped commands that
319 * decide to execute something themselves.
320 * Called from do_one_cmd() before executing a command.
321 */
322 void
323dbg_check_breakpoint(eap)
324 exarg_T *eap;
325{
326 char_u *p;
327
328 debug_skipped = FALSE;
329 if (debug_breakpoint_name != NULL)
330 {
331 if (!eap->skip)
332 {
333 /* replace K_SNR with "<SNR>" */
334 if (debug_breakpoint_name[0] == K_SPECIAL
335 && debug_breakpoint_name[1] == KS_EXTRA
336 && debug_breakpoint_name[2] == (int)KE_SNR)
337 p = (char_u *)"<SNR>";
338 else
339 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000340 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
341 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 debug_breakpoint_name + (*p == NUL ? 0 : 3),
343 (long)debug_breakpoint_lnum);
344 debug_breakpoint_name = NULL;
345 do_debug(eap->cmd);
346 }
347 else
348 {
349 debug_skipped = TRUE;
350 debug_skipped_name = debug_breakpoint_name;
351 debug_breakpoint_name = NULL;
352 }
353 }
354 else if (ex_nesting_level <= debug_break_level)
355 {
356 if (!eap->skip)
357 do_debug(eap->cmd);
358 else
359 {
360 debug_skipped = TRUE;
361 debug_skipped_name = NULL;
362 }
363 }
364}
365
366/*
367 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
368 * set. Return TRUE when the debug mode is entered this time.
369 */
370 int
371dbg_check_skipped(eap)
372 exarg_T *eap;
373{
374 int prev_got_int;
375
376 if (debug_skipped)
377 {
378 /*
379 * Save the value of got_int and reset it. We don't want a previous
380 * interruption cause flushing the input buffer.
381 */
382 prev_got_int = got_int;
383 got_int = FALSE;
384 debug_breakpoint_name = debug_skipped_name;
385 /* eap->skip is TRUE */
386 eap->skip = FALSE;
387 (void)dbg_check_breakpoint(eap);
388 eap->skip = TRUE;
389 got_int |= prev_got_int;
390 return TRUE;
391 }
392 return FALSE;
393}
394
395/*
396 * The list of breakpoints: dbg_breakp.
397 * This is a grow-array of structs.
398 */
399struct debuggy
400{
401 int dbg_nr; /* breakpoint number */
402 int dbg_type; /* DBG_FUNC or DBG_FILE */
403 char_u *dbg_name; /* function or file name */
404 regprog_T *dbg_prog; /* regexp program */
405 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000406 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407};
408
409static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000410#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
411#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412static int last_breakp = 0; /* nr of last defined breakpoint */
413
Bram Moolenaar05159a02005-02-26 23:04:13 +0000414#ifdef FEAT_PROFILE
415/* Profiling uses file and func names similar to breakpoints. */
416static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
417#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418#define DBG_FUNC 1
419#define DBG_FILE 2
420
Bram Moolenaar05159a02005-02-26 23:04:13 +0000421static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
422static 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 +0000423
424/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000425 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
426 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
427 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428 * Returns FAIL for failure.
429 */
430 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000431dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000433 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000434{
435 char_u *p = arg;
436 char_u *q;
437 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000438 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439
Bram Moolenaar05159a02005-02-26 23:04:13 +0000440 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000442 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443
444 /* Find "func" or "file". */
445 if (STRNCMP(p, "func", 4) == 0)
446 bp->dbg_type = DBG_FUNC;
447 else if (STRNCMP(p, "file", 4) == 0)
448 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000449 else if (
450#ifdef FEAT_PROFILE
451 gap != &prof_ga &&
452#endif
453 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000454 {
455 if (curbuf->b_ffname == NULL)
456 {
457 EMSG(_(e_noname));
458 return FAIL;
459 }
460 bp->dbg_type = DBG_FILE;
461 here = TRUE;
462 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463 else
464 {
465 EMSG2(_(e_invarg2), p);
466 return FAIL;
467 }
468 p = skipwhite(p + 4);
469
470 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000471 if (here)
472 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000473 else if (
474#ifdef FEAT_PROFILE
475 gap != &prof_ga &&
476#endif
477 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000478 {
479 bp->dbg_lnum = getdigits(&p);
480 p = skipwhite(p);
481 }
482 else
483 bp->dbg_lnum = 0;
484
485 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000486 if ((!here && *p == NUL)
487 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
489 {
490 EMSG2(_(e_invarg2), arg);
491 return FAIL;
492 }
493
494 if (bp->dbg_type == DBG_FUNC)
495 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000496 else if (here)
497 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 else
499 {
500 /* Expand the file name in the same way as do_source(). This means
501 * doing it twice, so that $DIR/file gets expanded when $DIR is
502 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 if (q == NULL)
505 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507 vim_free(q);
508 if (p == NULL)
509 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000510 if (*p != '*')
511 {
512 bp->dbg_name = fix_fname(p);
513 vim_free(p);
514 }
515 else
516 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517 }
518
519 if (bp->dbg_name == NULL)
520 return FAIL;
521 return OK;
522}
523
524/*
525 * ":breakadd".
526 */
527 void
528ex_breakadd(eap)
529 exarg_T *eap;
530{
531 struct debuggy *bp;
532 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534
Bram Moolenaar05159a02005-02-26 23:04:13 +0000535 gap = &dbg_breakp;
536#ifdef FEAT_PROFILE
537 if (eap->cmdidx == CMD_profile)
538 gap = &prof_ga;
539#endif
540
541 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000543 bp = &DEBUGGY(gap, gap->ga_len);
544 bp->dbg_forceit = eap->forceit;
545
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
547 if (pat != NULL)
548 {
549 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
550 vim_free(pat);
551 }
552 if (pat == NULL || bp->dbg_prog == NULL)
553 vim_free(bp->dbg_name);
554 else
555 {
556 if (bp->dbg_lnum == 0) /* default line number is 1 */
557 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000558#ifdef FEAT_PROFILE
559 if (eap->cmdidx != CMD_profile)
560#endif
561 {
562 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
563 ++debug_tick;
564 }
565 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 }
567 }
568}
569
570/*
571 * ":debuggreedy".
572 */
573 void
574ex_debuggreedy(eap)
575 exarg_T *eap;
576{
577 if (eap->addr_count == 0 || eap->line2 != 0)
578 debug_greedy = TRUE;
579 else
580 debug_greedy = FALSE;
581}
582
583/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000584 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585 */
586 void
587ex_breakdel(eap)
588 exarg_T *eap;
589{
590 struct debuggy *bp, *bpi;
591 int nr;
592 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000593 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 int i;
595 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000596 garray_T *gap;
597
598 gap = &dbg_breakp;
599#ifdef FEAT_PROFILE
600 if (eap->cmdidx == CMD_profdel)
601 gap = &prof_ga;
602#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603
604 if (vim_isdigit(*eap->arg))
605 {
606 /* ":breakdel {nr}" */
607 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000608 for (i = 0; i < gap->ga_len; ++i)
609 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610 {
611 todel = i;
612 break;
613 }
614 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000615 else if (*eap->arg == '*')
616 {
617 todel = 0;
618 del_all = TRUE;
619 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620 else
621 {
622 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000623 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000625 bp = &DEBUGGY(gap, gap->ga_len);
626 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000628 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629 if (bp->dbg_type == bpi->dbg_type
630 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
631 && (bp->dbg_lnum == bpi->dbg_lnum
632 || (bp->dbg_lnum == 0
633 && (best_lnum == 0
634 || bpi->dbg_lnum < best_lnum))))
635 {
636 todel = i;
637 best_lnum = bpi->dbg_lnum;
638 }
639 }
640 vim_free(bp->dbg_name);
641 }
642
643 if (todel < 0)
644 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
645 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000646 {
647 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000648 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000649 vim_free(DEBUGGY(gap, todel).dbg_name);
650 vim_free(DEBUGGY(gap, todel).dbg_prog);
651 --gap->ga_len;
652 if (todel < gap->ga_len)
653 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
654 (gap->ga_len - todel) * sizeof(struct debuggy));
655#ifdef FEAT_PROFILE
656 if (eap->cmdidx == CMD_breakdel)
657#endif
658 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000659 if (!del_all)
660 break;
661 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000662
663 /* If all breakpoints were removed clear the array. */
664 if (gap->ga_len == 0)
665 ga_clear(gap);
666 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667}
668
669/*
670 * ":breaklist".
671 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 void
673ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000674 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675{
676 struct debuggy *bp;
677 int i;
678
679 if (dbg_breakp.ga_len == 0)
680 MSG(_("No breakpoints defined"));
681 else
682 for (i = 0; i < dbg_breakp.ga_len; ++i)
683 {
684 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200685 if (bp->dbg_type == DBG_FILE)
686 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687 smsg((char_u *)_("%3d %s %s line %ld"),
688 bp->dbg_nr,
689 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200690 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691 (long)bp->dbg_lnum);
692 }
693}
694
695/*
696 * Find a breakpoint for a function or sourced file.
697 * Returns line number at which to break; zero when no matching breakpoint.
698 */
699 linenr_T
700dbg_find_breakpoint(file, fname, after)
701 int file; /* TRUE for a file, FALSE for a function */
702 char_u *fname; /* file or function name */
703 linenr_T after; /* after this line number */
704{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000705 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
706}
707
708#if defined(FEAT_PROFILE) || defined(PROTO)
709/*
710 * Return TRUE if profiling is on for a function or sourced file.
711 */
712 int
713has_profiling(file, fname, fp)
714 int file; /* TRUE for a file, FALSE for a function */
715 char_u *fname; /* file or function name */
716 int *fp; /* return: forceit */
717{
718 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
719 != (linenr_T)0);
720}
721#endif
722
723/*
724 * Common code for dbg_find_breakpoint() and has_profiling().
725 */
726 static linenr_T
727debuggy_find(file, fname, after, gap, fp)
728 int file; /* TRUE for a file, FALSE for a function */
729 char_u *fname; /* file or function name */
730 linenr_T after; /* after this line number */
731 garray_T *gap; /* either &dbg_breakp or &prof_ga */
732 int *fp; /* if not NULL: return forceit */
733{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 struct debuggy *bp;
735 int i;
736 linenr_T lnum = 0;
737 regmatch_T regmatch;
738 char_u *name = fname;
739 int prev_got_int;
740
Bram Moolenaar05159a02005-02-26 23:04:13 +0000741 /* Return quickly when there are no breakpoints. */
742 if (gap->ga_len == 0)
743 return (linenr_T)0;
744
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 /* Replace K_SNR in function name with "<SNR>". */
746 if (!file && fname[0] == K_SPECIAL)
747 {
748 name = alloc((unsigned)STRLEN(fname) + 3);
749 if (name == NULL)
750 name = fname;
751 else
752 {
753 STRCPY(name, "<SNR>");
754 STRCPY(name + 5, fname + 3);
755 }
756 }
757
Bram Moolenaar05159a02005-02-26 23:04:13 +0000758 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000760 /* Skip entries that are not useful or are for a line that is beyond
761 * an already found breakpoint. */
762 bp = &DEBUGGY(gap, i);
763 if (((bp->dbg_type == DBG_FILE) == file && (
764#ifdef FEAT_PROFILE
765 gap == &prof_ga ||
766#endif
767 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768 {
769 regmatch.regprog = bp->dbg_prog;
770 regmatch.rm_ic = FALSE;
771 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000772 * Save the value of got_int and reset it. We don't want a
773 * previous interruption cancel matching, only hitting CTRL-C
774 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 */
776 prev_got_int = got_int;
777 got_int = FALSE;
778 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000779 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000781 if (fp != NULL)
782 *fp = bp->dbg_forceit;
783 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 got_int |= prev_got_int;
785 }
786 }
787 if (name != fname)
788 vim_free(name);
789
790 return lnum;
791}
792
793/*
794 * Called when a breakpoint was encountered.
795 */
796 void
797dbg_breakpoint(name, lnum)
798 char_u *name;
799 linenr_T lnum;
800{
801 /* We need to check if this line is actually executed in do_one_cmd() */
802 debug_breakpoint_name = name;
803 debug_breakpoint_lnum = lnum;
804}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000805
806
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000807# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000808/*
809 * Store the current time in "tm".
810 */
811 void
812profile_start(tm)
813 proftime_T *tm;
814{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000815# ifdef WIN3264
816 QueryPerformanceCounter(tm);
817# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000818 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000819# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000820}
821
822/*
823 * Compute the elapsed time from "tm" till now and store in "tm".
824 */
825 void
826profile_end(tm)
827 proftime_T *tm;
828{
829 proftime_T now;
830
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000831# ifdef WIN3264
832 QueryPerformanceCounter(&now);
833 tm->QuadPart = now.QuadPart - tm->QuadPart;
834# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000835 gettimeofday(&now, NULL);
836 tm->tv_usec = now.tv_usec - tm->tv_usec;
837 tm->tv_sec = now.tv_sec - tm->tv_sec;
838 if (tm->tv_usec < 0)
839 {
840 tm->tv_usec += 1000000;
841 --tm->tv_sec;
842 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000843# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000844}
845
846/*
847 * Subtract the time "tm2" from "tm".
848 */
849 void
850profile_sub(tm, tm2)
851 proftime_T *tm, *tm2;
852{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000853# ifdef WIN3264
854 tm->QuadPart -= tm2->QuadPart;
855# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000856 tm->tv_usec -= tm2->tv_usec;
857 tm->tv_sec -= tm2->tv_sec;
858 if (tm->tv_usec < 0)
859 {
860 tm->tv_usec += 1000000;
861 --tm->tv_sec;
862 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000863# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000864}
865
866/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000867 * Return a string that represents the time in "tm".
868 * Uses a static buffer!
869 */
870 char *
871profile_msg(tm)
872 proftime_T *tm;
873{
874 static char buf[50];
875
876# ifdef WIN3264
877 LARGE_INTEGER fr;
878
879 QueryPerformanceFrequency(&fr);
880 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
881# else
882 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000883# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000884 return buf;
885}
886
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000887/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000888 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000889 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000890 void
891profile_setlimit(msec, tm)
892 long msec;
893 proftime_T *tm;
894{
895 if (msec <= 0) /* no limit */
896 profile_zero(tm);
897 else
898 {
899# ifdef WIN3264
900 LARGE_INTEGER fr;
901
902 QueryPerformanceCounter(tm);
903 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000904 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000905# else
906 long usec;
907
908 gettimeofday(tm, NULL);
909 usec = (long)tm->tv_usec + (long)msec * 1000;
910 tm->tv_usec = usec % 1000000L;
911 tm->tv_sec += usec / 1000000L;
912# endif
913 }
914}
915
916/*
917 * Return TRUE if the current time is past "tm".
918 */
919 int
920profile_passed_limit(tm)
921 proftime_T *tm;
922{
923 proftime_T now;
924
925# ifdef WIN3264
926 if (tm->QuadPart == 0) /* timer was not set */
927 return FALSE;
928 QueryPerformanceCounter(&now);
929 return (now.QuadPart > tm->QuadPart);
930# else
931 if (tm->tv_sec == 0) /* timer was not set */
932 return FALSE;
933 gettimeofday(&now, NULL);
934 return (now.tv_sec > tm->tv_sec
935 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
936# endif
937}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000938
939/*
940 * Set the time in "tm" to zero.
941 */
942 void
943profile_zero(tm)
944 proftime_T *tm;
945{
946# ifdef WIN3264
947 tm->QuadPart = 0;
948# else
949 tm->tv_usec = 0;
950 tm->tv_sec = 0;
951# endif
952}
953
Bram Moolenaar76929292008-01-06 19:07:36 +0000954# endif /* FEAT_PROFILE || FEAT_RELTIME */
955
956# if defined(FEAT_PROFILE) || defined(PROTO)
957/*
958 * Functions for profiling.
959 */
960static void script_do_profile __ARGS((scriptitem_T *si));
961static void script_dump_profile __ARGS((FILE *fd));
962static proftime_T prof_wait_time;
963
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000964/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000965 * Add the time "tm2" to "tm".
966 */
967 void
968profile_add(tm, tm2)
969 proftime_T *tm, *tm2;
970{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000971# ifdef WIN3264
972 tm->QuadPart += tm2->QuadPart;
973# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000974 tm->tv_usec += tm2->tv_usec;
975 tm->tv_sec += tm2->tv_sec;
976 if (tm->tv_usec >= 1000000)
977 {
978 tm->tv_usec -= 1000000;
979 ++tm->tv_sec;
980 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000981# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000982}
983
984/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000985 * Add the "self" time from the total time and the children's time.
986 */
987 void
988profile_self(self, total, children)
989 proftime_T *self, *total, *children;
990{
991 /* Check that the result won't be negative. Can happen with recursive
992 * calls. */
993#ifdef WIN3264
994 if (total->QuadPart <= children->QuadPart)
995 return;
996#else
997 if (total->tv_sec < children->tv_sec
998 || (total->tv_sec == children->tv_sec
999 && total->tv_usec <= children->tv_usec))
1000 return;
1001#endif
1002 profile_add(self, total);
1003 profile_sub(self, children);
1004}
1005
1006/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001007 * Get the current waittime.
1008 */
1009 void
1010profile_get_wait(tm)
1011 proftime_T *tm;
1012{
1013 *tm = prof_wait_time;
1014}
1015
1016/*
1017 * Subtract the passed waittime since "tm" from "tma".
1018 */
1019 void
1020profile_sub_wait(tm, tma)
1021 proftime_T *tm, *tma;
1022{
1023 proftime_T tm3 = prof_wait_time;
1024
1025 profile_sub(&tm3, tm);
1026 profile_sub(tma, &tm3);
1027}
1028
1029/*
1030 * Return TRUE if "tm1" and "tm2" are equal.
1031 */
1032 int
1033profile_equal(tm1, tm2)
1034 proftime_T *tm1, *tm2;
1035{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001036# ifdef WIN3264
1037 return (tm1->QuadPart == tm2->QuadPart);
1038# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001039 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001040# endif
1041}
1042
1043/*
1044 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1045 */
1046 int
1047profile_cmp(tm1, tm2)
1048 proftime_T *tm1, *tm2;
1049{
1050# ifdef WIN3264
1051 return (int)(tm2->QuadPart - tm1->QuadPart);
1052# else
1053 if (tm1->tv_sec == tm2->tv_sec)
1054 return tm2->tv_usec - tm1->tv_usec;
1055 return tm2->tv_sec - tm1->tv_sec;
1056# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001057}
1058
Bram Moolenaar05159a02005-02-26 23:04:13 +00001059static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001060static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001061
1062/*
1063 * ":profile cmd args"
1064 */
1065 void
1066ex_profile(eap)
1067 exarg_T *eap;
1068{
1069 char_u *e;
1070 int len;
1071
1072 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001073 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001074 e = skipwhite(e);
1075
1076 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1077 {
1078 vim_free(profile_fname);
1079 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001080 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001081 profile_zero(&prof_wait_time);
1082 set_vim_var_nr(VV_PROFILING, 1L);
1083 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001084 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001085 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001086 else if (STRCMP(eap->arg, "pause") == 0)
1087 {
1088 if (do_profiling == PROF_YES)
1089 profile_start(&pause_time);
1090 do_profiling = PROF_PAUSED;
1091 }
1092 else if (STRCMP(eap->arg, "continue") == 0)
1093 {
1094 if (do_profiling == PROF_PAUSED)
1095 {
1096 profile_end(&pause_time);
1097 profile_add(&prof_wait_time, &pause_time);
1098 }
1099 do_profiling = PROF_YES;
1100 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001101 else
1102 {
1103 /* The rest is similar to ":breakadd". */
1104 ex_breakadd(eap);
1105 }
1106}
1107
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001108/* Command line expansion for :profile. */
1109static enum
1110{
1111 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001112 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001113} pexpand_what;
1114
1115static char *pexpand_cmds[] = {
1116 "start",
1117#define PROFCMD_START 0
1118 "pause",
1119#define PROFCMD_PAUSE 1
1120 "continue",
1121#define PROFCMD_CONTINUE 2
1122 "func",
1123#define PROFCMD_FUNC 3
1124 "file",
1125#define PROFCMD_FILE 4
1126 NULL
1127#define PROFCMD_LAST 5
1128};
1129
1130/*
1131 * Function given to ExpandGeneric() to obtain the profile command
1132 * specific expansion.
1133 */
1134 char_u *
1135get_profile_name(xp, idx)
1136 expand_T *xp UNUSED;
1137 int idx;
1138{
1139 switch (pexpand_what)
1140 {
1141 case PEXP_SUBCMD:
1142 return (char_u *)pexpand_cmds[idx];
1143 /* case PEXP_FUNC: TODO */
1144 default:
1145 return NULL;
1146 }
1147}
1148
1149/*
1150 * Handle command line completion for :profile command.
1151 */
1152 void
1153set_context_in_profile_cmd(xp, arg)
1154 expand_T *xp;
1155 char_u *arg;
1156{
1157 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001158
1159 /* Default: expand subcommands. */
1160 xp->xp_context = EXPAND_PROFILE;
1161 pexpand_what = PEXP_SUBCMD;
1162 xp->xp_pattern = arg;
1163
1164 end_subcmd = skiptowhite(arg);
1165 if (*end_subcmd == NUL)
1166 return;
1167
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001168 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001169 {
1170 xp->xp_context = EXPAND_FILES;
1171 xp->xp_pattern = skipwhite(end_subcmd);
1172 return;
1173 }
1174
1175 /* TODO: expand function names after "func" */
1176 xp->xp_context = EXPAND_NOTHING;
1177}
1178
Bram Moolenaar05159a02005-02-26 23:04:13 +00001179/*
1180 * Dump the profiling info.
1181 */
1182 void
1183profile_dump()
1184{
1185 FILE *fd;
1186
1187 if (profile_fname != NULL)
1188 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001189 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001190 if (fd == NULL)
1191 EMSG2(_(e_notopen), profile_fname);
1192 else
1193 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001194 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001195 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001196 fclose(fd);
1197 }
1198 }
1199}
1200
1201/*
1202 * Start profiling script "fp".
1203 */
1204 static void
1205script_do_profile(si)
1206 scriptitem_T *si;
1207{
1208 si->sn_pr_count = 0;
1209 profile_zero(&si->sn_pr_total);
1210 profile_zero(&si->sn_pr_self);
1211
1212 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1213 si->sn_prl_idx = -1;
1214 si->sn_prof_on = TRUE;
1215 si->sn_pr_nest = 0;
1216}
1217
1218/*
1219 * save time when starting to invoke another script or function.
1220 */
1221 void
1222script_prof_save(tm)
1223 proftime_T *tm; /* place to store wait time */
1224{
1225 scriptitem_T *si;
1226
1227 if (current_SID > 0 && current_SID <= script_items.ga_len)
1228 {
1229 si = &SCRIPT_ITEM(current_SID);
1230 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1231 profile_start(&si->sn_pr_child);
1232 }
1233 profile_get_wait(tm);
1234}
1235
1236/*
1237 * Count time spent in children after invoking another script or function.
1238 */
1239 void
1240script_prof_restore(tm)
1241 proftime_T *tm;
1242{
1243 scriptitem_T *si;
1244
1245 if (current_SID > 0 && current_SID <= script_items.ga_len)
1246 {
1247 si = &SCRIPT_ITEM(current_SID);
1248 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1249 {
1250 profile_end(&si->sn_pr_child);
1251 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1252 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1253 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1254 }
1255 }
1256}
1257
1258static proftime_T inchar_time;
1259
1260/*
1261 * Called when starting to wait for the user to type a character.
1262 */
1263 void
1264prof_inchar_enter()
1265{
1266 profile_start(&inchar_time);
1267}
1268
1269/*
1270 * Called when finished waiting for the user to type a character.
1271 */
1272 void
1273prof_inchar_exit()
1274{
1275 profile_end(&inchar_time);
1276 profile_add(&prof_wait_time, &inchar_time);
1277}
1278
1279/*
1280 * Dump the profiling results for all scripts in file "fd".
1281 */
1282 static void
1283script_dump_profile(fd)
1284 FILE *fd;
1285{
1286 int id;
1287 scriptitem_T *si;
1288 int i;
1289 FILE *sfd;
1290 sn_prl_T *pp;
1291
1292 for (id = 1; id <= script_items.ga_len; ++id)
1293 {
1294 si = &SCRIPT_ITEM(id);
1295 if (si->sn_prof_on)
1296 {
1297 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1298 if (si->sn_pr_count == 1)
1299 fprintf(fd, "Sourced 1 time\n");
1300 else
1301 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1302 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1303 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1304 fprintf(fd, "\n");
1305 fprintf(fd, "count total (s) self (s)\n");
1306
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001307 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001308 if (sfd == NULL)
1309 fprintf(fd, "Cannot open file!\n");
1310 else
1311 {
1312 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1313 {
1314 if (vim_fgets(IObuff, IOSIZE, sfd))
1315 break;
1316 pp = &PRL_ITEM(si, i);
1317 if (pp->snp_count > 0)
1318 {
1319 fprintf(fd, "%5d ", pp->snp_count);
1320 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1321 fprintf(fd, " ");
1322 else
1323 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1324 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1325 }
1326 else
1327 fprintf(fd, " ");
1328 fprintf(fd, "%s", IObuff);
1329 }
1330 fclose(sfd);
1331 }
1332 fprintf(fd, "\n");
1333 }
1334 }
1335}
1336
1337/*
1338 * Return TRUE when a function defined in the current script should be
1339 * profiled.
1340 */
1341 int
1342prof_def_func()
1343{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001344 if (current_SID > 0)
1345 return SCRIPT_ITEM(current_SID).sn_pr_force;
1346 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001347}
1348
1349# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001350#endif
1351
1352/*
1353 * If 'autowrite' option set, try to write the file.
1354 * Careful: autocommands may make "buf" invalid!
1355 *
1356 * return FAIL for failure, OK otherwise
1357 */
1358 int
1359autowrite(buf, forceit)
1360 buf_T *buf;
1361 int forceit;
1362{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001363 int r;
1364
Bram Moolenaar071d4272004-06-13 20:20:40 +00001365 if (!(p_aw || p_awa) || !p_write
1366#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001367 /* never autowrite a "nofile" or "nowrite" buffer */
1368 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001369#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001370 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001371 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001372 r = buf_write_all(buf, forceit);
1373
1374 /* Writing may succeed but the buffer still changed, e.g., when there is a
1375 * conversion error. We do want to return FAIL then. */
1376 if (buf_valid(buf) && bufIsChanged(buf))
1377 r = FAIL;
1378 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001379}
1380
1381/*
1382 * flush all buffers, except the ones that are readonly
1383 */
1384 void
1385autowrite_all()
1386{
1387 buf_T *buf;
1388
1389 if (!(p_aw || p_awa) || !p_write)
1390 return;
1391 for (buf = firstbuf; buf; buf = buf->b_next)
1392 if (bufIsChanged(buf) && !buf->b_p_ro)
1393 {
1394 (void)buf_write_all(buf, FALSE);
1395#ifdef FEAT_AUTOCMD
1396 /* an autocommand may have deleted the buffer */
1397 if (!buf_valid(buf))
1398 buf = firstbuf;
1399#endif
1400 }
1401}
1402
1403/*
1404 * return TRUE if buffer was changed and cannot be abandoned.
1405 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001406 int
1407check_changed(buf, checkaw, mult_win, forceit, allbuf)
1408 buf_T *buf;
1409 int checkaw; /* do autowrite if buffer was changed */
1410 int mult_win; /* check also when several wins for the buf */
1411 int forceit;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001412 int allbuf UNUSED; /* may write all buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001413{
1414 if ( !forceit
1415 && bufIsChanged(buf)
1416 && (mult_win || buf->b_nwindows <= 1)
1417 && (!checkaw || autowrite(buf, forceit) == FAIL))
1418 {
1419#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1420 if ((p_confirm || cmdmod.confirm) && p_write)
1421 {
1422 buf_T *buf2;
1423 int count = 0;
1424
1425 if (allbuf)
1426 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1427 if (bufIsChanged(buf2)
1428 && (buf2->b_ffname != NULL
1429# ifdef FEAT_BROWSE
1430 || cmdmod.browse
1431# endif
1432 ))
1433 ++count;
1434# ifdef FEAT_AUTOCMD
1435 if (!buf_valid(buf))
1436 /* Autocommand deleted buffer, oops! It's not changed now. */
1437 return FALSE;
1438# endif
1439 dialog_changed(buf, count > 1);
1440# ifdef FEAT_AUTOCMD
1441 if (!buf_valid(buf))
1442 /* Autocommand deleted buffer, oops! It's not changed now. */
1443 return FALSE;
1444# endif
1445 return bufIsChanged(buf);
1446 }
1447#endif
1448 EMSG(_(e_nowrtmsg));
1449 return TRUE;
1450 }
1451 return FALSE;
1452}
1453
1454#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1455
1456#if defined(FEAT_BROWSE) || defined(PROTO)
1457/*
1458 * When wanting to write a file without a file name, ask the user for a name.
1459 */
1460 void
1461browse_save_fname(buf)
1462 buf_T *buf;
1463{
1464 if (buf->b_fname == NULL)
1465 {
1466 char_u *fname;
1467
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001468 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1469 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001470 if (fname != NULL)
1471 {
1472 if (setfname(buf, fname, NULL, TRUE) == OK)
1473 buf->b_flags |= BF_NOTEDITED;
1474 vim_free(fname);
1475 }
1476 }
1477}
1478#endif
1479
1480/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001481 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001482 * Must check 'write' option first!
1483 */
1484 void
1485dialog_changed(buf, checkall)
1486 buf_T *buf;
1487 int checkall; /* may abandon all changed buffers */
1488{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001489 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001490 int ret;
1491 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001492 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001493
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001494 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001495 (buf->b_fname != NULL) ?
1496 buf->b_fname : (char_u *)_("Untitled"));
1497 if (checkall)
1498 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1499 else
1500 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1501
Bram Moolenaar8218f602012-04-25 17:32:18 +02001502 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1503 * function. */
1504 ea.append = ea.forceit = FALSE;
1505
Bram Moolenaar071d4272004-06-13 20:20:40 +00001506 if (ret == VIM_YES)
1507 {
1508#ifdef FEAT_BROWSE
1509 /* May get file name, when there is none */
1510 browse_save_fname(buf);
1511#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001512 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1513 buf->b_fname, buf->b_ffname, FALSE) == OK)
1514 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001515 (void)buf_write_all(buf, FALSE);
1516 }
1517 else if (ret == VIM_NO)
1518 {
1519 unchanged(buf, TRUE);
1520 }
1521 else if (ret == VIM_ALL)
1522 {
1523 /*
1524 * Write all modified files that can be written.
1525 * Skip readonly buffers, these need to be confirmed
1526 * individually.
1527 */
1528 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1529 {
1530 if (bufIsChanged(buf2)
1531 && (buf2->b_ffname != NULL
1532#ifdef FEAT_BROWSE
1533 || cmdmod.browse
1534#endif
1535 )
1536 && !buf2->b_p_ro)
1537 {
1538#ifdef FEAT_BROWSE
1539 /* May get file name, when there is none */
1540 browse_save_fname(buf2);
1541#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001542 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1543 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1544 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001545 (void)buf_write_all(buf2, FALSE);
1546#ifdef FEAT_AUTOCMD
1547 /* an autocommand may have deleted the buffer */
1548 if (!buf_valid(buf2))
1549 buf2 = firstbuf;
1550#endif
1551 }
1552 }
1553 }
1554 else if (ret == VIM_DISCARDALL)
1555 {
1556 /*
1557 * mark all buffers as unchanged
1558 */
1559 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1560 unchanged(buf2, TRUE);
1561 }
1562}
1563#endif
1564
1565/*
1566 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1567 * hidden, autowriting it or unloading it.
1568 */
1569 int
1570can_abandon(buf, forceit)
1571 buf_T *buf;
1572 int forceit;
1573{
1574 return ( P_HID(buf)
1575 || !bufIsChanged(buf)
1576 || buf->b_nwindows > 1
1577 || autowrite(buf, forceit) == OK
1578 || forceit);
1579}
1580
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001581static void add_bufnum __ARGS((int *bufnrs, int *bufnump, int nr));
1582
1583/*
1584 * Add a buffer number to "bufnrs", unless it's already there.
1585 */
1586 static void
1587add_bufnum(bufnrs, bufnump, nr)
1588 int *bufnrs;
1589 int *bufnump;
1590 int nr;
1591{
1592 int i;
1593
1594 for (i = 0; i < *bufnump; ++i)
1595 if (bufnrs[i] == nr)
1596 return;
1597 bufnrs[*bufnump] = nr;
1598 *bufnump = *bufnump + 1;
1599}
1600
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601/*
1602 * Return TRUE if any buffer was changed and cannot be abandoned.
1603 * That changed buffer becomes the current buffer.
1604 */
1605 int
1606check_changed_any(hidden)
1607 int hidden; /* Only check hidden buffers */
1608{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001609 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001610 buf_T *buf;
1611 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001612 int i;
1613 int bufnum = 0;
1614 int bufcount = 0;
1615 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001617 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001618 win_T *wp;
1619#endif
1620
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001621 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1622 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001623
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001624 if (bufcount == 0)
1625 return FALSE;
1626
1627 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1628 if (bufnrs == NULL)
1629 return FALSE;
1630
1631 /* curbuf */
1632 bufnrs[bufnum++] = curbuf->b_fnum;
1633#ifdef FEAT_WINDOWS
1634 /* buf in curtab */
1635 FOR_ALL_WINDOWS(wp)
1636 if (wp->w_buffer != curbuf)
1637 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1638
1639 /* buf in other tab */
1640 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1641 if (tp != curtab)
1642 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1643 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1644#endif
1645 /* any other buf */
1646 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1647 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1648
1649 for (i = 0; i < bufnum; ++i)
1650 {
1651 buf = buflist_findnr(bufnrs[i]);
1652 if (buf == NULL)
1653 continue;
1654 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1655 {
1656 /* Try auto-writing the buffer. If this fails but the buffer no
1657 * longer exists it's not changed, that's OK. */
1658 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1659 break; /* didn't save - still changes */
1660 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661 }
1662
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001663 if (i >= bufnum)
1664 goto theend;
1665
1666 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667 exiting = FALSE;
1668#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1669 /*
1670 * When ":confirm" used, don't give an error message.
1671 */
1672 if (!(p_confirm || cmdmod.confirm))
1673#endif
1674 {
1675 /* There must be a wait_return for this message, do_buffer()
1676 * may cause a redraw. But wait_return() is a no-op when vgetc()
1677 * is busy (Quit used from window menu), then make sure we don't
1678 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001679 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001680 {
1681 msg_row = cmdline_row;
1682 msg_col = 0;
1683 msg_didout = FALSE;
1684 }
1685 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1686 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1687 buf->b_fname))
1688 {
1689 save = no_wait_return;
1690 no_wait_return = FALSE;
1691 wait_return(FALSE);
1692 no_wait_return = save;
1693 }
1694 }
1695
1696#ifdef FEAT_WINDOWS
1697 /* Try to find a window that contains the buffer. */
1698 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001699 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001700 if (wp->w_buffer == buf)
1701 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001702 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703# ifdef FEAT_AUTOCMD
1704 /* Paranoia: did autocms wipe out the buffer with changes? */
1705 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001706 {
1707 goto theend;
1708 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001709# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001710 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001712buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001713#endif
1714
1715 /* Open the changed buffer in the current window. */
1716 if (buf != curbuf)
1717 set_curbuf(buf, DOBUF_GOTO);
1718
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001719theend:
1720 vim_free(bufnrs);
1721 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722}
1723
1724/*
1725 * return FAIL if there is no file name, OK if there is one
1726 * give error message for FAIL
1727 */
1728 int
1729check_fname()
1730{
1731 if (curbuf->b_ffname == NULL)
1732 {
1733 EMSG(_(e_noname));
1734 return FAIL;
1735 }
1736 return OK;
1737}
1738
1739/*
1740 * flush the contents of a buffer, unless it has no file name
1741 *
1742 * return FAIL for failure, OK otherwise
1743 */
1744 int
1745buf_write_all(buf, forceit)
1746 buf_T *buf;
1747 int forceit;
1748{
1749 int retval;
1750#ifdef FEAT_AUTOCMD
1751 buf_T *old_curbuf = curbuf;
1752#endif
1753
1754 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1755 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1756 FALSE, forceit, TRUE, FALSE));
1757#ifdef FEAT_AUTOCMD
1758 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001759 {
1760 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001762 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763#endif
1764 return retval;
1765}
1766
1767/*
1768 * Code to handle the argument list.
1769 */
1770
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001771static char_u *do_one_arg __ARGS((char_u *str));
1772static int do_arglist __ARGS((char_u *str, int what, int after));
1773static void alist_check_arg_idx __ARGS((void));
1774static int editing_arg_idx __ARGS((win_T *win));
1775#ifdef FEAT_LISTCMDS
1776static int alist_add_list __ARGS((int count, char_u **files, int after));
1777#endif
1778#define AL_SET 1
1779#define AL_ADD 2
1780#define AL_DEL 3
1781
Bram Moolenaar071d4272004-06-13 20:20:40 +00001782/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001783 * Isolate one argument, taking backticks.
1784 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001785 * Return a pointer to the start of the next argument.
1786 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001787 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788do_one_arg(str)
1789 char_u *str;
1790{
1791 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792 int inbacktick;
1793
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 inbacktick = FALSE;
1795 for (p = str; *str; ++str)
1796 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001797 /* When the backslash is used for escaping the special meaning of a
1798 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001799 if (rem_backslash(str))
1800 {
1801 *p++ = *str++;
1802 *p++ = *str;
1803 }
1804 else
1805 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001806 /* An item ends at a space not in backticks */
1807 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001809 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001811 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812 }
1813 }
1814 str = skipwhite(str);
1815 *p = NUL;
1816
1817 return str;
1818}
1819
Bram Moolenaar86b68352004-12-27 21:59:20 +00001820/*
1821 * Separate the arguments in "str" and return a list of pointers in the
1822 * growarray "gap".
1823 */
1824 int
1825get_arglist(gap, str)
1826 garray_T *gap;
1827 char_u *str;
1828{
1829 ga_init2(gap, (int)sizeof(char_u *), 20);
1830 while (*str != NUL)
1831 {
1832 if (ga_grow(gap, 1) == FAIL)
1833 {
1834 ga_clear(gap);
1835 return FAIL;
1836 }
1837 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1838
1839 /* Isolate one argument, change it in-place, put a NUL after it. */
1840 str = do_one_arg(str);
1841 }
1842 return OK;
1843}
1844
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001845#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001846/*
1847 * Parse a list of arguments (file names), expand them and return in
1848 * "fnames[fcountp]".
1849 * Return FAIL or OK.
1850 */
1851 int
1852get_arglist_exp(str, fcountp, fnamesp)
1853 char_u *str;
1854 int *fcountp;
1855 char_u ***fnamesp;
1856{
1857 garray_T ga;
1858 int i;
1859
1860 if (get_arglist(&ga, str) == FAIL)
1861 return FAIL;
1862 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1863 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1864 ga_clear(&ga);
1865 return i;
1866}
1867#endif
1868
Bram Moolenaar071d4272004-06-13 20:20:40 +00001869#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1870/*
1871 * Redefine the argument list.
1872 */
1873 void
1874set_arglist(str)
1875 char_u *str;
1876{
1877 do_arglist(str, AL_SET, 0);
1878}
1879#endif
1880
1881/*
1882 * "what" == AL_SET: Redefine the argument list to 'str'.
1883 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1884 * "what" == AL_DEL: remove files in 'str' from the argument list.
1885 *
1886 * Return FAIL for failure, OK otherwise.
1887 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001888 static int
1889do_arglist(str, what, after)
1890 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001891 int what UNUSED;
1892 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893{
1894 garray_T new_ga;
1895 int exp_count;
1896 char_u **exp_files;
1897 int i;
1898#ifdef FEAT_LISTCMDS
1899 char_u *p;
1900 int match;
1901#endif
1902
1903 /*
1904 * Collect all file name arguments in "new_ga".
1905 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001906 if (get_arglist(&new_ga, str) == FAIL)
1907 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908
1909#ifdef FEAT_LISTCMDS
1910 if (what == AL_DEL)
1911 {
1912 regmatch_T regmatch;
1913 int didone;
1914
1915 /*
1916 * Delete the items: use each item as a regexp and find a match in the
1917 * argument list.
1918 */
1919#ifdef CASE_INSENSITIVE_FILENAME
1920 regmatch.rm_ic = TRUE; /* Always ignore case */
1921#else
1922 regmatch.rm_ic = FALSE; /* Never ignore case */
1923#endif
1924 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1925 {
1926 p = ((char_u **)new_ga.ga_data)[i];
1927 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1928 if (p == NULL)
1929 break;
1930 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1931 if (regmatch.regprog == NULL)
1932 {
1933 vim_free(p);
1934 break;
1935 }
1936
1937 didone = FALSE;
1938 for (match = 0; match < ARGCOUNT; ++match)
1939 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1940 (colnr_T)0))
1941 {
1942 didone = TRUE;
1943 vim_free(ARGLIST[match].ae_fname);
1944 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1945 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1946 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001947 if (curwin->w_arg_idx > match)
1948 --curwin->w_arg_idx;
1949 --match;
1950 }
1951
1952 vim_free(regmatch.regprog);
1953 vim_free(p);
1954 if (!didone)
1955 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1956 }
1957 ga_clear(&new_ga);
1958 }
1959 else
1960#endif
1961 {
1962 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1963 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1964 ga_clear(&new_ga);
1965 if (i == FAIL)
1966 return FAIL;
1967 if (exp_count == 0)
1968 {
1969 EMSG(_(e_nomatch));
1970 return FAIL;
1971 }
1972
1973#ifdef FEAT_LISTCMDS
1974 if (what == AL_ADD)
1975 {
1976 (void)alist_add_list(exp_count, exp_files, after);
1977 vim_free(exp_files);
1978 }
1979 else /* what == AL_SET */
1980#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001981 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001982 }
1983
1984 alist_check_arg_idx();
1985
1986 return OK;
1987}
1988
1989/*
1990 * Check the validity of the arg_idx for each other window.
1991 */
1992 static void
1993alist_check_arg_idx()
1994{
1995#ifdef FEAT_WINDOWS
1996 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001997 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001998
Bram Moolenaarf740b292006-02-16 22:11:02 +00001999 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002000 if (win->w_alist == curwin->w_alist)
2001 check_arg_idx(win);
2002#else
2003 check_arg_idx(curwin);
2004#endif
2005}
2006
2007/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002008 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002009 * index.
2010 */
2011 static int
2012editing_arg_idx(win)
2013 win_T *win;
2014{
2015 return !(win->w_arg_idx >= WARGCOUNT(win)
2016 || (win->w_buffer->b_fnum
2017 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2018 && (win->w_buffer->b_ffname == NULL
2019 || !(fullpathcmp(
2020 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2021 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2022}
2023
2024/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025 * Check if window "win" is editing the w_arg_idx file in its argument list.
2026 */
2027 void
2028check_arg_idx(win)
2029 win_T *win;
2030{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002031 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002032 {
2033 /* We are not editing the current entry in the argument list.
2034 * Set "arg_had_last" if we are editing the last one. */
2035 win->w_arg_idx_invalid = TRUE;
2036 if (win->w_arg_idx != WARGCOUNT(win) - 1
2037 && arg_had_last == FALSE
2038#ifdef FEAT_WINDOWS
2039 && ALIST(win) == &global_alist
2040#endif
2041 && GARGCOUNT > 0
2042 && win->w_arg_idx < GARGCOUNT
2043 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2044 || (win->w_buffer->b_ffname != NULL
2045 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2046 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2047 arg_had_last = TRUE;
2048 }
2049 else
2050 {
2051 /* We are editing the current entry in the argument list.
2052 * Set "arg_had_last" if it's also the last one */
2053 win->w_arg_idx_invalid = FALSE;
2054 if (win->w_arg_idx == WARGCOUNT(win) - 1
2055#ifdef FEAT_WINDOWS
2056 && win->w_alist == &global_alist
2057#endif
2058 )
2059 arg_had_last = TRUE;
2060 }
2061}
2062
2063/*
2064 * ":args", ":argslocal" and ":argsglobal".
2065 */
2066 void
2067ex_args(eap)
2068 exarg_T *eap;
2069{
2070 int i;
2071
2072 if (eap->cmdidx != CMD_args)
2073 {
2074#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2075 alist_unlink(ALIST(curwin));
2076 if (eap->cmdidx == CMD_argglobal)
2077 ALIST(curwin) = &global_alist;
2078 else /* eap->cmdidx == CMD_arglocal */
2079 alist_new();
2080#else
2081 ex_ni(eap);
2082 return;
2083#endif
2084 }
2085
2086 if (!ends_excmd(*eap->arg))
2087 {
2088 /*
2089 * ":args file ..": define new argument list, handle like ":next"
2090 * Also for ":argslocal file .." and ":argsglobal file ..".
2091 */
2092 ex_next(eap);
2093 }
2094 else
2095#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2096 if (eap->cmdidx == CMD_args)
2097#endif
2098 {
2099 /*
2100 * ":args": list arguments.
2101 */
2102 if (ARGCOUNT > 0)
2103 {
2104 /* Overwrite the command, for a short list there is no scrolling
2105 * required and no wait_return(). */
2106 gotocmdline(TRUE);
2107 for (i = 0; i < ARGCOUNT; ++i)
2108 {
2109 if (i == curwin->w_arg_idx)
2110 msg_putchar('[');
2111 msg_outtrans(alist_name(&ARGLIST[i]));
2112 if (i == curwin->w_arg_idx)
2113 msg_putchar(']');
2114 msg_putchar(' ');
2115 }
2116 }
2117 }
2118#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2119 else if (eap->cmdidx == CMD_arglocal)
2120 {
2121 garray_T *gap = &curwin->w_alist->al_ga;
2122
2123 /*
2124 * ":argslocal": make a local copy of the global argument list.
2125 */
2126 if (ga_grow(gap, GARGCOUNT) == OK)
2127 for (i = 0; i < GARGCOUNT; ++i)
2128 if (GARGLIST[i].ae_fname != NULL)
2129 {
2130 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2131 vim_strsave(GARGLIST[i].ae_fname);
2132 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2133 GARGLIST[i].ae_fnum;
2134 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002135 }
2136 }
2137#endif
2138}
2139
2140/*
2141 * ":previous", ":sprevious", ":Next" and ":sNext".
2142 */
2143 void
2144ex_previous(eap)
2145 exarg_T *eap;
2146{
2147 /* If past the last one already, go to the last one. */
2148 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2149 do_argfile(eap, ARGCOUNT - 1);
2150 else
2151 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2152}
2153
2154/*
2155 * ":rewind", ":first", ":sfirst" and ":srewind".
2156 */
2157 void
2158ex_rewind(eap)
2159 exarg_T *eap;
2160{
2161 do_argfile(eap, 0);
2162}
2163
2164/*
2165 * ":last" and ":slast".
2166 */
2167 void
2168ex_last(eap)
2169 exarg_T *eap;
2170{
2171 do_argfile(eap, ARGCOUNT - 1);
2172}
2173
2174/*
2175 * ":argument" and ":sargument".
2176 */
2177 void
2178ex_argument(eap)
2179 exarg_T *eap;
2180{
2181 int i;
2182
2183 if (eap->addr_count > 0)
2184 i = eap->line2 - 1;
2185 else
2186 i = curwin->w_arg_idx;
2187 do_argfile(eap, i);
2188}
2189
2190/*
2191 * Edit file "argn" of the argument lists.
2192 */
2193 void
2194do_argfile(eap, argn)
2195 exarg_T *eap;
2196 int argn;
2197{
2198 int other;
2199 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002200 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002201
2202 if (argn < 0 || argn >= ARGCOUNT)
2203 {
2204 if (ARGCOUNT <= 1)
2205 EMSG(_("E163: There is only one file to edit"));
2206 else if (argn < 0)
2207 EMSG(_("E164: Cannot go before first file"));
2208 else
2209 EMSG(_("E165: Cannot go beyond last file"));
2210 }
2211 else
2212 {
2213 setpcmark();
2214#ifdef FEAT_GUI
2215 need_mouse_correct = TRUE;
2216#endif
2217
2218#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002219 /* split window or create new tab page first */
2220 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221 {
2222 if (win_split(0, 0) == FAIL)
2223 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002224 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225 }
2226 else
2227#endif
2228 {
2229 /*
2230 * if 'hidden' set, only check for changed file when re-editing
2231 * the same buffer
2232 */
2233 other = TRUE;
2234 if (P_HID(curbuf))
2235 {
2236 p = fix_fname(alist_name(&ARGLIST[argn]));
2237 other = otherfile(p);
2238 vim_free(p);
2239 }
2240 if ((!P_HID(curbuf) || !other)
2241 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2242 return;
2243 }
2244
2245 curwin->w_arg_idx = argn;
2246 if (argn == ARGCOUNT - 1
2247#ifdef FEAT_WINDOWS
2248 && curwin->w_alist == &global_alist
2249#endif
2250 )
2251 arg_had_last = TRUE;
2252
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002253 /* Edit the file; always use the last known line number.
2254 * When it fails (e.g. Abort for already edited file) restore the
2255 * argument index. */
2256 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002258 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2259 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002260 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002262 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002263 setmark('\'');
2264 }
2265}
2266
2267/*
2268 * ":next", and commands that behave like it.
2269 */
2270 void
2271ex_next(eap)
2272 exarg_T *eap;
2273{
2274 int i;
2275
2276 /*
2277 * check for changed buffer now, if this fails the argument list is not
2278 * redefined.
2279 */
2280 if ( P_HID(curbuf)
2281 || eap->cmdidx == CMD_snext
2282 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2283 {
2284 if (*eap->arg != NUL) /* redefine file list */
2285 {
2286 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2287 return;
2288 i = 0;
2289 }
2290 else
2291 i = curwin->w_arg_idx + (int)eap->line2;
2292 do_argfile(eap, i);
2293 }
2294}
2295
2296#ifdef FEAT_LISTCMDS
2297/*
2298 * ":argedit"
2299 */
2300 void
2301ex_argedit(eap)
2302 exarg_T *eap;
2303{
2304 int fnum;
2305 int i;
2306 char_u *s;
2307
2308 /* Add the argument to the buffer list and get the buffer number. */
2309 fnum = buflist_add(eap->arg, BLN_LISTED);
2310
2311 /* Check if this argument is already in the argument list. */
2312 for (i = 0; i < ARGCOUNT; ++i)
2313 if (ARGLIST[i].ae_fnum == fnum)
2314 break;
2315 if (i == ARGCOUNT)
2316 {
2317 /* Can't find it, add it to the argument list. */
2318 s = vim_strsave(eap->arg);
2319 if (s == NULL)
2320 return;
2321 i = alist_add_list(1, &s,
2322 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2323 if (i < 0)
2324 return;
2325 curwin->w_arg_idx = i;
2326 }
2327
2328 alist_check_arg_idx();
2329
2330 /* Edit the argument. */
2331 do_argfile(eap, i);
2332}
2333
2334/*
2335 * ":argadd"
2336 */
2337 void
2338ex_argadd(eap)
2339 exarg_T *eap;
2340{
2341 do_arglist(eap->arg, AL_ADD,
2342 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2343#ifdef FEAT_TITLE
2344 maketitle();
2345#endif
2346}
2347
2348/*
2349 * ":argdelete"
2350 */
2351 void
2352ex_argdelete(eap)
2353 exarg_T *eap;
2354{
2355 int i;
2356 int n;
2357
2358 if (eap->addr_count > 0)
2359 {
2360 /* ":1,4argdel": Delete all arguments in the range. */
2361 if (eap->line2 > ARGCOUNT)
2362 eap->line2 = ARGCOUNT;
2363 n = eap->line2 - eap->line1 + 1;
2364 if (*eap->arg != NUL || n <= 0)
2365 EMSG(_(e_invarg));
2366 else
2367 {
2368 for (i = eap->line1; i <= eap->line2; ++i)
2369 vim_free(ARGLIST[i - 1].ae_fname);
2370 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2371 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2372 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373 if (curwin->w_arg_idx >= eap->line2)
2374 curwin->w_arg_idx -= n;
2375 else if (curwin->w_arg_idx > eap->line1)
2376 curwin->w_arg_idx = eap->line1;
2377 }
2378 }
2379 else if (*eap->arg == NUL)
2380 EMSG(_(e_argreq));
2381 else
2382 do_arglist(eap->arg, AL_DEL, 0);
2383#ifdef FEAT_TITLE
2384 maketitle();
2385#endif
2386}
2387
2388/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002389 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 */
2391 void
2392ex_listdo(eap)
2393 exarg_T *eap;
2394{
2395 int i;
2396#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002397 win_T *wp;
2398 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399#endif
2400 buf_T *buf;
2401 int next_fnum = 0;
2402#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2403 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002405 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406
2407#ifndef FEAT_WINDOWS
2408 if (eap->cmdidx == CMD_windo)
2409 {
2410 ex_ni(eap);
2411 return;
2412 }
2413#endif
2414
2415#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002416 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002417 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2418 * great speed improvement. */
2419 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420#endif
2421
2422 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002423 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002424 || P_HID(curbuf)
2425 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2426 {
2427 /* start at the first argument/window/buffer */
2428 i = 0;
2429#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002430 wp = firstwin;
2431 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432#endif
2433 /* set pcmark now */
2434 if (eap->cmdidx == CMD_bufdo)
2435 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2436 else
2437 setpcmark();
2438 listcmd_busy = TRUE; /* avoids setting pcmark below */
2439
2440 while (!got_int)
2441 {
2442 if (eap->cmdidx == CMD_argdo)
2443 {
2444 /* go to argument "i" */
2445 if (i == ARGCOUNT)
2446 break;
2447 /* Don't call do_argfile() when already there, it will try
2448 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002449 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002450 {
2451 /* Clear 'shm' to avoid that the file message overwrites
2452 * any output from the command. */
2453 p_shm_save = vim_strsave(p_shm);
2454 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002455 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002456 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2457 vim_free(p_shm_save);
2458 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 if (curwin->w_arg_idx != i)
2460 break;
2461 ++i;
2462 }
2463#ifdef FEAT_WINDOWS
2464 else if (eap->cmdidx == CMD_windo)
2465 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002466 /* go to window "wp" */
2467 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002469 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002470 if (curwin != wp)
2471 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002472 wp = curwin->w_next;
2473 }
2474 else if (eap->cmdidx == CMD_tabdo)
2475 {
2476 /* go to window "tp" */
2477 if (!valid_tabpage(tp))
2478 break;
2479 goto_tabpage_tp(tp);
2480 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 }
2482#endif
2483 else if (eap->cmdidx == CMD_bufdo)
2484 {
2485 /* Remember the number of the next listed buffer, in case
2486 * ":bwipe" is used or autocommands do something strange. */
2487 next_fnum = -1;
2488 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2489 if (buf->b_p_bl)
2490 {
2491 next_fnum = buf->b_fnum;
2492 break;
2493 }
2494 }
2495
2496 /* execute the command */
2497 do_cmdline(eap->arg, eap->getline, eap->cookie,
2498 DOCMD_VERBOSE + DOCMD_NOWAIT);
2499
2500 if (eap->cmdidx == CMD_bufdo)
2501 {
2502 /* Done? */
2503 if (next_fnum < 0)
2504 break;
2505 /* Check if the buffer still exists. */
2506 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2507 if (buf->b_fnum == next_fnum)
2508 break;
2509 if (buf == NULL)
2510 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002511
2512 /* Go to the next buffer. Clear 'shm' to avoid that the file
2513 * message overwrites any output from the command. */
2514 p_shm_save = vim_strsave(p_shm);
2515 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002517 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2518 vim_free(p_shm_save);
2519
Bram Moolenaar071d4272004-06-13 20:20:40 +00002520 /* If autocommands took us elsewhere, quit here */
2521 if (curbuf->b_fnum != next_fnum)
2522 break;
2523 }
2524
2525 if (eap->cmdidx == CMD_windo)
2526 {
2527 validate_cursor(); /* cursor may have moved */
2528#ifdef FEAT_SCROLLBIND
2529 /* required when 'scrollbind' has been set */
2530 if (curwin->w_p_scb)
2531 do_check_scrollbind(TRUE);
2532#endif
2533 }
2534 }
2535 listcmd_busy = FALSE;
2536 }
2537
2538#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002539 if (save_ei != NULL)
2540 {
2541 au_event_restore(save_ei);
2542 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2543 curbuf->b_fname, TRUE, curbuf);
2544 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002545#endif
2546}
2547
2548/*
2549 * Add files[count] to the arglist of the current window after arg "after".
2550 * The file names in files[count] must have been allocated and are taken over.
2551 * Files[] itself is not taken over.
2552 * Returns index of first added argument. Returns -1 when failed (out of mem).
2553 */
2554 static int
2555alist_add_list(count, files, after)
2556 int count;
2557 char_u **files;
2558 int after; /* where to add: 0 = before first one */
2559{
2560 int i;
2561
2562 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2563 {
2564 if (after < 0)
2565 after = 0;
2566 if (after > ARGCOUNT)
2567 after = ARGCOUNT;
2568 if (after < ARGCOUNT)
2569 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2570 (ARGCOUNT - after) * sizeof(aentry_T));
2571 for (i = 0; i < count; ++i)
2572 {
2573 ARGLIST[after + i].ae_fname = files[i];
2574 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2575 }
2576 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577 if (curwin->w_arg_idx >= after)
2578 ++curwin->w_arg_idx;
2579 return after;
2580 }
2581
2582 for (i = 0; i < count; ++i)
2583 vim_free(files[i]);
2584 return -1;
2585}
2586
2587#endif /* FEAT_LISTCMDS */
2588
2589#ifdef FEAT_EVAL
2590/*
2591 * ":compiler[!] {name}"
2592 */
2593 void
2594ex_compiler(eap)
2595 exarg_T *eap;
2596{
2597 char_u *buf;
2598 char_u *old_cur_comp = NULL;
2599 char_u *p;
2600
2601 if (*eap->arg == NUL)
2602 {
2603 /* List all compiler scripts. */
2604 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2605 /* ) keep the indenter happy... */
2606 }
2607 else
2608 {
2609 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2610 if (buf != NULL)
2611 {
2612 if (eap->forceit)
2613 {
2614 /* ":compiler! {name}" sets global options */
2615 do_cmdline_cmd((char_u *)
2616 "command -nargs=* CompilerSet set <args>");
2617 }
2618 else
2619 {
2620 /* ":compiler! {name}" sets local options.
2621 * To remain backwards compatible "current_compiler" is always
2622 * used. A user's compiler plugin may set it, the distributed
2623 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002624 * "b:current_compiler" and restore "current_compiler".
2625 * Explicitly prepend "g:" to make it work in a function. */
2626 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627 if (old_cur_comp != NULL)
2628 old_cur_comp = vim_strsave(old_cur_comp);
2629 do_cmdline_cmd((char_u *)
2630 "command -nargs=* CompilerSet setlocal <args>");
2631 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002632 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002633 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002634
2635 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002636 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002637 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2638 vim_free(buf);
2639
2640 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2641
2642 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002643 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644 if (p != NULL)
2645 set_internal_string_var((char_u *)"b:current_compiler", p);
2646
2647 /* Restore "current_compiler" for ":compiler {name}". */
2648 if (!eap->forceit)
2649 {
2650 if (old_cur_comp != NULL)
2651 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002652 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653 old_cur_comp);
2654 vim_free(old_cur_comp);
2655 }
2656 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002657 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 }
2659 }
2660 }
2661}
2662#endif
2663
2664/*
2665 * ":runtime {name}"
2666 */
2667 void
2668ex_runtime(eap)
2669 exarg_T *eap;
2670{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002671 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002672}
2673
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002674static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675
2676 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002677source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002679 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002681 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682}
2683
2684/*
2685 * Source the file "name" from all directories in 'runtimepath'.
2686 * "name" can contain wildcards.
2687 * When "all" is TRUE, source all files, otherwise only the first one.
2688 * return FAIL when no file could be sourced, OK otherwise.
2689 */
2690 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002691source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692 char_u *name;
2693 int all;
2694{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002695 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696}
2697
2698/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002699 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2700 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002701 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2702 * used.
2703 * Returns OK when at least one match found, FAIL otherwise.
2704 */
2705 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002706do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707 char_u *name;
2708 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002709 void (*callback)__ARGS((char_u *fname, void *ck));
2710 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711{
2712 char_u *rtp;
2713 char_u *np;
2714 char_u *buf;
2715 char_u *rtp_copy;
2716 char_u *tail;
2717 int num_files;
2718 char_u **files;
2719 int i;
2720 int did_one = FALSE;
2721#ifdef AMIGA
2722 struct Process *proc = (struct Process *)FindTask(0L);
2723 APTR save_winptr = proc->pr_WindowPtr;
2724
2725 /* Avoid a requester here for a volume that doesn't exist. */
2726 proc->pr_WindowPtr = (APTR)-1L;
2727#endif
2728
2729 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2730 * value. */
2731 rtp_copy = vim_strsave(p_rtp);
2732 buf = alloc(MAXPATHL);
2733 if (buf != NULL && rtp_copy != NULL)
2734 {
2735 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002736 {
2737 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002738 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002740 verbose_leave();
2741 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002742
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743 /* Loop over all entries in 'runtimepath'. */
2744 rtp = rtp_copy;
2745 while (*rtp != NUL && (all || !did_one))
2746 {
2747 /* Copy the path from 'runtimepath' to buf[]. */
2748 copy_option_part(&rtp, buf, MAXPATHL, ",");
2749 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2750 {
2751 add_pathsep(buf);
2752 tail = buf + STRLEN(buf);
2753
2754 /* Loop over all patterns in "name" */
2755 np = name;
2756 while (*np != NUL && (all || !did_one))
2757 {
2758 /* Append the pattern from "name" to buf[]. */
2759 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2760 "\t ");
2761
2762 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002763 {
2764 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002765 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002766 verbose_leave();
2767 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002768
2769 /* Expand wildcards, invoke the callback for each match. */
2770 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2771 EW_FILE) == OK)
2772 {
2773 for (i = 0; i < num_files; ++i)
2774 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002775 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 did_one = TRUE;
2777 if (!all)
2778 break;
2779 }
2780 FreeWild(num_files, files);
2781 }
2782 }
2783 }
2784 }
2785 }
2786 vim_free(buf);
2787 vim_free(rtp_copy);
2788 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002789 {
2790 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002791 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002792 verbose_leave();
2793 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794
2795#ifdef AMIGA
2796 proc->pr_WindowPtr = save_winptr;
2797#endif
2798
2799 return did_one ? OK : FAIL;
2800}
2801
2802#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2803/*
2804 * ":options"
2805 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002806 void
2807ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002808 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002809{
2810 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2811}
2812#endif
2813
2814/*
2815 * ":source {fname}"
2816 */
2817 void
2818ex_source(eap)
2819 exarg_T *eap;
2820{
2821#ifdef FEAT_BROWSE
2822 if (cmdmod.browse)
2823 {
2824 char_u *fname = NULL;
2825
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002826 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002827 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2828 if (fname != NULL)
2829 {
2830 cmd_source(fname, eap);
2831 vim_free(fname);
2832 }
2833 }
2834 else
2835#endif
2836 cmd_source(eap->arg, eap);
2837}
2838
2839 static void
2840cmd_source(fname, eap)
2841 char_u *fname;
2842 exarg_T *eap;
2843{
2844 if (*fname == NUL)
2845 EMSG(_(e_argreq));
2846
Bram Moolenaar071d4272004-06-13 20:20:40 +00002847 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002848 /* ":source!": read Normal mdoe commands
2849 * Need to execute the commands directly. This is required at least
2850 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851 * - ":g" command busy
2852 * - after ":argdo", ":windo" or ":bufdo"
2853 * - another command follows
2854 * - inside a loop
2855 */
2856 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2857#ifdef FEAT_EVAL
2858 || eap->cstack->cs_idx >= 0
2859#endif
2860 );
2861
2862 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002863 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002864 EMSG2(_(e_notopen), fname);
2865}
2866
2867/*
2868 * ":source" and associated commands.
2869 */
2870/*
2871 * Structure used to store info for each sourced file.
2872 * It is shared between do_source() and getsourceline().
2873 * This is required, because it needs to be handed to do_cmdline() and
2874 * sourcing can be done recursively.
2875 */
2876struct source_cookie
2877{
2878 FILE *fp; /* opened file for sourcing */
2879 char_u *nextline; /* if not NULL: line that was read ahead */
2880 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002881#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002882 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2883 int error; /* TRUE if LF found after CR-LF */
2884#endif
2885#ifdef FEAT_EVAL
2886 linenr_T breakpoint; /* next line with breakpoint or zero */
2887 char_u *fname; /* name of sourced file */
2888 int dbg_tick; /* debug_tick when breakpoint was set */
2889 int level; /* top nesting level of sourced file */
2890#endif
2891#ifdef FEAT_MBYTE
2892 vimconv_T conv; /* type of conversion */
2893#endif
2894};
2895
2896#ifdef FEAT_EVAL
2897/*
2898 * Return the address holding the next breakpoint line for a source cookie.
2899 */
2900 linenr_T *
2901source_breakpoint(cookie)
2902 void *cookie;
2903{
2904 return &((struct source_cookie *)cookie)->breakpoint;
2905}
2906
2907/*
2908 * Return the address holding the debug tick for a source cookie.
2909 */
2910 int *
2911source_dbg_tick(cookie)
2912 void *cookie;
2913{
2914 return &((struct source_cookie *)cookie)->dbg_tick;
2915}
2916
2917/*
2918 * Return the nesting level for a source cookie.
2919 */
2920 int
2921source_level(cookie)
2922 void *cookie;
2923{
2924 return ((struct source_cookie *)cookie)->level;
2925}
2926#endif
2927
2928static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2929
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002930#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2931# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932static FILE *fopen_noinh_readbin __ARGS((char *filename));
2933
2934/*
2935 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002936 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 */
2938 static FILE *
2939fopen_noinh_readbin(filename)
2940 char *filename;
2941{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002942# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002943 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2944# else
2945 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002946# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947
2948 if (fd_tmp == -1)
2949 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002950
2951# ifdef HAVE_FD_CLOEXEC
2952 {
2953 int fdflags = fcntl(fd_tmp, F_GETFD);
2954 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
2955 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
2956 }
2957# endif
2958
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959 return fdopen(fd_tmp, READBIN);
2960}
2961#endif
2962
2963
2964/*
2965 * do_source: Read the file "fname" and execute its lines as EX commands.
2966 *
2967 * This function may be called recursively!
2968 *
2969 * return FAIL if file could not be opened, OK otherwise
2970 */
2971 int
2972do_source(fname, check_other, is_vimrc)
2973 char_u *fname;
2974 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002975 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002976{
2977 struct source_cookie cookie;
2978 char_u *save_sourcing_name;
2979 linenr_T save_sourcing_lnum;
2980 char_u *p;
2981 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002982 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983 int retval = FAIL;
2984#ifdef FEAT_EVAL
2985 scid_T save_current_SID;
2986 static scid_T last_current_SID = 0;
2987 void *save_funccalp;
2988 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002989 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990# ifdef UNIX
2991 struct stat st;
2992 int stat_ok;
2993# endif
2994#endif
2995#ifdef STARTUPTIME
2996 struct timeval tv_rel;
2997 struct timeval tv_start;
2998#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002999#ifdef FEAT_PROFILE
3000 proftime_T wait_start;
3001#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003002
Bram Moolenaar071d4272004-06-13 20:20:40 +00003003 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 if (p == NULL)
3005 return retval;
3006 fname_exp = fix_fname(p);
3007 vim_free(p);
3008 if (fname_exp == NULL)
3009 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010 if (mch_isdir(fname_exp))
3011 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003012 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003013 goto theend;
3014 }
3015
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003016#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003017 /* Apply SourceCmd autocommands, they should get the file and source it. */
3018 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3019 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3020 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003021 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003022# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003023 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003024# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003025 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003026# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003027 goto theend;
3028 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003029
3030 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003031 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3032#endif
3033
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003034#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3036#else
3037 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3038#endif
3039 if (cookie.fp == NULL && check_other)
3040 {
3041 /*
3042 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3043 * and ".exrc" by "_exrc" or vice versa.
3044 */
3045 p = gettail(fname_exp);
3046 if ((*p == '.' || *p == '_')
3047 && (STRICMP(p + 1, "vimrc") == 0
3048 || STRICMP(p + 1, "gvimrc") == 0
3049 || STRICMP(p + 1, "exrc") == 0))
3050 {
3051 if (*p == '_')
3052 *p = '.';
3053 else
3054 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003055#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3057#else
3058 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3059#endif
3060 }
3061 }
3062
3063 if (cookie.fp == NULL)
3064 {
3065 if (p_verbose > 0)
3066 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003067 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003069 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070 else
3071 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003072 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003073 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 }
3075 goto theend;
3076 }
3077
3078 /*
3079 * The file exists.
3080 * - In verbose mode, give a message.
3081 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3082 */
3083 if (p_verbose > 1)
3084 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003085 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003087 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088 else
3089 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003090 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003091 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003093 if (is_vimrc == DOSO_VIMRC)
3094 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3095 else if (is_vimrc == DOSO_GVIMRC)
3096 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003097
3098#ifdef USE_CRNL
3099 /* If no automatic file format: Set default to CR-NL. */
3100 if (*p_ffs == NUL)
3101 cookie.fileformat = EOL_DOS;
3102 else
3103 cookie.fileformat = EOL_UNKNOWN;
3104 cookie.error = FALSE;
3105#endif
3106
3107#ifdef USE_CR
3108 /* If no automatic file format: Set default to CR. */
3109 if (*p_ffs == NUL)
3110 cookie.fileformat = EOL_MAC;
3111 else
3112 cookie.fileformat = EOL_UNKNOWN;
3113 cookie.error = FALSE;
3114#endif
3115
3116 cookie.nextline = NULL;
3117 cookie.finished = FALSE;
3118
3119#ifdef FEAT_EVAL
3120 /*
3121 * Check if this script has a breakpoint.
3122 */
3123 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3124 cookie.fname = fname_exp;
3125 cookie.dbg_tick = debug_tick;
3126
3127 cookie.level = ex_nesting_level;
3128#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129
3130 /*
3131 * Keep the sourcing name/lnum, for recursive calls.
3132 */
3133 save_sourcing_name = sourcing_name;
3134 sourcing_name = fname_exp;
3135 save_sourcing_lnum = sourcing_lnum;
3136 sourcing_lnum = 0;
3137
Bram Moolenaar73881402009-02-04 16:50:47 +00003138#ifdef FEAT_MBYTE
3139 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3140
3141 /* Read the first line so we can check for a UTF-8 BOM. */
3142 firstline = getsourceline(0, (void *)&cookie, 0);
3143 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3144 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3145 {
3146 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3147 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3148 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003149 if (p == NULL)
3150 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003151 if (p != NULL)
3152 {
3153 vim_free(firstline);
3154 firstline = p;
3155 }
3156 }
3157#endif
3158
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003160 if (time_fd != NULL)
3161 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162#endif
3163
3164#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003165# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003166 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003167 prof_child_enter(&wait_start); /* entering a child now */
3168# endif
3169
3170 /* Don't use local function variables, if called from a function.
3171 * Also starts profiling timer for nested script. */
3172 save_funccalp = save_funccal();
3173
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174 /*
3175 * Check if this script was sourced before to finds its SID.
3176 * If it's new, generate a new SID.
3177 */
3178 save_current_SID = current_SID;
3179# ifdef UNIX
3180 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3181# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003182 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3183 {
3184 si = &SCRIPT_ITEM(current_SID);
3185 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 && (
3187# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003188 /* Compare dev/ino when possible, it catches symbolic
3189 * links. Also compare file names, the inode may change
3190 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003191 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003192 && (si->sn_dev == st.st_dev
3193 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003194# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003195 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003196 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003197 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198 if (current_SID == 0)
3199 {
3200 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003201 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3202 == FAIL)
3203 goto almosttheend;
3204 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003205 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003206 ++script_items.ga_len;
3207 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3208# ifdef FEAT_PROFILE
3209 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003212 si = &SCRIPT_ITEM(current_SID);
3213 si->sn_name = fname_exp;
3214 fname_exp = NULL;
3215# ifdef UNIX
3216 if (stat_ok)
3217 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003218 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003219 si->sn_dev = st.st_dev;
3220 si->sn_ino = st.st_ino;
3221 }
3222 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003223 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003224# endif
3225
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 /* Allocate the local script variables to use for this script. */
3227 new_script_vars(current_SID);
3228 }
3229
Bram Moolenaar05159a02005-02-26 23:04:13 +00003230# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003231 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003232 {
3233 int forceit;
3234
3235 /* Check if we do profiling for this script. */
3236 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3237 {
3238 script_do_profile(si);
3239 si->sn_pr_force = forceit;
3240 }
3241 if (si->sn_prof_on)
3242 {
3243 ++si->sn_pr_count;
3244 profile_start(&si->sn_pr_start);
3245 profile_zero(&si->sn_pr_children);
3246 }
3247 }
3248# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249#endif
3250
3251 /*
3252 * Call do_cmdline, which will call getsourceline() to get the lines.
3253 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003254 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003257
3258#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003259 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003260 {
3261 /* Get "si" again, "script_items" may have been reallocated. */
3262 si = &SCRIPT_ITEM(current_SID);
3263 if (si->sn_prof_on)
3264 {
3265 profile_end(&si->sn_pr_start);
3266 profile_sub_wait(&wait_start, &si->sn_pr_start);
3267 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003268 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3269 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003270 }
3271 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272#endif
3273
3274 if (got_int)
3275 EMSG(_(e_interr));
3276 sourcing_name = save_sourcing_name;
3277 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278 if (p_verbose > 1)
3279 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003280 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003281 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003282 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003283 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003284 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285 }
3286#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003287 if (time_fd != NULL)
3288 {
3289 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3290 time_msg((char *)IObuff, &tv_start);
3291 time_pop(&tv_rel);
3292 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003293#endif
3294
3295#ifdef FEAT_EVAL
3296 /*
3297 * After a "finish" in debug mode, need to break at first command of next
3298 * sourced file.
3299 */
3300 if (save_debug_break_level > ex_nesting_level
3301 && debug_break_level == ex_nesting_level)
3302 ++debug_break_level;
3303#endif
3304
Bram Moolenaar05159a02005-02-26 23:04:13 +00003305#ifdef FEAT_EVAL
3306almosttheend:
3307 current_SID = save_current_SID;
3308 restore_funccal(save_funccalp);
3309# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003310 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003311 prof_child_exit(&wait_start); /* leaving a child now */
3312# endif
3313#endif
3314 fclose(cookie.fp);
3315 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003316 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003317#ifdef FEAT_MBYTE
3318 convert_setup(&cookie.conv, NULL, NULL);
3319#endif
3320
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321theend:
3322 vim_free(fname_exp);
3323 return retval;
3324}
3325
3326#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003327
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328/*
3329 * ":scriptnames"
3330 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331 void
3332ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003333 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334{
3335 int i;
3336
Bram Moolenaar05159a02005-02-26 23:04:13 +00003337 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3338 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003339 {
3340 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3341 NameBuff, MAXPATHL, TRUE);
3342 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003343 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344}
3345
3346# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3347/*
3348 * Fix slashes in the list of script names for 'shellslash'.
3349 */
3350 void
3351scriptnames_slash_adjust()
3352{
3353 int i;
3354
Bram Moolenaar05159a02005-02-26 23:04:13 +00003355 for (i = 1; i <= script_items.ga_len; ++i)
3356 if (SCRIPT_ITEM(i).sn_name != NULL)
3357 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358}
3359# endif
3360
3361/*
3362 * Get a pointer to a script name. Used for ":verbose set".
3363 */
3364 char_u *
3365get_scriptname(id)
3366 scid_T id;
3367{
3368 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003369 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003371 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003373 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003374 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003375 return (char_u *)_("environment variable");
3376 if (id == SID_ERROR)
3377 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003378 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003380
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003381# if defined(EXITFREE) || defined(PROTO)
3382 void
3383free_scriptnames()
3384{
3385 int i;
3386
3387 for (i = script_items.ga_len; i > 0; --i)
3388 vim_free(SCRIPT_ITEM(i).sn_name);
3389 ga_clear(&script_items);
3390}
3391# endif
3392
Bram Moolenaar071d4272004-06-13 20:20:40 +00003393#endif
3394
3395#if defined(USE_CR) || defined(PROTO)
3396
3397# if defined(__MSL__) && (__MSL__ >= 22)
3398/*
3399 * Newer version of the Metrowerks library handle DOS and UNIX files
3400 * without help.
3401 * Test with earlier versions, MSL 2.2 is the library supplied with
3402 * Codewarrior Pro 2.
3403 */
3404 char *
3405fgets_cr(s, n, stream)
3406 char *s;
3407 int n;
3408 FILE *stream;
3409{
3410 return fgets(s, n, stream);
3411}
3412# else
3413/*
3414 * Version of fgets() which also works for lines ending in a <CR> only
3415 * (Macintosh format).
3416 * For older versions of the Metrowerks library.
3417 * At least CodeWarrior 9 needed this code.
3418 */
3419 char *
3420fgets_cr(s, n, stream)
3421 char *s;
3422 int n;
3423 FILE *stream;
3424{
3425 int c = 0;
3426 int char_read = 0;
3427
3428 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3429 {
3430 c = fgetc(stream);
3431 s[char_read++] = c;
3432 /* If the file is in DOS format, we need to skip a NL after a CR. I
3433 * thought it was the other way around, but this appears to work... */
3434 if (c == '\n')
3435 {
3436 c = fgetc(stream);
3437 if (c != '\r')
3438 ungetc(c, stream);
3439 }
3440 }
3441
3442 s[char_read] = 0;
3443 if (char_read == 0)
3444 return NULL;
3445
3446 if (feof(stream) && char_read == 1)
3447 return NULL;
3448
3449 return s;
3450}
3451# endif
3452#endif
3453
3454/*
3455 * Get one full line from a sourced file.
3456 * Called by do_cmdline() when it's called from do_source().
3457 *
3458 * Return a pointer to the line in allocated memory.
3459 * Return NULL for end-of-file or some error.
3460 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461 char_u *
3462getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003463 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003465 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466{
3467 struct source_cookie *sp = (struct source_cookie *)cookie;
3468 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003469 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470
3471#ifdef FEAT_EVAL
3472 /* If breakpoints have been added/deleted need to check for it. */
3473 if (sp->dbg_tick < debug_tick)
3474 {
3475 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3476 sp->dbg_tick = debug_tick;
3477 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003478# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003479 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003480 script_line_end();
3481# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482#endif
3483 /*
3484 * Get current line. If there is a read-ahead line, use it, otherwise get
3485 * one now.
3486 */
3487 if (sp->finished)
3488 line = NULL;
3489 else if (sp->nextline == NULL)
3490 line = get_one_sourceline(sp);
3491 else
3492 {
3493 line = sp->nextline;
3494 sp->nextline = NULL;
3495 ++sourcing_lnum;
3496 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003497#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003498 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003499 script_line_start();
3500#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003501
3502 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3503 * contain the 'C' flag. */
3504 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3505 {
3506 /* compensate for the one line read-ahead */
3507 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003508
3509 /* Get the next line and concatenate it when it starts with a
3510 * backslash. We always need to read the next line, keep it in
3511 * sp->nextline. */
3512 sp->nextline = get_one_sourceline(sp);
3513 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003515 garray_T ga;
3516
Bram Moolenaarb549a732012-02-22 18:29:33 +01003517 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003518 ga_concat(&ga, line);
3519 ga_concat(&ga, p + 1);
3520 for (;;)
3521 {
3522 vim_free(sp->nextline);
3523 sp->nextline = get_one_sourceline(sp);
3524 if (sp->nextline == NULL)
3525 break;
3526 p = skipwhite(sp->nextline);
3527 if (*p != '\\')
3528 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003529 /* Adjust the growsize to the current length to speed up
3530 * concatenating many lines. */
3531 if (ga.ga_len > 400)
3532 {
3533 if (ga.ga_len > 8000)
3534 ga.ga_growsize = 8000;
3535 else
3536 ga.ga_growsize = ga.ga_len;
3537 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003538 ga_concat(&ga, p + 1);
3539 }
3540 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003542 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003543 }
3544 }
3545
3546#ifdef FEAT_MBYTE
3547 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3548 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003549 char_u *s;
3550
Bram Moolenaar071d4272004-06-13 20:20:40 +00003551 /* Convert the encoding of the script line. */
3552 s = string_convert(&sp->conv, line, NULL);
3553 if (s != NULL)
3554 {
3555 vim_free(line);
3556 line = s;
3557 }
3558 }
3559#endif
3560
3561#ifdef FEAT_EVAL
3562 /* Did we encounter a breakpoint? */
3563 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3564 {
3565 dbg_breakpoint(sp->fname, sourcing_lnum);
3566 /* Find next breakpoint. */
3567 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3568 sp->dbg_tick = debug_tick;
3569 }
3570#endif
3571
3572 return line;
3573}
3574
3575 static char_u *
3576get_one_sourceline(sp)
3577 struct source_cookie *sp;
3578{
3579 garray_T ga;
3580 int len;
3581 int c;
3582 char_u *buf;
3583#ifdef USE_CRNL
3584 int has_cr; /* CR-LF found */
3585#endif
3586#ifdef USE_CR
3587 char_u *scan;
3588#endif
3589 int have_read = FALSE;
3590
3591 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003592 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593
3594 /*
3595 * Loop until there is a finished line (or end-of-file).
3596 */
3597 sourcing_lnum++;
3598 for (;;)
3599 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003600 /* make room to read at least 120 (more) characters */
3601 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 break;
3603 buf = (char_u *)ga.ga_data;
3604
3605#ifdef USE_CR
3606 if (sp->fileformat == EOL_MAC)
3607 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003608 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3609 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003610 break;
3611 }
3612 else
3613#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003614 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3615 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003617 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003618#ifdef USE_CRNL
3619 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3620 * CTRL-Z by its own, or after a NL. */
3621 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3622 && sp->fileformat == EOL_DOS
3623 && buf[len - 1] == Ctrl_Z)
3624 {
3625 buf[len - 1] = NUL;
3626 break;
3627 }
3628#endif
3629
3630#ifdef USE_CR
3631 /* If the read doesn't stop on a new line, and there's
3632 * some CR then we assume a Mac format */
3633 if (sp->fileformat == EOL_UNKNOWN)
3634 {
3635 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3636 sp->fileformat = EOL_MAC;
3637 else
3638 sp->fileformat = EOL_UNIX;
3639 }
3640
3641 if (sp->fileformat == EOL_MAC)
3642 {
3643 scan = vim_strchr(buf, '\r');
3644
3645 if (scan != NULL)
3646 {
3647 *scan = '\n';
3648 if (*(scan + 1) != 0)
3649 {
3650 *(scan + 1) = 0;
3651 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3652 }
3653 }
3654 len = STRLEN(buf);
3655 }
3656#endif
3657
3658 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659 ga.ga_len = len;
3660
3661 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003662 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663 continue;
3664
3665 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3666 {
3667#ifdef USE_CRNL
3668 has_cr = (len >= 2 && buf[len - 2] == '\r');
3669 if (sp->fileformat == EOL_UNKNOWN)
3670 {
3671 if (has_cr)
3672 sp->fileformat = EOL_DOS;
3673 else
3674 sp->fileformat = EOL_UNIX;
3675 }
3676
3677 if (sp->fileformat == EOL_DOS)
3678 {
3679 if (has_cr) /* replace trailing CR */
3680 {
3681 buf[len - 2] = '\n';
3682 --len;
3683 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003684 }
3685 else /* lines like ":map xx yy^M" will have failed */
3686 {
3687 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003688 {
3689 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003691 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003692 sp->error = TRUE;
3693 sp->fileformat = EOL_UNIX;
3694 }
3695 }
3696#endif
3697 /* The '\n' is escaped if there is an odd number of ^V's just
3698 * before it, first set "c" just before the 'V's and then check
3699 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3700 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3701 ;
3702 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3703 {
3704 sourcing_lnum++;
3705 continue;
3706 }
3707
3708 buf[len - 1] = NUL; /* remove the NL */
3709 }
3710
3711 /*
3712 * Check for ^C here now and then, so recursive :so can be broken.
3713 */
3714 line_breakcheck();
3715 break;
3716 }
3717
3718 if (have_read)
3719 return (char_u *)ga.ga_data;
3720
3721 vim_free(ga.ga_data);
3722 return NULL;
3723}
3724
Bram Moolenaar05159a02005-02-26 23:04:13 +00003725#if defined(FEAT_PROFILE) || defined(PROTO)
3726/*
3727 * Called when starting to read a script line.
3728 * "sourcing_lnum" must be correct!
3729 * When skipping lines it may not actually be executed, but we won't find out
3730 * until later and we need to store the time now.
3731 */
3732 void
3733script_line_start()
3734{
3735 scriptitem_T *si;
3736 sn_prl_T *pp;
3737
3738 if (current_SID <= 0 || current_SID > script_items.ga_len)
3739 return;
3740 si = &SCRIPT_ITEM(current_SID);
3741 if (si->sn_prof_on && sourcing_lnum >= 1)
3742 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003743 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003744 * here isn't counted. */
3745 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3746 si->sn_prl_idx = sourcing_lnum - 1;
3747 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3748 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3749 {
3750 /* Zero counters for a line that was not used before. */
3751 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3752 pp->snp_count = 0;
3753 profile_zero(&pp->sn_prl_total);
3754 profile_zero(&pp->sn_prl_self);
3755 ++si->sn_prl_ga.ga_len;
3756 }
3757 si->sn_prl_execed = FALSE;
3758 profile_start(&si->sn_prl_start);
3759 profile_zero(&si->sn_prl_children);
3760 profile_get_wait(&si->sn_prl_wait);
3761 }
3762}
3763
3764/*
3765 * Called when actually executing a function line.
3766 */
3767 void
3768script_line_exec()
3769{
3770 scriptitem_T *si;
3771
3772 if (current_SID <= 0 || current_SID > script_items.ga_len)
3773 return;
3774 si = &SCRIPT_ITEM(current_SID);
3775 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3776 si->sn_prl_execed = TRUE;
3777}
3778
3779/*
3780 * Called when done with a function line.
3781 */
3782 void
3783script_line_end()
3784{
3785 scriptitem_T *si;
3786 sn_prl_T *pp;
3787
3788 if (current_SID <= 0 || current_SID > script_items.ga_len)
3789 return;
3790 si = &SCRIPT_ITEM(current_SID);
3791 if (si->sn_prof_on && si->sn_prl_idx >= 0
3792 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3793 {
3794 if (si->sn_prl_execed)
3795 {
3796 pp = &PRL_ITEM(si, si->sn_prl_idx);
3797 ++pp->snp_count;
3798 profile_end(&si->sn_prl_start);
3799 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003800 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003801 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3802 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003803 }
3804 si->sn_prl_idx = -1;
3805 }
3806}
3807#endif
3808
Bram Moolenaar071d4272004-06-13 20:20:40 +00003809/*
3810 * ":scriptencoding": Set encoding conversion for a sourced script.
3811 * Without the multi-byte feature it's simply ignored.
3812 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813 void
3814ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003815 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003816{
3817#ifdef FEAT_MBYTE
3818 struct source_cookie *sp;
3819 char_u *name;
3820
3821 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3822 {
3823 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3824 return;
3825 }
3826
3827 if (*eap->arg != NUL)
3828 {
3829 name = enc_canonize(eap->arg);
3830 if (name == NULL) /* out of memory */
3831 return;
3832 }
3833 else
3834 name = eap->arg;
3835
3836 /* Setup for conversion from the specified encoding to 'encoding'. */
3837 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3838 convert_setup(&sp->conv, name, p_enc);
3839
3840 if (name != eap->arg)
3841 vim_free(name);
3842#endif
3843}
3844
3845#if defined(FEAT_EVAL) || defined(PROTO)
3846/*
3847 * ":finish": Mark a sourced file as finished.
3848 */
3849 void
3850ex_finish(eap)
3851 exarg_T *eap;
3852{
3853 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3854 do_finish(eap, FALSE);
3855 else
3856 EMSG(_("E168: :finish used outside of a sourced file"));
3857}
3858
3859/*
3860 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3861 * Also called for a pending finish at the ":endtry" or after returning from
3862 * an extra do_cmdline(). "reanimate" is used in the latter case.
3863 */
3864 void
3865do_finish(eap, reanimate)
3866 exarg_T *eap;
3867 int reanimate;
3868{
3869 int idx;
3870
3871 if (reanimate)
3872 ((struct source_cookie *)getline_cookie(eap->getline,
3873 eap->cookie))->finished = FALSE;
3874
3875 /*
3876 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3877 * not in its finally clause (which then is to be executed next) is found.
3878 * In this case, make the ":finish" pending for execution at the ":endtry".
3879 * Otherwise, finish normally.
3880 */
3881 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3882 if (idx >= 0)
3883 {
3884 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3885 report_make_pending(CSTP_FINISH, NULL);
3886 }
3887 else
3888 ((struct source_cookie *)getline_cookie(eap->getline,
3889 eap->cookie))->finished = TRUE;
3890}
3891
3892
3893/*
3894 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3895 * message for missing ":endif".
3896 * Return FALSE when not sourcing a file.
3897 */
3898 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003899source_finished(fgetline, cookie)
3900 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 void *cookie;
3902{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003903 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003904 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003905 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906}
3907#endif
3908
3909#if defined(FEAT_LISTCMDS) || defined(PROTO)
3910/*
3911 * ":checktime [buffer]"
3912 */
3913 void
3914ex_checktime(eap)
3915 exarg_T *eap;
3916{
3917 buf_T *buf;
3918 int save_no_check_timestamps = no_check_timestamps;
3919
3920 no_check_timestamps = 0;
3921 if (eap->addr_count == 0) /* default is all buffers */
3922 check_timestamps(FALSE);
3923 else
3924 {
3925 buf = buflist_findnr((int)eap->line2);
3926 if (buf != NULL) /* cannot happen? */
3927 (void)buf_check_timestamp(buf, FALSE);
3928 }
3929 no_check_timestamps = save_no_check_timestamps;
3930}
3931#endif
3932
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3934 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003935# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003936static char *get_locale_val __ARGS((int what));
3937
3938 static char *
3939get_locale_val(what)
3940 int what;
3941{
3942 char *loc;
3943
3944 /* Obtain the locale value from the libraries. For DJGPP this is
3945 * redefined and it doesn't use the arguments. */
3946 loc = setlocale(what, NULL);
3947
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003948# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003949 if (loc != NULL)
3950 {
3951 char_u *p;
3952
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003953 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3954 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955 p = vim_strchr(loc, '=');
3956 if (p != NULL)
3957 {
3958 loc = ++p;
3959 while (*p != NUL) /* remove trailing newline */
3960 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003961 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003962 {
3963 *p = NUL;
3964 break;
3965 }
3966 ++p;
3967 }
3968 }
3969 }
3970# endif
3971
3972 return loc;
3973}
3974#endif
3975
3976
3977#ifdef WIN32
3978/*
3979 * On MS-Windows locale names are strings like "German_Germany.1252", but
3980 * gettext expects "de". Try to translate one into another here for a few
3981 * supported languages.
3982 */
3983 static char_u *
3984gettext_lang(char_u *name)
3985{
3986 int i;
3987 static char *(mtable[]) = {
3988 "afrikaans", "af",
3989 "czech", "cs",
3990 "dutch", "nl",
3991 "german", "de",
3992 "english_united kingdom", "en_GB",
3993 "spanish", "es",
3994 "french", "fr",
3995 "italian", "it",
3996 "japanese", "ja",
3997 "korean", "ko",
3998 "norwegian", "no",
3999 "polish", "pl",
4000 "russian", "ru",
4001 "slovak", "sk",
4002 "swedish", "sv",
4003 "ukrainian", "uk",
4004 "chinese_china", "zh_CN",
4005 "chinese_taiwan", "zh_TW",
4006 NULL};
4007
4008 for (i = 0; mtable[i] != NULL; i += 2)
4009 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4010 return mtable[i + 1];
4011 return name;
4012}
4013#endif
4014
4015#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4016/*
4017 * Obtain the current messages language. Used to set the default for
4018 * 'helplang'. May return NULL or an empty string.
4019 */
4020 char_u *
4021get_mess_lang()
4022{
4023 char_u *p;
4024
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004025# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004026# if defined(LC_MESSAGES)
4027 p = (char_u *)get_locale_val(LC_MESSAGES);
4028# else
4029 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004030 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4031 * and LC_MONETARY may be set differently for a Japanese working in the
4032 * US. */
4033 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004034# endif
4035# else
4036 p = mch_getenv((char_u *)"LC_ALL");
4037 if (p == NULL || *p == NUL)
4038 {
4039 p = mch_getenv((char_u *)"LC_MESSAGES");
4040 if (p == NULL || *p == NUL)
4041 p = mch_getenv((char_u *)"LANG");
4042 }
4043# endif
4044# ifdef WIN32
4045 p = gettext_lang(p);
4046# endif
4047 return p;
4048}
4049#endif
4050
Bram Moolenaardef9e822004-12-31 20:58:58 +00004051/* Complicated #if; matches with where get_mess_env() is used below. */
4052#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4053 && defined(LC_MESSAGES))) \
4054 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4055 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4056 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004057static char_u *get_mess_env __ARGS((void));
4058
4059/*
4060 * Get the language used for messages from the environment.
4061 */
4062 static char_u *
4063get_mess_env()
4064{
4065 char_u *p;
4066
4067 p = mch_getenv((char_u *)"LC_ALL");
4068 if (p == NULL || *p == NUL)
4069 {
4070 p = mch_getenv((char_u *)"LC_MESSAGES");
4071 if (p == NULL || *p == NUL)
4072 {
4073 p = mch_getenv((char_u *)"LANG");
4074 if (p != NULL && VIM_ISDIGIT(*p))
4075 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004076# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004077 if (p == NULL || *p == NUL)
4078 p = (char_u *)get_locale_val(LC_CTYPE);
4079# endif
4080 }
4081 }
4082 return p;
4083}
4084#endif
4085
4086#if defined(FEAT_EVAL) || defined(PROTO)
4087
4088/*
4089 * Set the "v:lang" variable according to the current locale setting.
4090 * Also do "v:lc_time"and "v:ctype".
4091 */
4092 void
4093set_lang_var()
4094{
4095 char_u *loc;
4096
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004097# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098 loc = (char_u *)get_locale_val(LC_CTYPE);
4099# else
4100 /* setlocale() not supported: use the default value */
4101 loc = (char_u *)"C";
4102# endif
4103 set_vim_var_string(VV_CTYPE, loc, -1);
4104
4105 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4106 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004107# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 loc = (char_u *)get_locale_val(LC_MESSAGES);
4109# else
4110 loc = get_mess_env();
4111# endif
4112 set_vim_var_string(VV_LANG, loc, -1);
4113
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004114# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115 loc = (char_u *)get_locale_val(LC_TIME);
4116# endif
4117 set_vim_var_string(VV_LC_TIME, loc, -1);
4118}
4119#endif
4120
4121#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4122 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4123/*
4124 * ":language": Set the language (locale).
4125 */
4126 void
4127ex_language(eap)
4128 exarg_T *eap;
4129{
4130 char *loc;
4131 char_u *p;
4132 char_u *name;
4133 int what = LC_ALL;
4134 char *whatstr = "";
4135#ifdef LC_MESSAGES
4136# define VIM_LC_MESSAGES LC_MESSAGES
4137#else
4138# define VIM_LC_MESSAGES 6789
4139#endif
4140
4141 name = eap->arg;
4142
4143 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4144 * Allow abbreviation, but require at least 3 characters to avoid
4145 * confusion with a two letter language name "me" or "ct". */
4146 p = skiptowhite(eap->arg);
4147 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4148 {
4149 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4150 {
4151 what = VIM_LC_MESSAGES;
4152 name = skipwhite(p);
4153 whatstr = "messages ";
4154 }
4155 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4156 {
4157 what = LC_CTYPE;
4158 name = skipwhite(p);
4159 whatstr = "ctype ";
4160 }
4161 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4162 {
4163 what = LC_TIME;
4164 name = skipwhite(p);
4165 whatstr = "time ";
4166 }
4167 }
4168
4169 if (*name == NUL)
4170 {
4171#ifndef LC_MESSAGES
4172 if (what == VIM_LC_MESSAGES)
4173 p = get_mess_env();
4174 else
4175#endif
4176 p = (char_u *)setlocale(what, NULL);
4177 if (p == NULL || *p == NUL)
4178 p = (char_u *)"Unknown";
4179 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4180 }
4181 else
4182 {
4183#ifndef LC_MESSAGES
4184 if (what == VIM_LC_MESSAGES)
4185 loc = "";
4186 else
4187#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004188 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004189 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004190#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4191 /* Make sure strtod() uses a decimal point, not a comma. */
4192 setlocale(LC_NUMERIC, "C");
4193#endif
4194 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004195 if (loc == NULL)
4196 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4197 else
4198 {
4199#ifdef HAVE_NL_MSG_CAT_CNTR
4200 /* Need to do this for GNU gettext, otherwise cached translations
4201 * will be used again. */
4202 extern int _nl_msg_cat_cntr;
4203
4204 ++_nl_msg_cat_cntr;
4205#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004206 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4208
4209 if (what != LC_TIME)
4210 {
4211 /* Tell gettext() what to translate to. It apparently doesn't
4212 * use the currently effective locale. Also do this when
4213 * FEAT_GETTEXT isn't defined, so that shell commands use this
4214 * value. */
4215 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004216 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004217 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004218# ifdef WIN32
4219 /* Apparently MS-Windows printf() may cause a crash when
4220 * we give it 8-bit text while it's expecting text in the
4221 * current locale. This call avoids that. */
4222 setlocale(LC_CTYPE, "C");
4223# endif
4224 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225 if (what != LC_CTYPE)
4226 {
4227 char_u *mname;
4228#ifdef WIN32
4229 mname = gettext_lang(name);
4230#else
4231 mname = name;
4232#endif
4233 vim_setenv((char_u *)"LC_MESSAGES", mname);
4234#ifdef FEAT_MULTI_LANG
4235 set_helplang_default(mname);
4236#endif
4237 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004238 }
4239
4240# ifdef FEAT_EVAL
4241 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4242 set_lang_var();
4243# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004244# ifdef FEAT_TITLE
4245 maketitle();
4246# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004247 }
4248 }
4249}
4250
4251# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004252
4253static char_u **locales = NULL; /* Array of all available locales */
4254static int did_init_locales = FALSE;
4255
4256static void init_locales __ARGS((void));
4257static char_u **find_locales __ARGS((void));
4258
4259/*
4260 * Lazy initialization of all available locales.
4261 */
4262 static void
4263init_locales()
4264{
4265 if (!did_init_locales)
4266 {
4267 did_init_locales = TRUE;
4268 locales = find_locales();
4269 }
4270}
4271
4272/* Return an array of strings for all available locales + NULL for the
4273 * last element. Return NULL in case of error. */
4274 static char_u **
4275find_locales()
4276{
4277 garray_T locales_ga;
4278 char_u *loc;
4279
4280 /* Find all available locales by running command "locale -a". If this
4281 * doesn't work we won't have completion. */
4282 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
4283 NULL, SHELL_SILENT);
4284 if (locale_a == NULL)
4285 return NULL;
4286 ga_init2(&locales_ga, sizeof(char_u *), 20);
4287
4288 /* Transform locale_a string where each locale is separated by "\n"
4289 * into an array of locale strings. */
4290 loc = (char_u *)strtok((char *)locale_a, "\n");
4291
4292 while (loc != NULL)
4293 {
4294 if (ga_grow(&locales_ga, 1) == FAIL)
4295 break;
4296 loc = vim_strsave(loc);
4297 if (loc == NULL)
4298 break;
4299
4300 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4301 loc = (char_u *)strtok(NULL, "\n");
4302 }
4303 vim_free(locale_a);
4304 if (ga_grow(&locales_ga, 1) == FAIL)
4305 {
4306 ga_clear(&locales_ga);
4307 return NULL;
4308 }
4309 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4310 return (char_u **)locales_ga.ga_data;
4311}
4312
4313# if defined(EXITFREE) || defined(PROTO)
4314 void
4315free_locales()
4316{
4317 int i;
4318 if (locales != NULL)
4319 {
4320 for (i = 0; locales[i] != NULL; i++)
4321 vim_free(locales[i]);
4322 vim_free(locales);
4323 locales = NULL;
4324 }
4325}
4326# endif
4327
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328/*
4329 * Function given to ExpandGeneric() to obtain the possible arguments of the
4330 * ":language" command.
4331 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004332 char_u *
4333get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004334 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335 int idx;
4336{
4337 if (idx == 0)
4338 return (char_u *)"messages";
4339 if (idx == 1)
4340 return (char_u *)"ctype";
4341 if (idx == 2)
4342 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004343
4344 init_locales();
4345 if (locales == NULL)
4346 return NULL;
4347 return locales[idx - 3];
4348}
4349
4350/*
4351 * Function given to ExpandGeneric() to obtain the available locales.
4352 */
4353 char_u *
4354get_locales(xp, idx)
4355 expand_T *xp UNUSED;
4356 int idx;
4357{
4358 init_locales();
4359 if (locales == NULL)
4360 return NULL;
4361 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362}
4363# endif
4364
4365#endif