blob: 908552d5801c4075f8792c06ae76095ebb6fde1b [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;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000599 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200600 {
601#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000602 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200603#else
604 ex_ni(eap);
605 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000606#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200607 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608
609 if (vim_isdigit(*eap->arg))
610 {
611 /* ":breakdel {nr}" */
612 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000613 for (i = 0; i < gap->ga_len; ++i)
614 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 {
616 todel = i;
617 break;
618 }
619 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000620 else if (*eap->arg == '*')
621 {
622 todel = 0;
623 del_all = TRUE;
624 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 else
626 {
627 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000628 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000630 bp = &DEBUGGY(gap, gap->ga_len);
631 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000633 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 if (bp->dbg_type == bpi->dbg_type
635 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
636 && (bp->dbg_lnum == bpi->dbg_lnum
637 || (bp->dbg_lnum == 0
638 && (best_lnum == 0
639 || bpi->dbg_lnum < best_lnum))))
640 {
641 todel = i;
642 best_lnum = bpi->dbg_lnum;
643 }
644 }
645 vim_free(bp->dbg_name);
646 }
647
648 if (todel < 0)
649 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
650 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000651 {
652 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000653 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000654 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200655 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000656 --gap->ga_len;
657 if (todel < gap->ga_len)
658 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
659 (gap->ga_len - todel) * sizeof(struct debuggy));
660#ifdef FEAT_PROFILE
661 if (eap->cmdidx == CMD_breakdel)
662#endif
663 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000664 if (!del_all)
665 break;
666 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000667
668 /* If all breakpoints were removed clear the array. */
669 if (gap->ga_len == 0)
670 ga_clear(gap);
671 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672}
673
674/*
675 * ":breaklist".
676 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677 void
678ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000679 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680{
681 struct debuggy *bp;
682 int i;
683
684 if (dbg_breakp.ga_len == 0)
685 MSG(_("No breakpoints defined"));
686 else
687 for (i = 0; i < dbg_breakp.ga_len; ++i)
688 {
689 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200690 if (bp->dbg_type == DBG_FILE)
691 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 smsg((char_u *)_("%3d %s %s line %ld"),
693 bp->dbg_nr,
694 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200695 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 (long)bp->dbg_lnum);
697 }
698}
699
700/*
701 * Find a breakpoint for a function or sourced file.
702 * Returns line number at which to break; zero when no matching breakpoint.
703 */
704 linenr_T
705dbg_find_breakpoint(file, fname, after)
706 int file; /* TRUE for a file, FALSE for a function */
707 char_u *fname; /* file or function name */
708 linenr_T after; /* after this line number */
709{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000710 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
711}
712
713#if defined(FEAT_PROFILE) || defined(PROTO)
714/*
715 * Return TRUE if profiling is on for a function or sourced file.
716 */
717 int
718has_profiling(file, fname, fp)
719 int file; /* TRUE for a file, FALSE for a function */
720 char_u *fname; /* file or function name */
721 int *fp; /* return: forceit */
722{
723 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
724 != (linenr_T)0);
725}
726#endif
727
728/*
729 * Common code for dbg_find_breakpoint() and has_profiling().
730 */
731 static linenr_T
732debuggy_find(file, fname, after, gap, fp)
733 int file; /* TRUE for a file, FALSE for a function */
734 char_u *fname; /* file or function name */
735 linenr_T after; /* after this line number */
736 garray_T *gap; /* either &dbg_breakp or &prof_ga */
737 int *fp; /* if not NULL: return forceit */
738{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 struct debuggy *bp;
740 int i;
741 linenr_T lnum = 0;
742 regmatch_T regmatch;
743 char_u *name = fname;
744 int prev_got_int;
745
Bram Moolenaar05159a02005-02-26 23:04:13 +0000746 /* Return quickly when there are no breakpoints. */
747 if (gap->ga_len == 0)
748 return (linenr_T)0;
749
Bram Moolenaar071d4272004-06-13 20:20:40 +0000750 /* Replace K_SNR in function name with "<SNR>". */
751 if (!file && fname[0] == K_SPECIAL)
752 {
753 name = alloc((unsigned)STRLEN(fname) + 3);
754 if (name == NULL)
755 name = fname;
756 else
757 {
758 STRCPY(name, "<SNR>");
759 STRCPY(name + 5, fname + 3);
760 }
761 }
762
Bram Moolenaar05159a02005-02-26 23:04:13 +0000763 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000765 /* Skip entries that are not useful or are for a line that is beyond
766 * an already found breakpoint. */
767 bp = &DEBUGGY(gap, i);
768 if (((bp->dbg_type == DBG_FILE) == file && (
769#ifdef FEAT_PROFILE
770 gap == &prof_ga ||
771#endif
772 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 {
774 regmatch.regprog = bp->dbg_prog;
775 regmatch.rm_ic = FALSE;
776 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000777 * Save the value of got_int and reset it. We don't want a
778 * previous interruption cancel matching, only hitting CTRL-C
779 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 */
781 prev_got_int = got_int;
782 got_int = FALSE;
783 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000784 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000786 if (fp != NULL)
787 *fp = bp->dbg_forceit;
788 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789 got_int |= prev_got_int;
790 }
791 }
792 if (name != fname)
793 vim_free(name);
794
795 return lnum;
796}
797
798/*
799 * Called when a breakpoint was encountered.
800 */
801 void
802dbg_breakpoint(name, lnum)
803 char_u *name;
804 linenr_T lnum;
805{
806 /* We need to check if this line is actually executed in do_one_cmd() */
807 debug_breakpoint_name = name;
808 debug_breakpoint_lnum = lnum;
809}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000810
811
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000812# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000813/*
814 * Store the current time in "tm".
815 */
816 void
817profile_start(tm)
818 proftime_T *tm;
819{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000820# ifdef WIN3264
821 QueryPerformanceCounter(tm);
822# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000823 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000824# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000825}
826
827/*
828 * Compute the elapsed time from "tm" till now and store in "tm".
829 */
830 void
831profile_end(tm)
832 proftime_T *tm;
833{
834 proftime_T now;
835
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000836# ifdef WIN3264
837 QueryPerformanceCounter(&now);
838 tm->QuadPart = now.QuadPart - tm->QuadPart;
839# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000840 gettimeofday(&now, NULL);
841 tm->tv_usec = now.tv_usec - tm->tv_usec;
842 tm->tv_sec = now.tv_sec - tm->tv_sec;
843 if (tm->tv_usec < 0)
844 {
845 tm->tv_usec += 1000000;
846 --tm->tv_sec;
847 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000848# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000849}
850
851/*
852 * Subtract the time "tm2" from "tm".
853 */
854 void
855profile_sub(tm, tm2)
856 proftime_T *tm, *tm2;
857{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000858# ifdef WIN3264
859 tm->QuadPart -= tm2->QuadPart;
860# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861 tm->tv_usec -= tm2->tv_usec;
862 tm->tv_sec -= tm2->tv_sec;
863 if (tm->tv_usec < 0)
864 {
865 tm->tv_usec += 1000000;
866 --tm->tv_sec;
867 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000868# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000869}
870
871/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000872 * Return a string that represents the time in "tm".
873 * Uses a static buffer!
874 */
875 char *
876profile_msg(tm)
877 proftime_T *tm;
878{
879 static char buf[50];
880
881# ifdef WIN3264
882 LARGE_INTEGER fr;
883
884 QueryPerformanceFrequency(&fr);
885 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
886# else
887 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000888# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000889 return buf;
890}
891
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000892/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000893 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000894 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000895 void
896profile_setlimit(msec, tm)
897 long msec;
898 proftime_T *tm;
899{
900 if (msec <= 0) /* no limit */
901 profile_zero(tm);
902 else
903 {
904# ifdef WIN3264
905 LARGE_INTEGER fr;
906
907 QueryPerformanceCounter(tm);
908 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000909 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000910# else
911 long usec;
912
913 gettimeofday(tm, NULL);
914 usec = (long)tm->tv_usec + (long)msec * 1000;
915 tm->tv_usec = usec % 1000000L;
916 tm->tv_sec += usec / 1000000L;
917# endif
918 }
919}
920
921/*
922 * Return TRUE if the current time is past "tm".
923 */
924 int
925profile_passed_limit(tm)
926 proftime_T *tm;
927{
928 proftime_T now;
929
930# ifdef WIN3264
931 if (tm->QuadPart == 0) /* timer was not set */
932 return FALSE;
933 QueryPerformanceCounter(&now);
934 return (now.QuadPart > tm->QuadPart);
935# else
936 if (tm->tv_sec == 0) /* timer was not set */
937 return FALSE;
938 gettimeofday(&now, NULL);
939 return (now.tv_sec > tm->tv_sec
940 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
941# endif
942}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000943
944/*
945 * Set the time in "tm" to zero.
946 */
947 void
948profile_zero(tm)
949 proftime_T *tm;
950{
951# ifdef WIN3264
952 tm->QuadPart = 0;
953# else
954 tm->tv_usec = 0;
955 tm->tv_sec = 0;
956# endif
957}
958
Bram Moolenaar76929292008-01-06 19:07:36 +0000959# endif /* FEAT_PROFILE || FEAT_RELTIME */
960
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200961#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
962# if defined(HAVE_MATH_H)
963# include <math.h>
964# endif
965
966/*
967 * Divide the time "tm" by "count" and store in "tm2".
968 */
969 void
970profile_divide(tm, count, tm2)
971 proftime_T *tm;
972 proftime_T *tm2;
973 int count;
974{
975 if (count == 0)
976 profile_zero(tm2);
977 else
978 {
979# ifdef WIN3264
980 tm2->QuadPart = tm->QuadPart / count;
981# else
982 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
983
984 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +0200985 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200986# endif
987 }
988}
989#endif
990
Bram Moolenaar76929292008-01-06 19:07:36 +0000991# if defined(FEAT_PROFILE) || defined(PROTO)
992/*
993 * Functions for profiling.
994 */
995static void script_do_profile __ARGS((scriptitem_T *si));
996static void script_dump_profile __ARGS((FILE *fd));
997static proftime_T prof_wait_time;
998
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000999/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001000 * Add the time "tm2" to "tm".
1001 */
1002 void
1003profile_add(tm, tm2)
1004 proftime_T *tm, *tm2;
1005{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001006# ifdef WIN3264
1007 tm->QuadPart += tm2->QuadPart;
1008# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001009 tm->tv_usec += tm2->tv_usec;
1010 tm->tv_sec += tm2->tv_sec;
1011 if (tm->tv_usec >= 1000000)
1012 {
1013 tm->tv_usec -= 1000000;
1014 ++tm->tv_sec;
1015 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001016# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001017}
1018
1019/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001020 * Add the "self" time from the total time and the children's time.
1021 */
1022 void
1023profile_self(self, total, children)
1024 proftime_T *self, *total, *children;
1025{
1026 /* Check that the result won't be negative. Can happen with recursive
1027 * calls. */
1028#ifdef WIN3264
1029 if (total->QuadPart <= children->QuadPart)
1030 return;
1031#else
1032 if (total->tv_sec < children->tv_sec
1033 || (total->tv_sec == children->tv_sec
1034 && total->tv_usec <= children->tv_usec))
1035 return;
1036#endif
1037 profile_add(self, total);
1038 profile_sub(self, children);
1039}
1040
1041/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001042 * Get the current waittime.
1043 */
1044 void
1045profile_get_wait(tm)
1046 proftime_T *tm;
1047{
1048 *tm = prof_wait_time;
1049}
1050
1051/*
1052 * Subtract the passed waittime since "tm" from "tma".
1053 */
1054 void
1055profile_sub_wait(tm, tma)
1056 proftime_T *tm, *tma;
1057{
1058 proftime_T tm3 = prof_wait_time;
1059
1060 profile_sub(&tm3, tm);
1061 profile_sub(tma, &tm3);
1062}
1063
1064/*
1065 * Return TRUE if "tm1" and "tm2" are equal.
1066 */
1067 int
1068profile_equal(tm1, tm2)
1069 proftime_T *tm1, *tm2;
1070{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001071# ifdef WIN3264
1072 return (tm1->QuadPart == tm2->QuadPart);
1073# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001074 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001075# endif
1076}
1077
1078/*
1079 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1080 */
1081 int
1082profile_cmp(tm1, tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001083 const proftime_T *tm1, *tm2;
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001084{
1085# ifdef WIN3264
1086 return (int)(tm2->QuadPart - tm1->QuadPart);
1087# else
1088 if (tm1->tv_sec == tm2->tv_sec)
1089 return tm2->tv_usec - tm1->tv_usec;
1090 return tm2->tv_sec - tm1->tv_sec;
1091# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001092}
1093
Bram Moolenaar05159a02005-02-26 23:04:13 +00001094static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001095static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001096
1097/*
1098 * ":profile cmd args"
1099 */
1100 void
1101ex_profile(eap)
1102 exarg_T *eap;
1103{
1104 char_u *e;
1105 int len;
1106
1107 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001108 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001109 e = skipwhite(e);
1110
1111 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1112 {
1113 vim_free(profile_fname);
1114 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001115 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001116 profile_zero(&prof_wait_time);
1117 set_vim_var_nr(VV_PROFILING, 1L);
1118 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001119 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001120 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001121 else if (STRCMP(eap->arg, "pause") == 0)
1122 {
1123 if (do_profiling == PROF_YES)
1124 profile_start(&pause_time);
1125 do_profiling = PROF_PAUSED;
1126 }
1127 else if (STRCMP(eap->arg, "continue") == 0)
1128 {
1129 if (do_profiling == PROF_PAUSED)
1130 {
1131 profile_end(&pause_time);
1132 profile_add(&prof_wait_time, &pause_time);
1133 }
1134 do_profiling = PROF_YES;
1135 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001136 else
1137 {
1138 /* The rest is similar to ":breakadd". */
1139 ex_breakadd(eap);
1140 }
1141}
1142
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001143/* Command line expansion for :profile. */
1144static enum
1145{
1146 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001147 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001148} pexpand_what;
1149
1150static char *pexpand_cmds[] = {
1151 "start",
1152#define PROFCMD_START 0
1153 "pause",
1154#define PROFCMD_PAUSE 1
1155 "continue",
1156#define PROFCMD_CONTINUE 2
1157 "func",
1158#define PROFCMD_FUNC 3
1159 "file",
1160#define PROFCMD_FILE 4
1161 NULL
1162#define PROFCMD_LAST 5
1163};
1164
1165/*
1166 * Function given to ExpandGeneric() to obtain the profile command
1167 * specific expansion.
1168 */
1169 char_u *
1170get_profile_name(xp, idx)
1171 expand_T *xp UNUSED;
1172 int idx;
1173{
1174 switch (pexpand_what)
1175 {
1176 case PEXP_SUBCMD:
1177 return (char_u *)pexpand_cmds[idx];
1178 /* case PEXP_FUNC: TODO */
1179 default:
1180 return NULL;
1181 }
1182}
1183
1184/*
1185 * Handle command line completion for :profile command.
1186 */
1187 void
1188set_context_in_profile_cmd(xp, arg)
1189 expand_T *xp;
1190 char_u *arg;
1191{
1192 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001193
1194 /* Default: expand subcommands. */
1195 xp->xp_context = EXPAND_PROFILE;
1196 pexpand_what = PEXP_SUBCMD;
1197 xp->xp_pattern = arg;
1198
1199 end_subcmd = skiptowhite(arg);
1200 if (*end_subcmd == NUL)
1201 return;
1202
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001203 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001204 {
1205 xp->xp_context = EXPAND_FILES;
1206 xp->xp_pattern = skipwhite(end_subcmd);
1207 return;
1208 }
1209
1210 /* TODO: expand function names after "func" */
1211 xp->xp_context = EXPAND_NOTHING;
1212}
1213
Bram Moolenaar05159a02005-02-26 23:04:13 +00001214/*
1215 * Dump the profiling info.
1216 */
1217 void
1218profile_dump()
1219{
1220 FILE *fd;
1221
1222 if (profile_fname != NULL)
1223 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001224 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001225 if (fd == NULL)
1226 EMSG2(_(e_notopen), profile_fname);
1227 else
1228 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001229 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001230 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001231 fclose(fd);
1232 }
1233 }
1234}
1235
1236/*
1237 * Start profiling script "fp".
1238 */
1239 static void
1240script_do_profile(si)
1241 scriptitem_T *si;
1242{
1243 si->sn_pr_count = 0;
1244 profile_zero(&si->sn_pr_total);
1245 profile_zero(&si->sn_pr_self);
1246
1247 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1248 si->sn_prl_idx = -1;
1249 si->sn_prof_on = TRUE;
1250 si->sn_pr_nest = 0;
1251}
1252
1253/*
1254 * save time when starting to invoke another script or function.
1255 */
1256 void
1257script_prof_save(tm)
1258 proftime_T *tm; /* place to store wait time */
1259{
1260 scriptitem_T *si;
1261
1262 if (current_SID > 0 && current_SID <= script_items.ga_len)
1263 {
1264 si = &SCRIPT_ITEM(current_SID);
1265 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1266 profile_start(&si->sn_pr_child);
1267 }
1268 profile_get_wait(tm);
1269}
1270
1271/*
1272 * Count time spent in children after invoking another script or function.
1273 */
1274 void
1275script_prof_restore(tm)
1276 proftime_T *tm;
1277{
1278 scriptitem_T *si;
1279
1280 if (current_SID > 0 && current_SID <= script_items.ga_len)
1281 {
1282 si = &SCRIPT_ITEM(current_SID);
1283 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1284 {
1285 profile_end(&si->sn_pr_child);
1286 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1287 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1288 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1289 }
1290 }
1291}
1292
1293static proftime_T inchar_time;
1294
1295/*
1296 * Called when starting to wait for the user to type a character.
1297 */
1298 void
1299prof_inchar_enter()
1300{
1301 profile_start(&inchar_time);
1302}
1303
1304/*
1305 * Called when finished waiting for the user to type a character.
1306 */
1307 void
1308prof_inchar_exit()
1309{
1310 profile_end(&inchar_time);
1311 profile_add(&prof_wait_time, &inchar_time);
1312}
1313
1314/*
1315 * Dump the profiling results for all scripts in file "fd".
1316 */
1317 static void
1318script_dump_profile(fd)
1319 FILE *fd;
1320{
1321 int id;
1322 scriptitem_T *si;
1323 int i;
1324 FILE *sfd;
1325 sn_prl_T *pp;
1326
1327 for (id = 1; id <= script_items.ga_len; ++id)
1328 {
1329 si = &SCRIPT_ITEM(id);
1330 if (si->sn_prof_on)
1331 {
1332 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1333 if (si->sn_pr_count == 1)
1334 fprintf(fd, "Sourced 1 time\n");
1335 else
1336 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1337 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1338 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1339 fprintf(fd, "\n");
1340 fprintf(fd, "count total (s) self (s)\n");
1341
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001342 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001343 if (sfd == NULL)
1344 fprintf(fd, "Cannot open file!\n");
1345 else
1346 {
1347 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1348 {
1349 if (vim_fgets(IObuff, IOSIZE, sfd))
1350 break;
1351 pp = &PRL_ITEM(si, i);
1352 if (pp->snp_count > 0)
1353 {
1354 fprintf(fd, "%5d ", pp->snp_count);
1355 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1356 fprintf(fd, " ");
1357 else
1358 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1359 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1360 }
1361 else
1362 fprintf(fd, " ");
1363 fprintf(fd, "%s", IObuff);
1364 }
1365 fclose(sfd);
1366 }
1367 fprintf(fd, "\n");
1368 }
1369 }
1370}
1371
1372/*
1373 * Return TRUE when a function defined in the current script should be
1374 * profiled.
1375 */
1376 int
1377prof_def_func()
1378{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001379 if (current_SID > 0)
1380 return SCRIPT_ITEM(current_SID).sn_pr_force;
1381 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001382}
1383
1384# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001385#endif
1386
1387/*
1388 * If 'autowrite' option set, try to write the file.
1389 * Careful: autocommands may make "buf" invalid!
1390 *
1391 * return FAIL for failure, OK otherwise
1392 */
1393 int
1394autowrite(buf, forceit)
1395 buf_T *buf;
1396 int forceit;
1397{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001398 int r;
1399
Bram Moolenaar071d4272004-06-13 20:20:40 +00001400 if (!(p_aw || p_awa) || !p_write
1401#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001402 /* never autowrite a "nofile" or "nowrite" buffer */
1403 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001404#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001405 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001406 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001407 r = buf_write_all(buf, forceit);
1408
1409 /* Writing may succeed but the buffer still changed, e.g., when there is a
1410 * conversion error. We do want to return FAIL then. */
1411 if (buf_valid(buf) && bufIsChanged(buf))
1412 r = FAIL;
1413 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001414}
1415
1416/*
1417 * flush all buffers, except the ones that are readonly
1418 */
1419 void
1420autowrite_all()
1421{
1422 buf_T *buf;
1423
1424 if (!(p_aw || p_awa) || !p_write)
1425 return;
1426 for (buf = firstbuf; buf; buf = buf->b_next)
1427 if (bufIsChanged(buf) && !buf->b_p_ro)
1428 {
1429 (void)buf_write_all(buf, FALSE);
1430#ifdef FEAT_AUTOCMD
1431 /* an autocommand may have deleted the buffer */
1432 if (!buf_valid(buf))
1433 buf = firstbuf;
1434#endif
1435 }
1436}
1437
1438/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001439 * Return TRUE if buffer was changed and cannot be abandoned.
1440 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001441 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001442 int
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001443check_changed(buf, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001444 buf_T *buf;
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001445 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001447 int forceit = (flags & CCGD_FORCEIT);
1448
Bram Moolenaar071d4272004-06-13 20:20:40 +00001449 if ( !forceit
1450 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001451 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1452 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001453 {
1454#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1455 if ((p_confirm || cmdmod.confirm) && p_write)
1456 {
1457 buf_T *buf2;
1458 int count = 0;
1459
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001460 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001461 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1462 if (bufIsChanged(buf2)
1463 && (buf2->b_ffname != NULL
1464# ifdef FEAT_BROWSE
1465 || cmdmod.browse
1466# endif
1467 ))
1468 ++count;
1469# ifdef FEAT_AUTOCMD
1470 if (!buf_valid(buf))
1471 /* Autocommand deleted buffer, oops! It's not changed now. */
1472 return FALSE;
1473# endif
1474 dialog_changed(buf, count > 1);
1475# ifdef FEAT_AUTOCMD
1476 if (!buf_valid(buf))
1477 /* Autocommand deleted buffer, oops! It's not changed now. */
1478 return FALSE;
1479# endif
1480 return bufIsChanged(buf);
1481 }
1482#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001483 if (flags & CCGD_EXCMD)
1484 EMSG(_(e_nowrtmsg));
1485 else
1486 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001487 return TRUE;
1488 }
1489 return FALSE;
1490}
1491
1492#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1493
1494#if defined(FEAT_BROWSE) || defined(PROTO)
1495/*
1496 * When wanting to write a file without a file name, ask the user for a name.
1497 */
1498 void
1499browse_save_fname(buf)
1500 buf_T *buf;
1501{
1502 if (buf->b_fname == NULL)
1503 {
1504 char_u *fname;
1505
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001506 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1507 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001508 if (fname != NULL)
1509 {
1510 if (setfname(buf, fname, NULL, TRUE) == OK)
1511 buf->b_flags |= BF_NOTEDITED;
1512 vim_free(fname);
1513 }
1514 }
1515}
1516#endif
1517
1518/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001519 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001520 * Must check 'write' option first!
1521 */
1522 void
1523dialog_changed(buf, checkall)
1524 buf_T *buf;
1525 int checkall; /* may abandon all changed buffers */
1526{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001527 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001528 int ret;
1529 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001530 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001531
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001532 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001533 (buf->b_fname != NULL) ?
1534 buf->b_fname : (char_u *)_("Untitled"));
1535 if (checkall)
1536 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1537 else
1538 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1539
Bram Moolenaar8218f602012-04-25 17:32:18 +02001540 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1541 * function. */
1542 ea.append = ea.forceit = FALSE;
1543
Bram Moolenaar071d4272004-06-13 20:20:40 +00001544 if (ret == VIM_YES)
1545 {
1546#ifdef FEAT_BROWSE
1547 /* May get file name, when there is none */
1548 browse_save_fname(buf);
1549#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001550 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1551 buf->b_fname, buf->b_ffname, FALSE) == OK)
1552 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001553 (void)buf_write_all(buf, FALSE);
1554 }
1555 else if (ret == VIM_NO)
1556 {
1557 unchanged(buf, TRUE);
1558 }
1559 else if (ret == VIM_ALL)
1560 {
1561 /*
1562 * Write all modified files that can be written.
1563 * Skip readonly buffers, these need to be confirmed
1564 * individually.
1565 */
1566 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1567 {
1568 if (bufIsChanged(buf2)
1569 && (buf2->b_ffname != NULL
1570#ifdef FEAT_BROWSE
1571 || cmdmod.browse
1572#endif
1573 )
1574 && !buf2->b_p_ro)
1575 {
1576#ifdef FEAT_BROWSE
1577 /* May get file name, when there is none */
1578 browse_save_fname(buf2);
1579#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001580 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1581 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1582 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583 (void)buf_write_all(buf2, FALSE);
1584#ifdef FEAT_AUTOCMD
1585 /* an autocommand may have deleted the buffer */
1586 if (!buf_valid(buf2))
1587 buf2 = firstbuf;
1588#endif
1589 }
1590 }
1591 }
1592 else if (ret == VIM_DISCARDALL)
1593 {
1594 /*
1595 * mark all buffers as unchanged
1596 */
1597 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1598 unchanged(buf2, TRUE);
1599 }
1600}
1601#endif
1602
1603/*
1604 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1605 * hidden, autowriting it or unloading it.
1606 */
1607 int
1608can_abandon(buf, forceit)
1609 buf_T *buf;
1610 int forceit;
1611{
1612 return ( P_HID(buf)
1613 || !bufIsChanged(buf)
1614 || buf->b_nwindows > 1
1615 || autowrite(buf, forceit) == OK
1616 || forceit);
1617}
1618
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001619static void add_bufnum __ARGS((int *bufnrs, int *bufnump, int nr));
1620
1621/*
1622 * Add a buffer number to "bufnrs", unless it's already there.
1623 */
1624 static void
1625add_bufnum(bufnrs, bufnump, nr)
1626 int *bufnrs;
1627 int *bufnump;
1628 int nr;
1629{
1630 int i;
1631
1632 for (i = 0; i < *bufnump; ++i)
1633 if (bufnrs[i] == nr)
1634 return;
1635 bufnrs[*bufnump] = nr;
1636 *bufnump = *bufnump + 1;
1637}
1638
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639/*
1640 * Return TRUE if any buffer was changed and cannot be abandoned.
1641 * That changed buffer becomes the current buffer.
1642 */
1643 int
1644check_changed_any(hidden)
1645 int hidden; /* Only check hidden buffers */
1646{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001647 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648 buf_T *buf;
1649 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001650 int i;
1651 int bufnum = 0;
1652 int bufcount = 0;
1653 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001655 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001656 win_T *wp;
1657#endif
1658
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001659 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1660 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001662 if (bufcount == 0)
1663 return FALSE;
1664
1665 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1666 if (bufnrs == NULL)
1667 return FALSE;
1668
1669 /* curbuf */
1670 bufnrs[bufnum++] = curbuf->b_fnum;
1671#ifdef FEAT_WINDOWS
1672 /* buf in curtab */
1673 FOR_ALL_WINDOWS(wp)
1674 if (wp->w_buffer != curbuf)
1675 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1676
1677 /* buf in other tab */
1678 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1679 if (tp != curtab)
1680 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1681 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1682#endif
1683 /* any other buf */
1684 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1685 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1686
1687 for (i = 0; i < bufnum; ++i)
1688 {
1689 buf = buflist_findnr(bufnrs[i]);
1690 if (buf == NULL)
1691 continue;
1692 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1693 {
1694 /* Try auto-writing the buffer. If this fails but the buffer no
1695 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001696 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1697 | CCGD_MULTWIN
1698 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001699 break; /* didn't save - still changes */
1700 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001701 }
1702
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001703 if (i >= bufnum)
1704 goto theend;
1705
1706 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001707 exiting = FALSE;
1708#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1709 /*
1710 * When ":confirm" used, don't give an error message.
1711 */
1712 if (!(p_confirm || cmdmod.confirm))
1713#endif
1714 {
1715 /* There must be a wait_return for this message, do_buffer()
1716 * may cause a redraw. But wait_return() is a no-op when vgetc()
1717 * is busy (Quit used from window menu), then make sure we don't
1718 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001719 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720 {
1721 msg_row = cmdline_row;
1722 msg_col = 0;
1723 msg_didout = FALSE;
1724 }
1725 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001726 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001727 {
1728 save = no_wait_return;
1729 no_wait_return = FALSE;
1730 wait_return(FALSE);
1731 no_wait_return = save;
1732 }
1733 }
1734
1735#ifdef FEAT_WINDOWS
1736 /* Try to find a window that contains the buffer. */
1737 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001738 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739 if (wp->w_buffer == buf)
1740 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001741 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742# ifdef FEAT_AUTOCMD
1743 /* Paranoia: did autocms wipe out the buffer with changes? */
1744 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001745 {
1746 goto theend;
1747 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001749 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001751buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752#endif
1753
1754 /* Open the changed buffer in the current window. */
1755 if (buf != curbuf)
1756 set_curbuf(buf, DOBUF_GOTO);
1757
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001758theend:
1759 vim_free(bufnrs);
1760 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761}
1762
1763/*
1764 * return FAIL if there is no file name, OK if there is one
1765 * give error message for FAIL
1766 */
1767 int
1768check_fname()
1769{
1770 if (curbuf->b_ffname == NULL)
1771 {
1772 EMSG(_(e_noname));
1773 return FAIL;
1774 }
1775 return OK;
1776}
1777
1778/*
1779 * flush the contents of a buffer, unless it has no file name
1780 *
1781 * return FAIL for failure, OK otherwise
1782 */
1783 int
1784buf_write_all(buf, forceit)
1785 buf_T *buf;
1786 int forceit;
1787{
1788 int retval;
1789#ifdef FEAT_AUTOCMD
1790 buf_T *old_curbuf = curbuf;
1791#endif
1792
1793 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1794 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1795 FALSE, forceit, TRUE, FALSE));
1796#ifdef FEAT_AUTOCMD
1797 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001798 {
1799 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001801 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802#endif
1803 return retval;
1804}
1805
1806/*
1807 * Code to handle the argument list.
1808 */
1809
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001810static char_u *do_one_arg __ARGS((char_u *str));
1811static int do_arglist __ARGS((char_u *str, int what, int after));
1812static void alist_check_arg_idx __ARGS((void));
1813static int editing_arg_idx __ARGS((win_T *win));
1814#ifdef FEAT_LISTCMDS
1815static int alist_add_list __ARGS((int count, char_u **files, int after));
1816#endif
1817#define AL_SET 1
1818#define AL_ADD 2
1819#define AL_DEL 3
1820
Bram Moolenaar071d4272004-06-13 20:20:40 +00001821/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001822 * Isolate one argument, taking backticks.
1823 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824 * Return a pointer to the start of the next argument.
1825 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001826 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827do_one_arg(str)
1828 char_u *str;
1829{
1830 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831 int inbacktick;
1832
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833 inbacktick = FALSE;
1834 for (p = str; *str; ++str)
1835 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001836 /* When the backslash is used for escaping the special meaning of a
1837 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 if (rem_backslash(str))
1839 {
1840 *p++ = *str++;
1841 *p++ = *str;
1842 }
1843 else
1844 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001845 /* An item ends at a space not in backticks */
1846 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001848 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001850 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851 }
1852 }
1853 str = skipwhite(str);
1854 *p = NUL;
1855
1856 return str;
1857}
1858
Bram Moolenaar86b68352004-12-27 21:59:20 +00001859/*
1860 * Separate the arguments in "str" and return a list of pointers in the
1861 * growarray "gap".
1862 */
1863 int
1864get_arglist(gap, str)
1865 garray_T *gap;
1866 char_u *str;
1867{
1868 ga_init2(gap, (int)sizeof(char_u *), 20);
1869 while (*str != NUL)
1870 {
1871 if (ga_grow(gap, 1) == FAIL)
1872 {
1873 ga_clear(gap);
1874 return FAIL;
1875 }
1876 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1877
1878 /* Isolate one argument, change it in-place, put a NUL after it. */
1879 str = do_one_arg(str);
1880 }
1881 return OK;
1882}
1883
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001884#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001885/*
1886 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001887 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001888 * Return FAIL or OK.
1889 */
1890 int
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001891get_arglist_exp(str, fcountp, fnamesp, wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001892 char_u *str;
1893 int *fcountp;
1894 char_u ***fnamesp;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001895 int wig;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001896{
1897 garray_T ga;
1898 int i;
1899
1900 if (get_arglist(&ga, str) == FAIL)
1901 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001902 if (wig == TRUE)
1903 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1904 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1905 else
1906 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1907 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1908
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001909 ga_clear(&ga);
1910 return i;
1911}
1912#endif
1913
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1915/*
1916 * Redefine the argument list.
1917 */
1918 void
1919set_arglist(str)
1920 char_u *str;
1921{
1922 do_arglist(str, AL_SET, 0);
1923}
1924#endif
1925
1926/*
1927 * "what" == AL_SET: Redefine the argument list to 'str'.
1928 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1929 * "what" == AL_DEL: remove files in 'str' from the argument list.
1930 *
1931 * Return FAIL for failure, OK otherwise.
1932 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 static int
1934do_arglist(str, what, after)
1935 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001936 int what UNUSED;
1937 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938{
1939 garray_T new_ga;
1940 int exp_count;
1941 char_u **exp_files;
1942 int i;
1943#ifdef FEAT_LISTCMDS
1944 char_u *p;
1945 int match;
1946#endif
1947
1948 /*
1949 * Collect all file name arguments in "new_ga".
1950 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001951 if (get_arglist(&new_ga, str) == FAIL)
1952 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953
1954#ifdef FEAT_LISTCMDS
1955 if (what == AL_DEL)
1956 {
1957 regmatch_T regmatch;
1958 int didone;
1959
1960 /*
1961 * Delete the items: use each item as a regexp and find a match in the
1962 * argument list.
1963 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01001964 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1966 {
1967 p = ((char_u **)new_ga.ga_data)[i];
1968 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1969 if (p == NULL)
1970 break;
1971 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1972 if (regmatch.regprog == NULL)
1973 {
1974 vim_free(p);
1975 break;
1976 }
1977
1978 didone = FALSE;
1979 for (match = 0; match < ARGCOUNT; ++match)
1980 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1981 (colnr_T)0))
1982 {
1983 didone = TRUE;
1984 vim_free(ARGLIST[match].ae_fname);
1985 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1986 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1987 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988 if (curwin->w_arg_idx > match)
1989 --curwin->w_arg_idx;
1990 --match;
1991 }
1992
Bram Moolenaar473de612013-06-08 18:19:48 +02001993 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001994 vim_free(p);
1995 if (!didone)
1996 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1997 }
1998 ga_clear(&new_ga);
1999 }
2000 else
2001#endif
2002 {
2003 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2004 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2005 ga_clear(&new_ga);
2006 if (i == FAIL)
2007 return FAIL;
2008 if (exp_count == 0)
2009 {
2010 EMSG(_(e_nomatch));
2011 return FAIL;
2012 }
2013
2014#ifdef FEAT_LISTCMDS
2015 if (what == AL_ADD)
2016 {
2017 (void)alist_add_list(exp_count, exp_files, after);
2018 vim_free(exp_files);
2019 }
2020 else /* what == AL_SET */
2021#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002022 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023 }
2024
2025 alist_check_arg_idx();
2026
2027 return OK;
2028}
2029
2030/*
2031 * Check the validity of the arg_idx for each other window.
2032 */
2033 static void
2034alist_check_arg_idx()
2035{
2036#ifdef FEAT_WINDOWS
2037 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002038 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039
Bram Moolenaarf740b292006-02-16 22:11:02 +00002040 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002041 if (win->w_alist == curwin->w_alist)
2042 check_arg_idx(win);
2043#else
2044 check_arg_idx(curwin);
2045#endif
2046}
2047
2048/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002049 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002050 * index.
2051 */
2052 static int
2053editing_arg_idx(win)
2054 win_T *win;
2055{
2056 return !(win->w_arg_idx >= WARGCOUNT(win)
2057 || (win->w_buffer->b_fnum
2058 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2059 && (win->w_buffer->b_ffname == NULL
2060 || !(fullpathcmp(
2061 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2062 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2063}
2064
2065/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002066 * Check if window "win" is editing the w_arg_idx file in its argument list.
2067 */
2068 void
2069check_arg_idx(win)
2070 win_T *win;
2071{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002072 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073 {
2074 /* We are not editing the current entry in the argument list.
2075 * Set "arg_had_last" if we are editing the last one. */
2076 win->w_arg_idx_invalid = TRUE;
2077 if (win->w_arg_idx != WARGCOUNT(win) - 1
2078 && arg_had_last == FALSE
2079#ifdef FEAT_WINDOWS
2080 && ALIST(win) == &global_alist
2081#endif
2082 && GARGCOUNT > 0
2083 && win->w_arg_idx < GARGCOUNT
2084 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2085 || (win->w_buffer->b_ffname != NULL
2086 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2087 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2088 arg_had_last = TRUE;
2089 }
2090 else
2091 {
2092 /* We are editing the current entry in the argument list.
2093 * Set "arg_had_last" if it's also the last one */
2094 win->w_arg_idx_invalid = FALSE;
2095 if (win->w_arg_idx == WARGCOUNT(win) - 1
2096#ifdef FEAT_WINDOWS
2097 && win->w_alist == &global_alist
2098#endif
2099 )
2100 arg_had_last = TRUE;
2101 }
2102}
2103
2104/*
2105 * ":args", ":argslocal" and ":argsglobal".
2106 */
2107 void
2108ex_args(eap)
2109 exarg_T *eap;
2110{
2111 int i;
2112
2113 if (eap->cmdidx != CMD_args)
2114 {
2115#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2116 alist_unlink(ALIST(curwin));
2117 if (eap->cmdidx == CMD_argglobal)
2118 ALIST(curwin) = &global_alist;
2119 else /* eap->cmdidx == CMD_arglocal */
2120 alist_new();
2121#else
2122 ex_ni(eap);
2123 return;
2124#endif
2125 }
2126
2127 if (!ends_excmd(*eap->arg))
2128 {
2129 /*
2130 * ":args file ..": define new argument list, handle like ":next"
2131 * Also for ":argslocal file .." and ":argsglobal file ..".
2132 */
2133 ex_next(eap);
2134 }
2135 else
2136#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2137 if (eap->cmdidx == CMD_args)
2138#endif
2139 {
2140 /*
2141 * ":args": list arguments.
2142 */
2143 if (ARGCOUNT > 0)
2144 {
2145 /* Overwrite the command, for a short list there is no scrolling
2146 * required and no wait_return(). */
2147 gotocmdline(TRUE);
2148 for (i = 0; i < ARGCOUNT; ++i)
2149 {
2150 if (i == curwin->w_arg_idx)
2151 msg_putchar('[');
2152 msg_outtrans(alist_name(&ARGLIST[i]));
2153 if (i == curwin->w_arg_idx)
2154 msg_putchar(']');
2155 msg_putchar(' ');
2156 }
2157 }
2158 }
2159#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2160 else if (eap->cmdidx == CMD_arglocal)
2161 {
2162 garray_T *gap = &curwin->w_alist->al_ga;
2163
2164 /*
2165 * ":argslocal": make a local copy of the global argument list.
2166 */
2167 if (ga_grow(gap, GARGCOUNT) == OK)
2168 for (i = 0; i < GARGCOUNT; ++i)
2169 if (GARGLIST[i].ae_fname != NULL)
2170 {
2171 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2172 vim_strsave(GARGLIST[i].ae_fname);
2173 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2174 GARGLIST[i].ae_fnum;
2175 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002176 }
2177 }
2178#endif
2179}
2180
2181/*
2182 * ":previous", ":sprevious", ":Next" and ":sNext".
2183 */
2184 void
2185ex_previous(eap)
2186 exarg_T *eap;
2187{
2188 /* If past the last one already, go to the last one. */
2189 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2190 do_argfile(eap, ARGCOUNT - 1);
2191 else
2192 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2193}
2194
2195/*
2196 * ":rewind", ":first", ":sfirst" and ":srewind".
2197 */
2198 void
2199ex_rewind(eap)
2200 exarg_T *eap;
2201{
2202 do_argfile(eap, 0);
2203}
2204
2205/*
2206 * ":last" and ":slast".
2207 */
2208 void
2209ex_last(eap)
2210 exarg_T *eap;
2211{
2212 do_argfile(eap, ARGCOUNT - 1);
2213}
2214
2215/*
2216 * ":argument" and ":sargument".
2217 */
2218 void
2219ex_argument(eap)
2220 exarg_T *eap;
2221{
2222 int i;
2223
2224 if (eap->addr_count > 0)
2225 i = eap->line2 - 1;
2226 else
2227 i = curwin->w_arg_idx;
2228 do_argfile(eap, i);
2229}
2230
2231/*
2232 * Edit file "argn" of the argument lists.
2233 */
2234 void
2235do_argfile(eap, argn)
2236 exarg_T *eap;
2237 int argn;
2238{
2239 int other;
2240 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002241 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002242
2243 if (argn < 0 || argn >= ARGCOUNT)
2244 {
2245 if (ARGCOUNT <= 1)
2246 EMSG(_("E163: There is only one file to edit"));
2247 else if (argn < 0)
2248 EMSG(_("E164: Cannot go before first file"));
2249 else
2250 EMSG(_("E165: Cannot go beyond last file"));
2251 }
2252 else
2253 {
2254 setpcmark();
2255#ifdef FEAT_GUI
2256 need_mouse_correct = TRUE;
2257#endif
2258
2259#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002260 /* split window or create new tab page first */
2261 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262 {
2263 if (win_split(0, 0) == FAIL)
2264 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002265 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 }
2267 else
2268#endif
2269 {
2270 /*
2271 * if 'hidden' set, only check for changed file when re-editing
2272 * the same buffer
2273 */
2274 other = TRUE;
2275 if (P_HID(curbuf))
2276 {
2277 p = fix_fname(alist_name(&ARGLIST[argn]));
2278 other = otherfile(p);
2279 vim_free(p);
2280 }
2281 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002282 && check_changed(curbuf, CCGD_AW
2283 | (other ? 0 : CCGD_MULTWIN)
2284 | (eap->forceit ? CCGD_FORCEIT : 0)
2285 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 return;
2287 }
2288
2289 curwin->w_arg_idx = argn;
2290 if (argn == ARGCOUNT - 1
2291#ifdef FEAT_WINDOWS
2292 && curwin->w_alist == &global_alist
2293#endif
2294 )
2295 arg_had_last = TRUE;
2296
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002297 /* Edit the file; always use the last known line number.
2298 * When it fails (e.g. Abort for already edited file) restore the
2299 * argument index. */
2300 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002302 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2303 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002304 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002306 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307 setmark('\'');
2308 }
2309}
2310
2311/*
2312 * ":next", and commands that behave like it.
2313 */
2314 void
2315ex_next(eap)
2316 exarg_T *eap;
2317{
2318 int i;
2319
2320 /*
2321 * check for changed buffer now, if this fails the argument list is not
2322 * redefined.
2323 */
2324 if ( P_HID(curbuf)
2325 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002326 || !check_changed(curbuf, CCGD_AW
2327 | (eap->forceit ? CCGD_FORCEIT : 0)
2328 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329 {
2330 if (*eap->arg != NUL) /* redefine file list */
2331 {
2332 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2333 return;
2334 i = 0;
2335 }
2336 else
2337 i = curwin->w_arg_idx + (int)eap->line2;
2338 do_argfile(eap, i);
2339 }
2340}
2341
2342#ifdef FEAT_LISTCMDS
2343/*
2344 * ":argedit"
2345 */
2346 void
2347ex_argedit(eap)
2348 exarg_T *eap;
2349{
2350 int fnum;
2351 int i;
2352 char_u *s;
2353
2354 /* Add the argument to the buffer list and get the buffer number. */
2355 fnum = buflist_add(eap->arg, BLN_LISTED);
2356
2357 /* Check if this argument is already in the argument list. */
2358 for (i = 0; i < ARGCOUNT; ++i)
2359 if (ARGLIST[i].ae_fnum == fnum)
2360 break;
2361 if (i == ARGCOUNT)
2362 {
2363 /* Can't find it, add it to the argument list. */
2364 s = vim_strsave(eap->arg);
2365 if (s == NULL)
2366 return;
2367 i = alist_add_list(1, &s,
2368 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2369 if (i < 0)
2370 return;
2371 curwin->w_arg_idx = i;
2372 }
2373
2374 alist_check_arg_idx();
2375
2376 /* Edit the argument. */
2377 do_argfile(eap, i);
2378}
2379
2380/*
2381 * ":argadd"
2382 */
2383 void
2384ex_argadd(eap)
2385 exarg_T *eap;
2386{
2387 do_arglist(eap->arg, AL_ADD,
2388 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2389#ifdef FEAT_TITLE
2390 maketitle();
2391#endif
2392}
2393
2394/*
2395 * ":argdelete"
2396 */
2397 void
2398ex_argdelete(eap)
2399 exarg_T *eap;
2400{
2401 int i;
2402 int n;
2403
2404 if (eap->addr_count > 0)
2405 {
2406 /* ":1,4argdel": Delete all arguments in the range. */
2407 if (eap->line2 > ARGCOUNT)
2408 eap->line2 = ARGCOUNT;
2409 n = eap->line2 - eap->line1 + 1;
2410 if (*eap->arg != NUL || n <= 0)
2411 EMSG(_(e_invarg));
2412 else
2413 {
2414 for (i = eap->line1; i <= eap->line2; ++i)
2415 vim_free(ARGLIST[i - 1].ae_fname);
2416 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2417 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2418 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002419 if (curwin->w_arg_idx >= eap->line2)
2420 curwin->w_arg_idx -= n;
2421 else if (curwin->w_arg_idx > eap->line1)
2422 curwin->w_arg_idx = eap->line1;
2423 }
2424 }
2425 else if (*eap->arg == NUL)
2426 EMSG(_(e_argreq));
2427 else
2428 do_arglist(eap->arg, AL_DEL, 0);
2429#ifdef FEAT_TITLE
2430 maketitle();
2431#endif
2432}
2433
2434/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002435 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002436 */
2437 void
2438ex_listdo(eap)
2439 exarg_T *eap;
2440{
2441 int i;
2442#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002443 win_T *wp;
2444 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002445#endif
2446 buf_T *buf;
2447 int next_fnum = 0;
2448#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2449 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002451 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452
2453#ifndef FEAT_WINDOWS
2454 if (eap->cmdidx == CMD_windo)
2455 {
2456 ex_ni(eap);
2457 return;
2458 }
2459#endif
2460
2461#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002462 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002463 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2464 * great speed improvement. */
2465 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002467#ifdef FEAT_CLIPBOARD
2468 start_global_changes();
2469#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470
2471 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002472 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002473 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002474 || !check_changed(curbuf, CCGD_AW
2475 | (eap->forceit ? CCGD_FORCEIT : 0)
2476 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 {
2478 /* start at the first argument/window/buffer */
2479 i = 0;
2480#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002481 wp = firstwin;
2482 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002483#endif
2484 /* set pcmark now */
2485 if (eap->cmdidx == CMD_bufdo)
2486 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2487 else
2488 setpcmark();
2489 listcmd_busy = TRUE; /* avoids setting pcmark below */
2490
2491 while (!got_int)
2492 {
2493 if (eap->cmdidx == CMD_argdo)
2494 {
2495 /* go to argument "i" */
2496 if (i == ARGCOUNT)
2497 break;
2498 /* Don't call do_argfile() when already there, it will try
2499 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002500 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002501 {
2502 /* Clear 'shm' to avoid that the file message overwrites
2503 * any output from the command. */
2504 p_shm_save = vim_strsave(p_shm);
2505 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002506 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002507 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2508 vim_free(p_shm_save);
2509 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510 if (curwin->w_arg_idx != i)
2511 break;
2512 ++i;
2513 }
2514#ifdef FEAT_WINDOWS
2515 else if (eap->cmdidx == CMD_windo)
2516 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002517 /* go to window "wp" */
2518 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002520 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002521 if (curwin != wp)
2522 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002523 wp = curwin->w_next;
2524 }
2525 else if (eap->cmdidx == CMD_tabdo)
2526 {
2527 /* go to window "tp" */
2528 if (!valid_tabpage(tp))
2529 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002530 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002531 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 }
2533#endif
2534 else if (eap->cmdidx == CMD_bufdo)
2535 {
2536 /* Remember the number of the next listed buffer, in case
2537 * ":bwipe" is used or autocommands do something strange. */
2538 next_fnum = -1;
2539 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2540 if (buf->b_p_bl)
2541 {
2542 next_fnum = buf->b_fnum;
2543 break;
2544 }
2545 }
2546
2547 /* execute the command */
2548 do_cmdline(eap->arg, eap->getline, eap->cookie,
2549 DOCMD_VERBOSE + DOCMD_NOWAIT);
2550
2551 if (eap->cmdidx == CMD_bufdo)
2552 {
2553 /* Done? */
2554 if (next_fnum < 0)
2555 break;
2556 /* Check if the buffer still exists. */
2557 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2558 if (buf->b_fnum == next_fnum)
2559 break;
2560 if (buf == NULL)
2561 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002562
2563 /* Go to the next buffer. Clear 'shm' to avoid that the file
2564 * message overwrites any output from the command. */
2565 p_shm_save = vim_strsave(p_shm);
2566 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002567 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002568 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2569 vim_free(p_shm_save);
2570
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 /* If autocommands took us elsewhere, quit here */
2572 if (curbuf->b_fnum != next_fnum)
2573 break;
2574 }
2575
2576 if (eap->cmdidx == CMD_windo)
2577 {
2578 validate_cursor(); /* cursor may have moved */
2579#ifdef FEAT_SCROLLBIND
2580 /* required when 'scrollbind' has been set */
2581 if (curwin->w_p_scb)
2582 do_check_scrollbind(TRUE);
2583#endif
2584 }
2585 }
2586 listcmd_busy = FALSE;
2587 }
2588
2589#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002590 if (save_ei != NULL)
2591 {
2592 au_event_restore(save_ei);
2593 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2594 curbuf->b_fname, TRUE, curbuf);
2595 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002597#ifdef FEAT_CLIPBOARD
2598 end_global_changes();
2599#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002600}
2601
2602/*
2603 * Add files[count] to the arglist of the current window after arg "after".
2604 * The file names in files[count] must have been allocated and are taken over.
2605 * Files[] itself is not taken over.
2606 * Returns index of first added argument. Returns -1 when failed (out of mem).
2607 */
2608 static int
2609alist_add_list(count, files, after)
2610 int count;
2611 char_u **files;
2612 int after; /* where to add: 0 = before first one */
2613{
2614 int i;
2615
2616 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2617 {
2618 if (after < 0)
2619 after = 0;
2620 if (after > ARGCOUNT)
2621 after = ARGCOUNT;
2622 if (after < ARGCOUNT)
2623 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2624 (ARGCOUNT - after) * sizeof(aentry_T));
2625 for (i = 0; i < count; ++i)
2626 {
2627 ARGLIST[after + i].ae_fname = files[i];
2628 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2629 }
2630 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002631 if (curwin->w_arg_idx >= after)
2632 ++curwin->w_arg_idx;
2633 return after;
2634 }
2635
2636 for (i = 0; i < count; ++i)
2637 vim_free(files[i]);
2638 return -1;
2639}
2640
2641#endif /* FEAT_LISTCMDS */
2642
2643#ifdef FEAT_EVAL
2644/*
2645 * ":compiler[!] {name}"
2646 */
2647 void
2648ex_compiler(eap)
2649 exarg_T *eap;
2650{
2651 char_u *buf;
2652 char_u *old_cur_comp = NULL;
2653 char_u *p;
2654
2655 if (*eap->arg == NUL)
2656 {
2657 /* List all compiler scripts. */
2658 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2659 /* ) keep the indenter happy... */
2660 }
2661 else
2662 {
2663 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2664 if (buf != NULL)
2665 {
2666 if (eap->forceit)
2667 {
2668 /* ":compiler! {name}" sets global options */
2669 do_cmdline_cmd((char_u *)
2670 "command -nargs=* CompilerSet set <args>");
2671 }
2672 else
2673 {
2674 /* ":compiler! {name}" sets local options.
2675 * To remain backwards compatible "current_compiler" is always
2676 * used. A user's compiler plugin may set it, the distributed
2677 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002678 * "b:current_compiler" and restore "current_compiler".
2679 * Explicitly prepend "g:" to make it work in a function. */
2680 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 if (old_cur_comp != NULL)
2682 old_cur_comp = vim_strsave(old_cur_comp);
2683 do_cmdline_cmd((char_u *)
2684 "command -nargs=* CompilerSet setlocal <args>");
2685 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002686 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002687 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688
2689 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002690 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002691 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2692 vim_free(buf);
2693
2694 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2695
2696 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002697 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 if (p != NULL)
2699 set_internal_string_var((char_u *)"b:current_compiler", p);
2700
2701 /* Restore "current_compiler" for ":compiler {name}". */
2702 if (!eap->forceit)
2703 {
2704 if (old_cur_comp != NULL)
2705 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002706 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707 old_cur_comp);
2708 vim_free(old_cur_comp);
2709 }
2710 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002711 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 }
2713 }
2714 }
2715}
2716#endif
2717
2718/*
2719 * ":runtime {name}"
2720 */
2721 void
2722ex_runtime(eap)
2723 exarg_T *eap;
2724{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002725 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726}
2727
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002728static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729
2730 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002731source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002732 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002733 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002735 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002736}
2737
2738/*
2739 * Source the file "name" from all directories in 'runtimepath'.
2740 * "name" can contain wildcards.
2741 * When "all" is TRUE, source all files, otherwise only the first one.
2742 * return FAIL when no file could be sourced, OK otherwise.
2743 */
2744 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002745source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746 char_u *name;
2747 int all;
2748{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002749 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002750}
2751
2752/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002753 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2754 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2756 * used.
2757 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002758 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002759 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2760 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002761 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002762 */
2763 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002764do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002765 char_u *name;
2766 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002767 void (*callback)__ARGS((char_u *fname, void *ck));
2768 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769{
2770 char_u *rtp;
2771 char_u *np;
2772 char_u *buf;
2773 char_u *rtp_copy;
2774 char_u *tail;
2775 int num_files;
2776 char_u **files;
2777 int i;
2778 int did_one = FALSE;
2779#ifdef AMIGA
2780 struct Process *proc = (struct Process *)FindTask(0L);
2781 APTR save_winptr = proc->pr_WindowPtr;
2782
2783 /* Avoid a requester here for a volume that doesn't exist. */
2784 proc->pr_WindowPtr = (APTR)-1L;
2785#endif
2786
2787 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2788 * value. */
2789 rtp_copy = vim_strsave(p_rtp);
2790 buf = alloc(MAXPATHL);
2791 if (buf != NULL && rtp_copy != NULL)
2792 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002793 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002794 {
2795 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002796 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002797 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002798 verbose_leave();
2799 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002800
Bram Moolenaar071d4272004-06-13 20:20:40 +00002801 /* Loop over all entries in 'runtimepath'. */
2802 rtp = rtp_copy;
2803 while (*rtp != NUL && (all || !did_one))
2804 {
2805 /* Copy the path from 'runtimepath' to buf[]. */
2806 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002807 if (name == NULL)
2808 {
2809 (*callback)(buf, (void *) &cookie);
2810 if (!did_one)
2811 did_one = (cookie == NULL);
2812 }
2813 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814 {
2815 add_pathsep(buf);
2816 tail = buf + STRLEN(buf);
2817
2818 /* Loop over all patterns in "name" */
2819 np = name;
2820 while (*np != NUL && (all || !did_one))
2821 {
2822 /* Append the pattern from "name" to buf[]. */
2823 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2824 "\t ");
2825
2826 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002827 {
2828 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002829 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002830 verbose_leave();
2831 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832
2833 /* Expand wildcards, invoke the callback for each match. */
2834 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2835 EW_FILE) == OK)
2836 {
2837 for (i = 0; i < num_files; ++i)
2838 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002839 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840 did_one = TRUE;
2841 if (!all)
2842 break;
2843 }
2844 FreeWild(num_files, files);
2845 }
2846 }
2847 }
2848 }
2849 }
2850 vim_free(buf);
2851 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002852 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002853 {
2854 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002855 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002856 verbose_leave();
2857 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002858
2859#ifdef AMIGA
2860 proc->pr_WindowPtr = save_winptr;
2861#endif
2862
2863 return did_one ? OK : FAIL;
2864}
2865
2866#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2867/*
2868 * ":options"
2869 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870 void
2871ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002872 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873{
2874 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2875}
2876#endif
2877
2878/*
2879 * ":source {fname}"
2880 */
2881 void
2882ex_source(eap)
2883 exarg_T *eap;
2884{
2885#ifdef FEAT_BROWSE
2886 if (cmdmod.browse)
2887 {
2888 char_u *fname = NULL;
2889
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002890 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2892 if (fname != NULL)
2893 {
2894 cmd_source(fname, eap);
2895 vim_free(fname);
2896 }
2897 }
2898 else
2899#endif
2900 cmd_source(eap->arg, eap);
2901}
2902
2903 static void
2904cmd_source(fname, eap)
2905 char_u *fname;
2906 exarg_T *eap;
2907{
2908 if (*fname == NUL)
2909 EMSG(_(e_argreq));
2910
Bram Moolenaar071d4272004-06-13 20:20:40 +00002911 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002912 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002913 * Need to execute the commands directly. This is required at least
2914 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915 * - ":g" command busy
2916 * - after ":argdo", ":windo" or ":bufdo"
2917 * - another command follows
2918 * - inside a loop
2919 */
2920 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2921#ifdef FEAT_EVAL
2922 || eap->cstack->cs_idx >= 0
2923#endif
2924 );
2925
2926 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002927 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928 EMSG2(_(e_notopen), fname);
2929}
2930
2931/*
2932 * ":source" and associated commands.
2933 */
2934/*
2935 * Structure used to store info for each sourced file.
2936 * It is shared between do_source() and getsourceline().
2937 * This is required, because it needs to be handed to do_cmdline() and
2938 * sourcing can be done recursively.
2939 */
2940struct source_cookie
2941{
2942 FILE *fp; /* opened file for sourcing */
2943 char_u *nextline; /* if not NULL: line that was read ahead */
2944 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002945#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2947 int error; /* TRUE if LF found after CR-LF */
2948#endif
2949#ifdef FEAT_EVAL
2950 linenr_T breakpoint; /* next line with breakpoint or zero */
2951 char_u *fname; /* name of sourced file */
2952 int dbg_tick; /* debug_tick when breakpoint was set */
2953 int level; /* top nesting level of sourced file */
2954#endif
2955#ifdef FEAT_MBYTE
2956 vimconv_T conv; /* type of conversion */
2957#endif
2958};
2959
2960#ifdef FEAT_EVAL
2961/*
2962 * Return the address holding the next breakpoint line for a source cookie.
2963 */
2964 linenr_T *
2965source_breakpoint(cookie)
2966 void *cookie;
2967{
2968 return &((struct source_cookie *)cookie)->breakpoint;
2969}
2970
2971/*
2972 * Return the address holding the debug tick for a source cookie.
2973 */
2974 int *
2975source_dbg_tick(cookie)
2976 void *cookie;
2977{
2978 return &((struct source_cookie *)cookie)->dbg_tick;
2979}
2980
2981/*
2982 * Return the nesting level for a source cookie.
2983 */
2984 int
2985source_level(cookie)
2986 void *cookie;
2987{
2988 return ((struct source_cookie *)cookie)->level;
2989}
2990#endif
2991
2992static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2993
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002994#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2995# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002996static FILE *fopen_noinh_readbin __ARGS((char *filename));
2997
2998/*
2999 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003000 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003001 */
3002 static FILE *
3003fopen_noinh_readbin(filename)
3004 char *filename;
3005{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003006# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003007 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3008# else
3009 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003010# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011
3012 if (fd_tmp == -1)
3013 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003014
3015# ifdef HAVE_FD_CLOEXEC
3016 {
3017 int fdflags = fcntl(fd_tmp, F_GETFD);
3018 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
3019 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
3020 }
3021# endif
3022
Bram Moolenaar071d4272004-06-13 20:20:40 +00003023 return fdopen(fd_tmp, READBIN);
3024}
3025#endif
3026
3027
3028/*
3029 * do_source: Read the file "fname" and execute its lines as EX commands.
3030 *
3031 * This function may be called recursively!
3032 *
3033 * return FAIL if file could not be opened, OK otherwise
3034 */
3035 int
3036do_source(fname, check_other, is_vimrc)
3037 char_u *fname;
3038 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003039 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040{
3041 struct source_cookie cookie;
3042 char_u *save_sourcing_name;
3043 linenr_T save_sourcing_lnum;
3044 char_u *p;
3045 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003046 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003047 int retval = FAIL;
3048#ifdef FEAT_EVAL
3049 scid_T save_current_SID;
3050 static scid_T last_current_SID = 0;
3051 void *save_funccalp;
3052 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003053 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003054# ifdef UNIX
3055 struct stat st;
3056 int stat_ok;
3057# endif
3058#endif
3059#ifdef STARTUPTIME
3060 struct timeval tv_rel;
3061 struct timeval tv_start;
3062#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003063#ifdef FEAT_PROFILE
3064 proftime_T wait_start;
3065#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068 if (p == NULL)
3069 return retval;
3070 fname_exp = fix_fname(p);
3071 vim_free(p);
3072 if (fname_exp == NULL)
3073 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 if (mch_isdir(fname_exp))
3075 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003076 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077 goto theend;
3078 }
3079
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003080#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003081 /* Apply SourceCmd autocommands, they should get the file and source it. */
3082 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3083 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3084 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003085 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003086# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003087 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003088# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003089 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003090# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003091 goto theend;
3092 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003093
3094 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003095 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3096#endif
3097
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003098#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003099 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3100#else
3101 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3102#endif
3103 if (cookie.fp == NULL && check_other)
3104 {
3105 /*
3106 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3107 * and ".exrc" by "_exrc" or vice versa.
3108 */
3109 p = gettail(fname_exp);
3110 if ((*p == '.' || *p == '_')
3111 && (STRICMP(p + 1, "vimrc") == 0
3112 || STRICMP(p + 1, "gvimrc") == 0
3113 || STRICMP(p + 1, "exrc") == 0))
3114 {
3115 if (*p == '_')
3116 *p = '.';
3117 else
3118 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003119#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003120 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3121#else
3122 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3123#endif
3124 }
3125 }
3126
3127 if (cookie.fp == NULL)
3128 {
3129 if (p_verbose > 0)
3130 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003131 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003133 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134 else
3135 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003136 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003137 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 }
3139 goto theend;
3140 }
3141
3142 /*
3143 * The file exists.
3144 * - In verbose mode, give a message.
3145 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3146 */
3147 if (p_verbose > 1)
3148 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003149 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003151 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152 else
3153 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003154 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003155 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003156 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003157 if (is_vimrc == DOSO_VIMRC)
3158 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3159 else if (is_vimrc == DOSO_GVIMRC)
3160 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003161
3162#ifdef USE_CRNL
3163 /* If no automatic file format: Set default to CR-NL. */
3164 if (*p_ffs == NUL)
3165 cookie.fileformat = EOL_DOS;
3166 else
3167 cookie.fileformat = EOL_UNKNOWN;
3168 cookie.error = FALSE;
3169#endif
3170
3171#ifdef USE_CR
3172 /* If no automatic file format: Set default to CR. */
3173 if (*p_ffs == NUL)
3174 cookie.fileformat = EOL_MAC;
3175 else
3176 cookie.fileformat = EOL_UNKNOWN;
3177 cookie.error = FALSE;
3178#endif
3179
3180 cookie.nextline = NULL;
3181 cookie.finished = FALSE;
3182
3183#ifdef FEAT_EVAL
3184 /*
3185 * Check if this script has a breakpoint.
3186 */
3187 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3188 cookie.fname = fname_exp;
3189 cookie.dbg_tick = debug_tick;
3190
3191 cookie.level = ex_nesting_level;
3192#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003193
3194 /*
3195 * Keep the sourcing name/lnum, for recursive calls.
3196 */
3197 save_sourcing_name = sourcing_name;
3198 sourcing_name = fname_exp;
3199 save_sourcing_lnum = sourcing_lnum;
3200 sourcing_lnum = 0;
3201
Bram Moolenaar73881402009-02-04 16:50:47 +00003202#ifdef FEAT_MBYTE
3203 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3204
3205 /* Read the first line so we can check for a UTF-8 BOM. */
3206 firstline = getsourceline(0, (void *)&cookie, 0);
3207 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3208 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3209 {
3210 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3211 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3212 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003213 if (p == NULL)
3214 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003215 if (p != NULL)
3216 {
3217 vim_free(firstline);
3218 firstline = p;
3219 }
3220 }
3221#endif
3222
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003224 if (time_fd != NULL)
3225 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226#endif
3227
3228#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003229# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003230 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003231 prof_child_enter(&wait_start); /* entering a child now */
3232# endif
3233
3234 /* Don't use local function variables, if called from a function.
3235 * Also starts profiling timer for nested script. */
3236 save_funccalp = save_funccal();
3237
Bram Moolenaar071d4272004-06-13 20:20:40 +00003238 /*
3239 * Check if this script was sourced before to finds its SID.
3240 * If it's new, generate a new SID.
3241 */
3242 save_current_SID = current_SID;
3243# ifdef UNIX
3244 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3245# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003246 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3247 {
3248 si = &SCRIPT_ITEM(current_SID);
3249 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003250 && (
3251# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003252 /* Compare dev/ino when possible, it catches symbolic
3253 * links. Also compare file names, the inode may change
3254 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003255 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003256 && (si->sn_dev == st.st_dev
3257 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003259 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003261 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262 if (current_SID == 0)
3263 {
3264 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003265 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3266 == FAIL)
3267 goto almosttheend;
3268 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003270 ++script_items.ga_len;
3271 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3272# ifdef FEAT_PROFILE
3273 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003274# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003275 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003276 si = &SCRIPT_ITEM(current_SID);
3277 si->sn_name = fname_exp;
3278 fname_exp = NULL;
3279# ifdef UNIX
3280 if (stat_ok)
3281 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003282 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003283 si->sn_dev = st.st_dev;
3284 si->sn_ino = st.st_ino;
3285 }
3286 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003287 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003288# endif
3289
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290 /* Allocate the local script variables to use for this script. */
3291 new_script_vars(current_SID);
3292 }
3293
Bram Moolenaar05159a02005-02-26 23:04:13 +00003294# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003295 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003296 {
3297 int forceit;
3298
3299 /* Check if we do profiling for this script. */
3300 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3301 {
3302 script_do_profile(si);
3303 si->sn_pr_force = forceit;
3304 }
3305 if (si->sn_prof_on)
3306 {
3307 ++si->sn_pr_count;
3308 profile_start(&si->sn_pr_start);
3309 profile_zero(&si->sn_pr_children);
3310 }
3311 }
3312# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313#endif
3314
3315 /*
3316 * Call do_cmdline, which will call getsourceline() to get the lines.
3317 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003318 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003320 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003321
3322#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003323 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003324 {
3325 /* Get "si" again, "script_items" may have been reallocated. */
3326 si = &SCRIPT_ITEM(current_SID);
3327 if (si->sn_prof_on)
3328 {
3329 profile_end(&si->sn_pr_start);
3330 profile_sub_wait(&wait_start, &si->sn_pr_start);
3331 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003332 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3333 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003334 }
3335 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336#endif
3337
3338 if (got_int)
3339 EMSG(_(e_interr));
3340 sourcing_name = save_sourcing_name;
3341 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 if (p_verbose > 1)
3343 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003344 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003345 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003346 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003347 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003348 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349 }
3350#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003351 if (time_fd != NULL)
3352 {
3353 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3354 time_msg((char *)IObuff, &tv_start);
3355 time_pop(&tv_rel);
3356 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003357#endif
3358
3359#ifdef FEAT_EVAL
3360 /*
3361 * After a "finish" in debug mode, need to break at first command of next
3362 * sourced file.
3363 */
3364 if (save_debug_break_level > ex_nesting_level
3365 && debug_break_level == ex_nesting_level)
3366 ++debug_break_level;
3367#endif
3368
Bram Moolenaar05159a02005-02-26 23:04:13 +00003369#ifdef FEAT_EVAL
3370almosttheend:
3371 current_SID = save_current_SID;
3372 restore_funccal(save_funccalp);
3373# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003374 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003375 prof_child_exit(&wait_start); /* leaving a child now */
3376# endif
3377#endif
3378 fclose(cookie.fp);
3379 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003380 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003381#ifdef FEAT_MBYTE
3382 convert_setup(&cookie.conv, NULL, NULL);
3383#endif
3384
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385theend:
3386 vim_free(fname_exp);
3387 return retval;
3388}
3389
3390#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003391
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392/*
3393 * ":scriptnames"
3394 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395 void
3396ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003397 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003398{
3399 int i;
3400
Bram Moolenaar05159a02005-02-26 23:04:13 +00003401 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3402 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003403 {
3404 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3405 NameBuff, MAXPATHL, TRUE);
3406 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003407 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003408}
3409
3410# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3411/*
3412 * Fix slashes in the list of script names for 'shellslash'.
3413 */
3414 void
3415scriptnames_slash_adjust()
3416{
3417 int i;
3418
Bram Moolenaar05159a02005-02-26 23:04:13 +00003419 for (i = 1; i <= script_items.ga_len; ++i)
3420 if (SCRIPT_ITEM(i).sn_name != NULL)
3421 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003422}
3423# endif
3424
3425/*
3426 * Get a pointer to a script name. Used for ":verbose set".
3427 */
3428 char_u *
3429get_scriptname(id)
3430 scid_T id;
3431{
3432 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003433 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003434 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003435 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003436 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003437 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003439 return (char_u *)_("environment variable");
3440 if (id == SID_ERROR)
3441 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003442 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003443}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003444
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003445# if defined(EXITFREE) || defined(PROTO)
3446 void
3447free_scriptnames()
3448{
3449 int i;
3450
3451 for (i = script_items.ga_len; i > 0; --i)
3452 vim_free(SCRIPT_ITEM(i).sn_name);
3453 ga_clear(&script_items);
3454}
3455# endif
3456
Bram Moolenaar071d4272004-06-13 20:20:40 +00003457#endif
3458
3459#if defined(USE_CR) || defined(PROTO)
3460
3461# if defined(__MSL__) && (__MSL__ >= 22)
3462/*
3463 * Newer version of the Metrowerks library handle DOS and UNIX files
3464 * without help.
3465 * Test with earlier versions, MSL 2.2 is the library supplied with
3466 * Codewarrior Pro 2.
3467 */
3468 char *
3469fgets_cr(s, n, stream)
3470 char *s;
3471 int n;
3472 FILE *stream;
3473{
3474 return fgets(s, n, stream);
3475}
3476# else
3477/*
3478 * Version of fgets() which also works for lines ending in a <CR> only
3479 * (Macintosh format).
3480 * For older versions of the Metrowerks library.
3481 * At least CodeWarrior 9 needed this code.
3482 */
3483 char *
3484fgets_cr(s, n, stream)
3485 char *s;
3486 int n;
3487 FILE *stream;
3488{
3489 int c = 0;
3490 int char_read = 0;
3491
3492 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3493 {
3494 c = fgetc(stream);
3495 s[char_read++] = c;
3496 /* If the file is in DOS format, we need to skip a NL after a CR. I
3497 * thought it was the other way around, but this appears to work... */
3498 if (c == '\n')
3499 {
3500 c = fgetc(stream);
3501 if (c != '\r')
3502 ungetc(c, stream);
3503 }
3504 }
3505
3506 s[char_read] = 0;
3507 if (char_read == 0)
3508 return NULL;
3509
3510 if (feof(stream) && char_read == 1)
3511 return NULL;
3512
3513 return s;
3514}
3515# endif
3516#endif
3517
3518/*
3519 * Get one full line from a sourced file.
3520 * Called by do_cmdline() when it's called from do_source().
3521 *
3522 * Return a pointer to the line in allocated memory.
3523 * Return NULL for end-of-file or some error.
3524 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525 char_u *
3526getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003527 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003528 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003529 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003530{
3531 struct source_cookie *sp = (struct source_cookie *)cookie;
3532 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003533 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003534
3535#ifdef FEAT_EVAL
3536 /* If breakpoints have been added/deleted need to check for it. */
3537 if (sp->dbg_tick < debug_tick)
3538 {
3539 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3540 sp->dbg_tick = debug_tick;
3541 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003542# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003543 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003544 script_line_end();
3545# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546#endif
3547 /*
3548 * Get current line. If there is a read-ahead line, use it, otherwise get
3549 * one now.
3550 */
3551 if (sp->finished)
3552 line = NULL;
3553 else if (sp->nextline == NULL)
3554 line = get_one_sourceline(sp);
3555 else
3556 {
3557 line = sp->nextline;
3558 sp->nextline = NULL;
3559 ++sourcing_lnum;
3560 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003561#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003562 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003563 script_line_start();
3564#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565
3566 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3567 * contain the 'C' flag. */
3568 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3569 {
3570 /* compensate for the one line read-ahead */
3571 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003572
3573 /* Get the next line and concatenate it when it starts with a
3574 * backslash. We always need to read the next line, keep it in
3575 * sp->nextline. */
3576 sp->nextline = get_one_sourceline(sp);
3577 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003579 garray_T ga;
3580
Bram Moolenaarb549a732012-02-22 18:29:33 +01003581 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003582 ga_concat(&ga, line);
3583 ga_concat(&ga, p + 1);
3584 for (;;)
3585 {
3586 vim_free(sp->nextline);
3587 sp->nextline = get_one_sourceline(sp);
3588 if (sp->nextline == NULL)
3589 break;
3590 p = skipwhite(sp->nextline);
3591 if (*p != '\\')
3592 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003593 /* Adjust the growsize to the current length to speed up
3594 * concatenating many lines. */
3595 if (ga.ga_len > 400)
3596 {
3597 if (ga.ga_len > 8000)
3598 ga.ga_growsize = 8000;
3599 else
3600 ga.ga_growsize = ga.ga_len;
3601 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003602 ga_concat(&ga, p + 1);
3603 }
3604 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003605 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003606 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003607 }
3608 }
3609
3610#ifdef FEAT_MBYTE
3611 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3612 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003613 char_u *s;
3614
Bram Moolenaar071d4272004-06-13 20:20:40 +00003615 /* Convert the encoding of the script line. */
3616 s = string_convert(&sp->conv, line, NULL);
3617 if (s != NULL)
3618 {
3619 vim_free(line);
3620 line = s;
3621 }
3622 }
3623#endif
3624
3625#ifdef FEAT_EVAL
3626 /* Did we encounter a breakpoint? */
3627 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3628 {
3629 dbg_breakpoint(sp->fname, sourcing_lnum);
3630 /* Find next breakpoint. */
3631 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3632 sp->dbg_tick = debug_tick;
3633 }
3634#endif
3635
3636 return line;
3637}
3638
3639 static char_u *
3640get_one_sourceline(sp)
3641 struct source_cookie *sp;
3642{
3643 garray_T ga;
3644 int len;
3645 int c;
3646 char_u *buf;
3647#ifdef USE_CRNL
3648 int has_cr; /* CR-LF found */
3649#endif
3650#ifdef USE_CR
3651 char_u *scan;
3652#endif
3653 int have_read = FALSE;
3654
3655 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003656 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003657
3658 /*
3659 * Loop until there is a finished line (or end-of-file).
3660 */
3661 sourcing_lnum++;
3662 for (;;)
3663 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003664 /* make room to read at least 120 (more) characters */
3665 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003666 break;
3667 buf = (char_u *)ga.ga_data;
3668
3669#ifdef USE_CR
3670 if (sp->fileformat == EOL_MAC)
3671 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003672 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3673 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003674 break;
3675 }
3676 else
3677#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003678 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3679 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003681 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682#ifdef USE_CRNL
3683 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3684 * CTRL-Z by its own, or after a NL. */
3685 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3686 && sp->fileformat == EOL_DOS
3687 && buf[len - 1] == Ctrl_Z)
3688 {
3689 buf[len - 1] = NUL;
3690 break;
3691 }
3692#endif
3693
3694#ifdef USE_CR
3695 /* If the read doesn't stop on a new line, and there's
3696 * some CR then we assume a Mac format */
3697 if (sp->fileformat == EOL_UNKNOWN)
3698 {
3699 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3700 sp->fileformat = EOL_MAC;
3701 else
3702 sp->fileformat = EOL_UNIX;
3703 }
3704
3705 if (sp->fileformat == EOL_MAC)
3706 {
3707 scan = vim_strchr(buf, '\r');
3708
3709 if (scan != NULL)
3710 {
3711 *scan = '\n';
3712 if (*(scan + 1) != 0)
3713 {
3714 *(scan + 1) = 0;
3715 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3716 }
3717 }
3718 len = STRLEN(buf);
3719 }
3720#endif
3721
3722 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723 ga.ga_len = len;
3724
3725 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003726 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003727 continue;
3728
3729 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3730 {
3731#ifdef USE_CRNL
3732 has_cr = (len >= 2 && buf[len - 2] == '\r');
3733 if (sp->fileformat == EOL_UNKNOWN)
3734 {
3735 if (has_cr)
3736 sp->fileformat = EOL_DOS;
3737 else
3738 sp->fileformat = EOL_UNIX;
3739 }
3740
3741 if (sp->fileformat == EOL_DOS)
3742 {
3743 if (has_cr) /* replace trailing CR */
3744 {
3745 buf[len - 2] = '\n';
3746 --len;
3747 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003748 }
3749 else /* lines like ":map xx yy^M" will have failed */
3750 {
3751 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003752 {
3753 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003755 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003756 sp->error = TRUE;
3757 sp->fileformat = EOL_UNIX;
3758 }
3759 }
3760#endif
3761 /* The '\n' is escaped if there is an odd number of ^V's just
3762 * before it, first set "c" just before the 'V's and then check
3763 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3764 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3765 ;
3766 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3767 {
3768 sourcing_lnum++;
3769 continue;
3770 }
3771
3772 buf[len - 1] = NUL; /* remove the NL */
3773 }
3774
3775 /*
3776 * Check for ^C here now and then, so recursive :so can be broken.
3777 */
3778 line_breakcheck();
3779 break;
3780 }
3781
3782 if (have_read)
3783 return (char_u *)ga.ga_data;
3784
3785 vim_free(ga.ga_data);
3786 return NULL;
3787}
3788
Bram Moolenaar05159a02005-02-26 23:04:13 +00003789#if defined(FEAT_PROFILE) || defined(PROTO)
3790/*
3791 * Called when starting to read a script line.
3792 * "sourcing_lnum" must be correct!
3793 * When skipping lines it may not actually be executed, but we won't find out
3794 * until later and we need to store the time now.
3795 */
3796 void
3797script_line_start()
3798{
3799 scriptitem_T *si;
3800 sn_prl_T *pp;
3801
3802 if (current_SID <= 0 || current_SID > script_items.ga_len)
3803 return;
3804 si = &SCRIPT_ITEM(current_SID);
3805 if (si->sn_prof_on && sourcing_lnum >= 1)
3806 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003807 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003808 * here isn't counted. */
3809 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3810 si->sn_prl_idx = sourcing_lnum - 1;
3811 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3812 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3813 {
3814 /* Zero counters for a line that was not used before. */
3815 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3816 pp->snp_count = 0;
3817 profile_zero(&pp->sn_prl_total);
3818 profile_zero(&pp->sn_prl_self);
3819 ++si->sn_prl_ga.ga_len;
3820 }
3821 si->sn_prl_execed = FALSE;
3822 profile_start(&si->sn_prl_start);
3823 profile_zero(&si->sn_prl_children);
3824 profile_get_wait(&si->sn_prl_wait);
3825 }
3826}
3827
3828/*
3829 * Called when actually executing a function line.
3830 */
3831 void
3832script_line_exec()
3833{
3834 scriptitem_T *si;
3835
3836 if (current_SID <= 0 || current_SID > script_items.ga_len)
3837 return;
3838 si = &SCRIPT_ITEM(current_SID);
3839 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3840 si->sn_prl_execed = TRUE;
3841}
3842
3843/*
3844 * Called when done with a function line.
3845 */
3846 void
3847script_line_end()
3848{
3849 scriptitem_T *si;
3850 sn_prl_T *pp;
3851
3852 if (current_SID <= 0 || current_SID > script_items.ga_len)
3853 return;
3854 si = &SCRIPT_ITEM(current_SID);
3855 if (si->sn_prof_on && si->sn_prl_idx >= 0
3856 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3857 {
3858 if (si->sn_prl_execed)
3859 {
3860 pp = &PRL_ITEM(si, si->sn_prl_idx);
3861 ++pp->snp_count;
3862 profile_end(&si->sn_prl_start);
3863 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003864 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003865 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3866 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003867 }
3868 si->sn_prl_idx = -1;
3869 }
3870}
3871#endif
3872
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873/*
3874 * ":scriptencoding": Set encoding conversion for a sourced script.
3875 * Without the multi-byte feature it's simply ignored.
3876 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877 void
3878ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003879 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003880{
3881#ifdef FEAT_MBYTE
3882 struct source_cookie *sp;
3883 char_u *name;
3884
3885 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3886 {
3887 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3888 return;
3889 }
3890
3891 if (*eap->arg != NUL)
3892 {
3893 name = enc_canonize(eap->arg);
3894 if (name == NULL) /* out of memory */
3895 return;
3896 }
3897 else
3898 name = eap->arg;
3899
3900 /* Setup for conversion from the specified encoding to 'encoding'. */
3901 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3902 convert_setup(&sp->conv, name, p_enc);
3903
3904 if (name != eap->arg)
3905 vim_free(name);
3906#endif
3907}
3908
3909#if defined(FEAT_EVAL) || defined(PROTO)
3910/*
3911 * ":finish": Mark a sourced file as finished.
3912 */
3913 void
3914ex_finish(eap)
3915 exarg_T *eap;
3916{
3917 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3918 do_finish(eap, FALSE);
3919 else
3920 EMSG(_("E168: :finish used outside of a sourced file"));
3921}
3922
3923/*
3924 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3925 * Also called for a pending finish at the ":endtry" or after returning from
3926 * an extra do_cmdline(). "reanimate" is used in the latter case.
3927 */
3928 void
3929do_finish(eap, reanimate)
3930 exarg_T *eap;
3931 int reanimate;
3932{
3933 int idx;
3934
3935 if (reanimate)
3936 ((struct source_cookie *)getline_cookie(eap->getline,
3937 eap->cookie))->finished = FALSE;
3938
3939 /*
3940 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3941 * not in its finally clause (which then is to be executed next) is found.
3942 * In this case, make the ":finish" pending for execution at the ":endtry".
3943 * Otherwise, finish normally.
3944 */
3945 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3946 if (idx >= 0)
3947 {
3948 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3949 report_make_pending(CSTP_FINISH, NULL);
3950 }
3951 else
3952 ((struct source_cookie *)getline_cookie(eap->getline,
3953 eap->cookie))->finished = TRUE;
3954}
3955
3956
3957/*
3958 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3959 * message for missing ":endif".
3960 * Return FALSE when not sourcing a file.
3961 */
3962 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003963source_finished(fgetline, cookie)
3964 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003965 void *cookie;
3966{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003967 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003968 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003969 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003970}
3971#endif
3972
3973#if defined(FEAT_LISTCMDS) || defined(PROTO)
3974/*
3975 * ":checktime [buffer]"
3976 */
3977 void
3978ex_checktime(eap)
3979 exarg_T *eap;
3980{
3981 buf_T *buf;
3982 int save_no_check_timestamps = no_check_timestamps;
3983
3984 no_check_timestamps = 0;
3985 if (eap->addr_count == 0) /* default is all buffers */
3986 check_timestamps(FALSE);
3987 else
3988 {
3989 buf = buflist_findnr((int)eap->line2);
3990 if (buf != NULL) /* cannot happen? */
3991 (void)buf_check_timestamp(buf, FALSE);
3992 }
3993 no_check_timestamps = save_no_check_timestamps;
3994}
3995#endif
3996
Bram Moolenaar071d4272004-06-13 20:20:40 +00003997#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3998 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003999# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000static char *get_locale_val __ARGS((int what));
4001
4002 static char *
4003get_locale_val(what)
4004 int what;
4005{
4006 char *loc;
4007
4008 /* Obtain the locale value from the libraries. For DJGPP this is
4009 * redefined and it doesn't use the arguments. */
4010 loc = setlocale(what, NULL);
4011
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004012# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013 if (loc != NULL)
4014 {
4015 char_u *p;
4016
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004017 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4018 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004019 p = vim_strchr(loc, '=');
4020 if (p != NULL)
4021 {
4022 loc = ++p;
4023 while (*p != NUL) /* remove trailing newline */
4024 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004025 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004026 {
4027 *p = NUL;
4028 break;
4029 }
4030 ++p;
4031 }
4032 }
4033 }
4034# endif
4035
4036 return loc;
4037}
4038#endif
4039
4040
4041#ifdef WIN32
4042/*
4043 * On MS-Windows locale names are strings like "German_Germany.1252", but
4044 * gettext expects "de". Try to translate one into another here for a few
4045 * supported languages.
4046 */
4047 static char_u *
4048gettext_lang(char_u *name)
4049{
4050 int i;
4051 static char *(mtable[]) = {
4052 "afrikaans", "af",
4053 "czech", "cs",
4054 "dutch", "nl",
4055 "german", "de",
4056 "english_united kingdom", "en_GB",
4057 "spanish", "es",
4058 "french", "fr",
4059 "italian", "it",
4060 "japanese", "ja",
4061 "korean", "ko",
4062 "norwegian", "no",
4063 "polish", "pl",
4064 "russian", "ru",
4065 "slovak", "sk",
4066 "swedish", "sv",
4067 "ukrainian", "uk",
4068 "chinese_china", "zh_CN",
4069 "chinese_taiwan", "zh_TW",
4070 NULL};
4071
4072 for (i = 0; mtable[i] != NULL; i += 2)
4073 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4074 return mtable[i + 1];
4075 return name;
4076}
4077#endif
4078
4079#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4080/*
4081 * Obtain the current messages language. Used to set the default for
4082 * 'helplang'. May return NULL or an empty string.
4083 */
4084 char_u *
4085get_mess_lang()
4086{
4087 char_u *p;
4088
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004089# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004090# if defined(LC_MESSAGES)
4091 p = (char_u *)get_locale_val(LC_MESSAGES);
4092# else
4093 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004094 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4095 * and LC_MONETARY may be set differently for a Japanese working in the
4096 * US. */
4097 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098# endif
4099# else
4100 p = mch_getenv((char_u *)"LC_ALL");
4101 if (p == NULL || *p == NUL)
4102 {
4103 p = mch_getenv((char_u *)"LC_MESSAGES");
4104 if (p == NULL || *p == NUL)
4105 p = mch_getenv((char_u *)"LANG");
4106 }
4107# endif
4108# ifdef WIN32
4109 p = gettext_lang(p);
4110# endif
4111 return p;
4112}
4113#endif
4114
Bram Moolenaardef9e822004-12-31 20:58:58 +00004115/* Complicated #if; matches with where get_mess_env() is used below. */
4116#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4117 && defined(LC_MESSAGES))) \
4118 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4119 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4120 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121static char_u *get_mess_env __ARGS((void));
4122
4123/*
4124 * Get the language used for messages from the environment.
4125 */
4126 static char_u *
4127get_mess_env()
4128{
4129 char_u *p;
4130
4131 p = mch_getenv((char_u *)"LC_ALL");
4132 if (p == NULL || *p == NUL)
4133 {
4134 p = mch_getenv((char_u *)"LC_MESSAGES");
4135 if (p == NULL || *p == NUL)
4136 {
4137 p = mch_getenv((char_u *)"LANG");
4138 if (p != NULL && VIM_ISDIGIT(*p))
4139 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004140# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004141 if (p == NULL || *p == NUL)
4142 p = (char_u *)get_locale_val(LC_CTYPE);
4143# endif
4144 }
4145 }
4146 return p;
4147}
4148#endif
4149
4150#if defined(FEAT_EVAL) || defined(PROTO)
4151
4152/*
4153 * Set the "v:lang" variable according to the current locale setting.
4154 * Also do "v:lc_time"and "v:ctype".
4155 */
4156 void
4157set_lang_var()
4158{
4159 char_u *loc;
4160
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004161# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 loc = (char_u *)get_locale_val(LC_CTYPE);
4163# else
4164 /* setlocale() not supported: use the default value */
4165 loc = (char_u *)"C";
4166# endif
4167 set_vim_var_string(VV_CTYPE, loc, -1);
4168
4169 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4170 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004171# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172 loc = (char_u *)get_locale_val(LC_MESSAGES);
4173# else
4174 loc = get_mess_env();
4175# endif
4176 set_vim_var_string(VV_LANG, loc, -1);
4177
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004178# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179 loc = (char_u *)get_locale_val(LC_TIME);
4180# endif
4181 set_vim_var_string(VV_LC_TIME, loc, -1);
4182}
4183#endif
4184
4185#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4186 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4187/*
4188 * ":language": Set the language (locale).
4189 */
4190 void
4191ex_language(eap)
4192 exarg_T *eap;
4193{
4194 char *loc;
4195 char_u *p;
4196 char_u *name;
4197 int what = LC_ALL;
4198 char *whatstr = "";
4199#ifdef LC_MESSAGES
4200# define VIM_LC_MESSAGES LC_MESSAGES
4201#else
4202# define VIM_LC_MESSAGES 6789
4203#endif
4204
4205 name = eap->arg;
4206
4207 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4208 * Allow abbreviation, but require at least 3 characters to avoid
4209 * confusion with a two letter language name "me" or "ct". */
4210 p = skiptowhite(eap->arg);
4211 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4212 {
4213 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4214 {
4215 what = VIM_LC_MESSAGES;
4216 name = skipwhite(p);
4217 whatstr = "messages ";
4218 }
4219 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4220 {
4221 what = LC_CTYPE;
4222 name = skipwhite(p);
4223 whatstr = "ctype ";
4224 }
4225 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4226 {
4227 what = LC_TIME;
4228 name = skipwhite(p);
4229 whatstr = "time ";
4230 }
4231 }
4232
4233 if (*name == NUL)
4234 {
4235#ifndef LC_MESSAGES
4236 if (what == VIM_LC_MESSAGES)
4237 p = get_mess_env();
4238 else
4239#endif
4240 p = (char_u *)setlocale(what, NULL);
4241 if (p == NULL || *p == NUL)
4242 p = (char_u *)"Unknown";
4243 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4244 }
4245 else
4246 {
4247#ifndef LC_MESSAGES
4248 if (what == VIM_LC_MESSAGES)
4249 loc = "";
4250 else
4251#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004252 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004254#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4255 /* Make sure strtod() uses a decimal point, not a comma. */
4256 setlocale(LC_NUMERIC, "C");
4257#endif
4258 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004259 if (loc == NULL)
4260 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4261 else
4262 {
4263#ifdef HAVE_NL_MSG_CAT_CNTR
4264 /* Need to do this for GNU gettext, otherwise cached translations
4265 * will be used again. */
4266 extern int _nl_msg_cat_cntr;
4267
4268 ++_nl_msg_cat_cntr;
4269#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004270 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4272
4273 if (what != LC_TIME)
4274 {
4275 /* Tell gettext() what to translate to. It apparently doesn't
4276 * use the currently effective locale. Also do this when
4277 * FEAT_GETTEXT isn't defined, so that shell commands use this
4278 * value. */
4279 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004280 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004281 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004282
4283 /* Clear $LANGUAGE because GNU gettext uses it. */
4284 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004285# ifdef WIN32
4286 /* Apparently MS-Windows printf() may cause a crash when
4287 * we give it 8-bit text while it's expecting text in the
4288 * current locale. This call avoids that. */
4289 setlocale(LC_CTYPE, "C");
4290# endif
4291 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292 if (what != LC_CTYPE)
4293 {
4294 char_u *mname;
4295#ifdef WIN32
4296 mname = gettext_lang(name);
4297#else
4298 mname = name;
4299#endif
4300 vim_setenv((char_u *)"LC_MESSAGES", mname);
4301#ifdef FEAT_MULTI_LANG
4302 set_helplang_default(mname);
4303#endif
4304 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004305 }
4306
4307# ifdef FEAT_EVAL
4308 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4309 set_lang_var();
4310# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004311# ifdef FEAT_TITLE
4312 maketitle();
4313# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314 }
4315 }
4316}
4317
4318# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004319
4320static char_u **locales = NULL; /* Array of all available locales */
4321static int did_init_locales = FALSE;
4322
4323static void init_locales __ARGS((void));
4324static char_u **find_locales __ARGS((void));
4325
4326/*
4327 * Lazy initialization of all available locales.
4328 */
4329 static void
4330init_locales()
4331{
4332 if (!did_init_locales)
4333 {
4334 did_init_locales = TRUE;
4335 locales = find_locales();
4336 }
4337}
4338
4339/* Return an array of strings for all available locales + NULL for the
4340 * last element. Return NULL in case of error. */
4341 static char_u **
4342find_locales()
4343{
4344 garray_T locales_ga;
4345 char_u *loc;
4346
4347 /* Find all available locales by running command "locale -a". If this
4348 * doesn't work we won't have completion. */
4349 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004350 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004351 if (locale_a == NULL)
4352 return NULL;
4353 ga_init2(&locales_ga, sizeof(char_u *), 20);
4354
4355 /* Transform locale_a string where each locale is separated by "\n"
4356 * into an array of locale strings. */
4357 loc = (char_u *)strtok((char *)locale_a, "\n");
4358
4359 while (loc != NULL)
4360 {
4361 if (ga_grow(&locales_ga, 1) == FAIL)
4362 break;
4363 loc = vim_strsave(loc);
4364 if (loc == NULL)
4365 break;
4366
4367 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4368 loc = (char_u *)strtok(NULL, "\n");
4369 }
4370 vim_free(locale_a);
4371 if (ga_grow(&locales_ga, 1) == FAIL)
4372 {
4373 ga_clear(&locales_ga);
4374 return NULL;
4375 }
4376 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4377 return (char_u **)locales_ga.ga_data;
4378}
4379
4380# if defined(EXITFREE) || defined(PROTO)
4381 void
4382free_locales()
4383{
4384 int i;
4385 if (locales != NULL)
4386 {
4387 for (i = 0; locales[i] != NULL; i++)
4388 vim_free(locales[i]);
4389 vim_free(locales);
4390 locales = NULL;
4391 }
4392}
4393# endif
4394
Bram Moolenaar071d4272004-06-13 20:20:40 +00004395/*
4396 * Function given to ExpandGeneric() to obtain the possible arguments of the
4397 * ":language" command.
4398 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004399 char_u *
4400get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004401 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004402 int idx;
4403{
4404 if (idx == 0)
4405 return (char_u *)"messages";
4406 if (idx == 1)
4407 return (char_u *)"ctype";
4408 if (idx == 2)
4409 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004410
4411 init_locales();
4412 if (locales == NULL)
4413 return NULL;
4414 return locales[idx - 3];
4415}
4416
4417/*
4418 * Function given to ExpandGeneric() to obtain the available locales.
4419 */
4420 char_u *
4421get_locales(xp, idx)
4422 expand_T *xp UNUSED;
4423 int idx;
4424{
4425 init_locales();
4426 if (locales == NULL)
4427 return NULL;
4428 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429}
4430# endif
4431
4432#endif