blob: bfa322d870d19719e10b499c893400fb51ed88e5 [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 Moolenaarc236c162008-07-13 17:41:49 +000014#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
Bram Moolenaar8c8de832008-06-24 22:58:06 +000015# include "vimio.h" /* for mch_open(), must be before vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +000016#endif
17
18#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000019#include "version.h"
20
21static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
22
Bram Moolenaar05159a02005-02-26 23:04:13 +000023#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000024/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000025 * For Unix also store the dev/ino, so that we don't have to stat() each
26 * script when going through the list. */
27typedef struct scriptitem_S
28{
29 char_u *sn_name;
30# ifdef UNIX
31 int sn_dev;
32 ino_t sn_ino;
33# endif
34# ifdef FEAT_PROFILE
35 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000036 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000037 proftime_T sn_pr_child; /* time set when going into first child */
38 int sn_pr_nest; /* nesting for sn_pr_child */
39 /* profiling the script as a whole */
40 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000041 proftime_T sn_pr_total; /* time spent in script + children */
42 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000043 proftime_T sn_pr_start; /* time at script start */
44 proftime_T sn_pr_children; /* time in children after script start */
45 /* profiling the script per line */
46 garray_T sn_prl_ga; /* things stored for every line */
47 proftime_T sn_prl_start; /* start time for current line */
48 proftime_T sn_prl_children; /* time spent in children for this line */
49 proftime_T sn_prl_wait; /* wait start time for current line */
50 int sn_prl_idx; /* index of line being timed; -1 if none */
51 int sn_prl_execed; /* line being timed was executed */
52# endif
53} scriptitem_T;
54
55static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
56#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
57
58# ifdef FEAT_PROFILE
59/* Struct used in sn_prl_ga for every line of a script. */
60typedef struct sn_prl_S
61{
62 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000063 proftime_T sn_prl_total; /* time spent in a line + children */
64 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000065} sn_prl_T;
66
67# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
68# endif
69#endif
70
Bram Moolenaar071d4272004-06-13 20:20:40 +000071#if defined(FEAT_EVAL) || defined(PROTO)
72static int debug_greedy = FALSE; /* batch mode debugging: don't save
73 and restore typeahead. */
74
75/*
76 * do_debug(): Debug mode.
77 * Repeatedly get Ex commands, until told to continue normal execution.
78 */
79 void
80do_debug(cmd)
81 char_u *cmd;
82{
83 int save_msg_scroll = msg_scroll;
84 int save_State = State;
85 int save_did_emsg = did_emsg;
86 int save_cmd_silent = cmd_silent;
87 int save_msg_silent = msg_silent;
88 int save_emsg_silent = emsg_silent;
89 int save_redir_off = redir_off;
90 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000091 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000092 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093# ifdef FEAT_EX_EXTRA
94 int save_ex_normal_busy;
95# endif
96 int n;
97 char_u *cmdline = NULL;
98 char_u *p;
99 char *tail = NULL;
100 static int last_cmd = 0;
101#define CMD_CONT 1
102#define CMD_NEXT 2
103#define CMD_STEP 3
104#define CMD_FINISH 4
105#define CMD_QUIT 5
106#define CMD_INTERRUPT 6
107
108#ifdef ALWAYS_USE_GUI
109 /* Can't do this when there is no terminal for input/output. */
110 if (!gui.in_use)
111 {
112 /* Break as soon as possible. */
113 debug_break_level = 9999;
114 return;
115 }
116#endif
117
118 /* Make sure we are in raw mode and start termcap mode. Might have side
119 * effects... */
120 settmode(TMODE_RAW);
121 starttermcap();
122
123 ++RedrawingDisabled; /* don't redisplay the window */
124 ++no_wait_return; /* don't wait for return */
125 did_emsg = FALSE; /* don't use error from debugged stuff */
126 cmd_silent = FALSE; /* display commands */
127 msg_silent = FALSE; /* display messages */
128 emsg_silent = FALSE; /* display error messages */
129 redir_off = TRUE; /* don't redirect debug commands */
130
131 State = NORMAL;
132#ifdef FEAT_SNIFF
133 want_sniff_request = 0; /* No K_SNIFF wanted */
134#endif
135
136 if (!debug_did_msg)
137 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
138 if (sourcing_name != NULL)
139 msg(sourcing_name);
140 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000141 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000142 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000143 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144
145 /*
146 * Repeat getting a command and executing it.
147 */
148 for (;;)
149 {
150 msg_scroll = TRUE;
151 need_wait_return = FALSE;
152#ifdef FEAT_SNIFF
153 ProcessSniffRequests();
154#endif
155 /* Save the current typeahead buffer and replace it with an empty one.
156 * This makes sure we get input from the user here and don't interfere
157 * with the commands being executed. Reset "ex_normal_busy" to avoid
158 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000159 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160# ifdef FEAT_EX_EXTRA
161 save_ex_normal_busy = ex_normal_busy;
162 ex_normal_busy = 0;
163# endif
164 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000165 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000167 typeahead_saved = TRUE;
168 save_ignore_script = ignore_script;
169 ignore_script = TRUE;
170 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000172 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000174 if (typeahead_saved)
175 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000177 ignore_script = save_ignore_script;
178 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179# ifdef FEAT_EX_EXTRA
180 ex_normal_busy = save_ex_normal_busy;
181# endif
182
183 cmdline_row = msg_row;
184 if (cmdline != NULL)
185 {
186 /* If this is a debug command, set "last_cmd".
187 * If not, reset "last_cmd".
188 * For a blank line use previous command. */
189 p = skipwhite(cmdline);
190 if (*p != NUL)
191 {
192 switch (*p)
193 {
194 case 'c': last_cmd = CMD_CONT;
195 tail = "ont";
196 break;
197 case 'n': last_cmd = CMD_NEXT;
198 tail = "ext";
199 break;
200 case 's': last_cmd = CMD_STEP;
201 tail = "tep";
202 break;
203 case 'f': last_cmd = CMD_FINISH;
204 tail = "inish";
205 break;
206 case 'q': last_cmd = CMD_QUIT;
207 tail = "uit";
208 break;
209 case 'i': last_cmd = CMD_INTERRUPT;
210 tail = "nterrupt";
211 break;
212 default: last_cmd = 0;
213 }
214 if (last_cmd != 0)
215 {
216 /* Check that the tail matches. */
217 ++p;
218 while (*p != NUL && *p == *tail)
219 {
220 ++p;
221 ++tail;
222 }
223 if (ASCII_ISALPHA(*p))
224 last_cmd = 0;
225 }
226 }
227
228 if (last_cmd != 0)
229 {
230 /* Execute debug command: decided where to break next and
231 * return. */
232 switch (last_cmd)
233 {
234 case CMD_CONT:
235 debug_break_level = -1;
236 break;
237 case CMD_NEXT:
238 debug_break_level = ex_nesting_level;
239 break;
240 case CMD_STEP:
241 debug_break_level = 9999;
242 break;
243 case CMD_FINISH:
244 debug_break_level = ex_nesting_level - 1;
245 break;
246 case CMD_QUIT:
247 got_int = TRUE;
248 debug_break_level = -1;
249 break;
250 case CMD_INTERRUPT:
251 got_int = TRUE;
252 debug_break_level = 9999;
253 /* Do not repeat ">interrupt" cmd, continue stepping. */
254 last_cmd = CMD_STEP;
255 break;
256 }
257 break;
258 }
259
260 /* don't debug this command */
261 n = debug_break_level;
262 debug_break_level = -1;
263 (void)do_cmdline(cmdline, getexline, NULL,
264 DOCMD_VERBOSE|DOCMD_EXCRESET);
265 debug_break_level = n;
266
267 vim_free(cmdline);
268 }
269 lines_left = Rows - 1;
270 }
271 vim_free(cmdline);
272
273 --RedrawingDisabled;
274 --no_wait_return;
275 redraw_all_later(NOT_VALID);
276 need_wait_return = FALSE;
277 msg_scroll = save_msg_scroll;
278 lines_left = Rows - 1;
279 State = save_State;
280 did_emsg = save_did_emsg;
281 cmd_silent = save_cmd_silent;
282 msg_silent = save_msg_silent;
283 emsg_silent = save_emsg_silent;
284 redir_off = save_redir_off;
285
286 /* Only print the message again when typing a command before coming back
287 * here. */
288 debug_did_msg = TRUE;
289}
290
291/*
292 * ":debug".
293 */
294 void
295ex_debug(eap)
296 exarg_T *eap;
297{
298 int debug_break_level_save = debug_break_level;
299
300 debug_break_level = 9999;
301 do_cmdline_cmd(eap->arg);
302 debug_break_level = debug_break_level_save;
303}
304
305static char_u *debug_breakpoint_name = NULL;
306static linenr_T debug_breakpoint_lnum;
307
308/*
309 * When debugging or a breakpoint is set on a skipped command, no debug prompt
310 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
311 * debug_skipped_name is then set to the source name in the breakpoint case. If
312 * a skipped command decides itself that a debug prompt should be displayed, it
313 * can do so by calling dbg_check_skipped().
314 */
315static int debug_skipped;
316static char_u *debug_skipped_name;
317
318/*
319 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
320 * at or below the break level. But only when the line is actually
321 * executed. Return TRUE and set breakpoint_name for skipped commands that
322 * decide to execute something themselves.
323 * Called from do_one_cmd() before executing a command.
324 */
325 void
326dbg_check_breakpoint(eap)
327 exarg_T *eap;
328{
329 char_u *p;
330
331 debug_skipped = FALSE;
332 if (debug_breakpoint_name != NULL)
333 {
334 if (!eap->skip)
335 {
336 /* replace K_SNR with "<SNR>" */
337 if (debug_breakpoint_name[0] == K_SPECIAL
338 && debug_breakpoint_name[1] == KS_EXTRA
339 && debug_breakpoint_name[2] == (int)KE_SNR)
340 p = (char_u *)"<SNR>";
341 else
342 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000343 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
344 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000345 debug_breakpoint_name + (*p == NUL ? 0 : 3),
346 (long)debug_breakpoint_lnum);
347 debug_breakpoint_name = NULL;
348 do_debug(eap->cmd);
349 }
350 else
351 {
352 debug_skipped = TRUE;
353 debug_skipped_name = debug_breakpoint_name;
354 debug_breakpoint_name = NULL;
355 }
356 }
357 else if (ex_nesting_level <= debug_break_level)
358 {
359 if (!eap->skip)
360 do_debug(eap->cmd);
361 else
362 {
363 debug_skipped = TRUE;
364 debug_skipped_name = NULL;
365 }
366 }
367}
368
369/*
370 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
371 * set. Return TRUE when the debug mode is entered this time.
372 */
373 int
374dbg_check_skipped(eap)
375 exarg_T *eap;
376{
377 int prev_got_int;
378
379 if (debug_skipped)
380 {
381 /*
382 * Save the value of got_int and reset it. We don't want a previous
383 * interruption cause flushing the input buffer.
384 */
385 prev_got_int = got_int;
386 got_int = FALSE;
387 debug_breakpoint_name = debug_skipped_name;
388 /* eap->skip is TRUE */
389 eap->skip = FALSE;
390 (void)dbg_check_breakpoint(eap);
391 eap->skip = TRUE;
392 got_int |= prev_got_int;
393 return TRUE;
394 }
395 return FALSE;
396}
397
398/*
399 * The list of breakpoints: dbg_breakp.
400 * This is a grow-array of structs.
401 */
402struct debuggy
403{
404 int dbg_nr; /* breakpoint number */
405 int dbg_type; /* DBG_FUNC or DBG_FILE */
406 char_u *dbg_name; /* function or file name */
407 regprog_T *dbg_prog; /* regexp program */
408 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000409 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410};
411
412static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000413#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
414#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415static int last_breakp = 0; /* nr of last defined breakpoint */
416
Bram Moolenaar05159a02005-02-26 23:04:13 +0000417#ifdef FEAT_PROFILE
418/* Profiling uses file and func names similar to breakpoints. */
419static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
420#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000421#define DBG_FUNC 1
422#define DBG_FILE 2
423
Bram Moolenaar05159a02005-02-26 23:04:13 +0000424static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
425static 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 +0000426
427/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000428 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
429 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
430 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 * Returns FAIL for failure.
432 */
433 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000434dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000435 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000436 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437{
438 char_u *p = arg;
439 char_u *q;
440 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000441 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000442
Bram Moolenaar05159a02005-02-26 23:04:13 +0000443 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000444 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000445 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446
447 /* Find "func" or "file". */
448 if (STRNCMP(p, "func", 4) == 0)
449 bp->dbg_type = DBG_FUNC;
450 else if (STRNCMP(p, "file", 4) == 0)
451 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000452 else if (
453#ifdef FEAT_PROFILE
454 gap != &prof_ga &&
455#endif
456 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000457 {
458 if (curbuf->b_ffname == NULL)
459 {
460 EMSG(_(e_noname));
461 return FAIL;
462 }
463 bp->dbg_type = DBG_FILE;
464 here = TRUE;
465 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000466 else
467 {
468 EMSG2(_(e_invarg2), p);
469 return FAIL;
470 }
471 p = skipwhite(p + 4);
472
473 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000474 if (here)
475 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000476 else if (
477#ifdef FEAT_PROFILE
478 gap != &prof_ga &&
479#endif
480 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000481 {
482 bp->dbg_lnum = getdigits(&p);
483 p = skipwhite(p);
484 }
485 else
486 bp->dbg_lnum = 0;
487
488 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000489 if ((!here && *p == NUL)
490 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
492 {
493 EMSG2(_(e_invarg2), arg);
494 return FAIL;
495 }
496
497 if (bp->dbg_type == DBG_FUNC)
498 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000499 else if (here)
500 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000501 else
502 {
503 /* Expand the file name in the same way as do_source(). This means
504 * doing it twice, so that $DIR/file gets expanded when $DIR is
505 * "~/dir". */
506#ifdef RISCOS
507 q = mch_munge_fname(p);
508#else
509 q = expand_env_save(p);
510#endif
511 if (q == NULL)
512 return FAIL;
513#ifdef RISCOS
514 p = mch_munge_fname(q);
515#else
516 p = expand_env_save(q);
517#endif
518 vim_free(q);
519 if (p == NULL)
520 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000521 if (*p != '*')
522 {
523 bp->dbg_name = fix_fname(p);
524 vim_free(p);
525 }
526 else
527 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000528 }
529
530 if (bp->dbg_name == NULL)
531 return FAIL;
532 return OK;
533}
534
535/*
536 * ":breakadd".
537 */
538 void
539ex_breakadd(eap)
540 exarg_T *eap;
541{
542 struct debuggy *bp;
543 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000544 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545
Bram Moolenaar05159a02005-02-26 23:04:13 +0000546 gap = &dbg_breakp;
547#ifdef FEAT_PROFILE
548 if (eap->cmdidx == CMD_profile)
549 gap = &prof_ga;
550#endif
551
552 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000554 bp = &DEBUGGY(gap, gap->ga_len);
555 bp->dbg_forceit = eap->forceit;
556
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
558 if (pat != NULL)
559 {
560 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
561 vim_free(pat);
562 }
563 if (pat == NULL || bp->dbg_prog == NULL)
564 vim_free(bp->dbg_name);
565 else
566 {
567 if (bp->dbg_lnum == 0) /* default line number is 1 */
568 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000569#ifdef FEAT_PROFILE
570 if (eap->cmdidx != CMD_profile)
571#endif
572 {
573 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
574 ++debug_tick;
575 }
576 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577 }
578 }
579}
580
581/*
582 * ":debuggreedy".
583 */
584 void
585ex_debuggreedy(eap)
586 exarg_T *eap;
587{
588 if (eap->addr_count == 0 || eap->line2 != 0)
589 debug_greedy = TRUE;
590 else
591 debug_greedy = FALSE;
592}
593
594/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000595 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596 */
597 void
598ex_breakdel(eap)
599 exarg_T *eap;
600{
601 struct debuggy *bp, *bpi;
602 int nr;
603 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000604 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 int i;
606 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000607 garray_T *gap;
608
609 gap = &dbg_breakp;
610#ifdef FEAT_PROFILE
611 if (eap->cmdidx == CMD_profdel)
612 gap = &prof_ga;
613#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000614
615 if (vim_isdigit(*eap->arg))
616 {
617 /* ":breakdel {nr}" */
618 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000619 for (i = 0; i < gap->ga_len; ++i)
620 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000621 {
622 todel = i;
623 break;
624 }
625 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000626 else if (*eap->arg == '*')
627 {
628 todel = 0;
629 del_all = TRUE;
630 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 else
632 {
633 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000634 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000636 bp = &DEBUGGY(gap, gap->ga_len);
637 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000639 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640 if (bp->dbg_type == bpi->dbg_type
641 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
642 && (bp->dbg_lnum == bpi->dbg_lnum
643 || (bp->dbg_lnum == 0
644 && (best_lnum == 0
645 || bpi->dbg_lnum < best_lnum))))
646 {
647 todel = i;
648 best_lnum = bpi->dbg_lnum;
649 }
650 }
651 vim_free(bp->dbg_name);
652 }
653
654 if (todel < 0)
655 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
656 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000657 {
658 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000659 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000660 vim_free(DEBUGGY(gap, todel).dbg_name);
661 vim_free(DEBUGGY(gap, todel).dbg_prog);
662 --gap->ga_len;
663 if (todel < gap->ga_len)
664 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
665 (gap->ga_len - todel) * sizeof(struct debuggy));
666#ifdef FEAT_PROFILE
667 if (eap->cmdidx == CMD_breakdel)
668#endif
669 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000670 if (!del_all)
671 break;
672 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000673
674 /* If all breakpoints were removed clear the array. */
675 if (gap->ga_len == 0)
676 ga_clear(gap);
677 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678}
679
680/*
681 * ":breaklist".
682 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683 void
684ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000685 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000686{
687 struct debuggy *bp;
688 int i;
689
690 if (dbg_breakp.ga_len == 0)
691 MSG(_("No breakpoints defined"));
692 else
693 for (i = 0; i < dbg_breakp.ga_len; ++i)
694 {
695 bp = &BREAKP(i);
696 smsg((char_u *)_("%3d %s %s line %ld"),
697 bp->dbg_nr,
698 bp->dbg_type == DBG_FUNC ? "func" : "file",
699 bp->dbg_name,
700 (long)bp->dbg_lnum);
701 }
702}
703
704/*
705 * Find a breakpoint for a function or sourced file.
706 * Returns line number at which to break; zero when no matching breakpoint.
707 */
708 linenr_T
709dbg_find_breakpoint(file, fname, after)
710 int file; /* TRUE for a file, FALSE for a function */
711 char_u *fname; /* file or function name */
712 linenr_T after; /* after this line number */
713{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000714 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
715}
716
717#if defined(FEAT_PROFILE) || defined(PROTO)
718/*
719 * Return TRUE if profiling is on for a function or sourced file.
720 */
721 int
722has_profiling(file, fname, fp)
723 int file; /* TRUE for a file, FALSE for a function */
724 char_u *fname; /* file or function name */
725 int *fp; /* return: forceit */
726{
727 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
728 != (linenr_T)0);
729}
730#endif
731
732/*
733 * Common code for dbg_find_breakpoint() and has_profiling().
734 */
735 static linenr_T
736debuggy_find(file, fname, after, gap, fp)
737 int file; /* TRUE for a file, FALSE for a function */
738 char_u *fname; /* file or function name */
739 linenr_T after; /* after this line number */
740 garray_T *gap; /* either &dbg_breakp or &prof_ga */
741 int *fp; /* if not NULL: return forceit */
742{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000743 struct debuggy *bp;
744 int i;
745 linenr_T lnum = 0;
746 regmatch_T regmatch;
747 char_u *name = fname;
748 int prev_got_int;
749
Bram Moolenaar05159a02005-02-26 23:04:13 +0000750 /* Return quickly when there are no breakpoints. */
751 if (gap->ga_len == 0)
752 return (linenr_T)0;
753
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754 /* Replace K_SNR in function name with "<SNR>". */
755 if (!file && fname[0] == K_SPECIAL)
756 {
757 name = alloc((unsigned)STRLEN(fname) + 3);
758 if (name == NULL)
759 name = fname;
760 else
761 {
762 STRCPY(name, "<SNR>");
763 STRCPY(name + 5, fname + 3);
764 }
765 }
766
Bram Moolenaar05159a02005-02-26 23:04:13 +0000767 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000769 /* Skip entries that are not useful or are for a line that is beyond
770 * an already found breakpoint. */
771 bp = &DEBUGGY(gap, i);
772 if (((bp->dbg_type == DBG_FILE) == file && (
773#ifdef FEAT_PROFILE
774 gap == &prof_ga ||
775#endif
776 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777 {
778 regmatch.regprog = bp->dbg_prog;
779 regmatch.rm_ic = FALSE;
780 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000781 * Save the value of got_int and reset it. We don't want a
782 * previous interruption cancel matching, only hitting CTRL-C
783 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 */
785 prev_got_int = got_int;
786 got_int = FALSE;
787 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000788 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000790 if (fp != NULL)
791 *fp = bp->dbg_forceit;
792 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 got_int |= prev_got_int;
794 }
795 }
796 if (name != fname)
797 vim_free(name);
798
799 return lnum;
800}
801
802/*
803 * Called when a breakpoint was encountered.
804 */
805 void
806dbg_breakpoint(name, lnum)
807 char_u *name;
808 linenr_T lnum;
809{
810 /* We need to check if this line is actually executed in do_one_cmd() */
811 debug_breakpoint_name = name;
812 debug_breakpoint_lnum = lnum;
813}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000814
815
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000816# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000817/*
818 * Store the current time in "tm".
819 */
820 void
821profile_start(tm)
822 proftime_T *tm;
823{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000824# ifdef WIN3264
825 QueryPerformanceCounter(tm);
826# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000827 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000828# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000829}
830
831/*
832 * Compute the elapsed time from "tm" till now and store in "tm".
833 */
834 void
835profile_end(tm)
836 proftime_T *tm;
837{
838 proftime_T now;
839
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000840# ifdef WIN3264
841 QueryPerformanceCounter(&now);
842 tm->QuadPart = now.QuadPart - tm->QuadPart;
843# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000844 gettimeofday(&now, NULL);
845 tm->tv_usec = now.tv_usec - tm->tv_usec;
846 tm->tv_sec = now.tv_sec - tm->tv_sec;
847 if (tm->tv_usec < 0)
848 {
849 tm->tv_usec += 1000000;
850 --tm->tv_sec;
851 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000852# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000853}
854
855/*
856 * Subtract the time "tm2" from "tm".
857 */
858 void
859profile_sub(tm, tm2)
860 proftime_T *tm, *tm2;
861{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000862# ifdef WIN3264
863 tm->QuadPart -= tm2->QuadPart;
864# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000865 tm->tv_usec -= tm2->tv_usec;
866 tm->tv_sec -= tm2->tv_sec;
867 if (tm->tv_usec < 0)
868 {
869 tm->tv_usec += 1000000;
870 --tm->tv_sec;
871 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000872# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000873}
874
875/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000876 * Return a string that represents the time in "tm".
877 * Uses a static buffer!
878 */
879 char *
880profile_msg(tm)
881 proftime_T *tm;
882{
883 static char buf[50];
884
885# ifdef WIN3264
886 LARGE_INTEGER fr;
887
888 QueryPerformanceFrequency(&fr);
889 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
890# else
891 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000892# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000893 return buf;
894}
895
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000896/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000897 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000898 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000899 void
900profile_setlimit(msec, tm)
901 long msec;
902 proftime_T *tm;
903{
904 if (msec <= 0) /* no limit */
905 profile_zero(tm);
906 else
907 {
908# ifdef WIN3264
909 LARGE_INTEGER fr;
910
911 QueryPerformanceCounter(tm);
912 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000913 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000914# else
915 long usec;
916
917 gettimeofday(tm, NULL);
918 usec = (long)tm->tv_usec + (long)msec * 1000;
919 tm->tv_usec = usec % 1000000L;
920 tm->tv_sec += usec / 1000000L;
921# endif
922 }
923}
924
925/*
926 * Return TRUE if the current time is past "tm".
927 */
928 int
929profile_passed_limit(tm)
930 proftime_T *tm;
931{
932 proftime_T now;
933
934# ifdef WIN3264
935 if (tm->QuadPart == 0) /* timer was not set */
936 return FALSE;
937 QueryPerformanceCounter(&now);
938 return (now.QuadPart > tm->QuadPart);
939# else
940 if (tm->tv_sec == 0) /* timer was not set */
941 return FALSE;
942 gettimeofday(&now, NULL);
943 return (now.tv_sec > tm->tv_sec
944 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
945# endif
946}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000947
948/*
949 * Set the time in "tm" to zero.
950 */
951 void
952profile_zero(tm)
953 proftime_T *tm;
954{
955# ifdef WIN3264
956 tm->QuadPart = 0;
957# else
958 tm->tv_usec = 0;
959 tm->tv_sec = 0;
960# endif
961}
962
Bram Moolenaar76929292008-01-06 19:07:36 +0000963# endif /* FEAT_PROFILE || FEAT_RELTIME */
964
965# if defined(FEAT_PROFILE) || defined(PROTO)
966/*
967 * Functions for profiling.
968 */
969static void script_do_profile __ARGS((scriptitem_T *si));
970static void script_dump_profile __ARGS((FILE *fd));
971static proftime_T prof_wait_time;
972
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000973/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000974 * Add the time "tm2" to "tm".
975 */
976 void
977profile_add(tm, tm2)
978 proftime_T *tm, *tm2;
979{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000980# ifdef WIN3264
981 tm->QuadPart += tm2->QuadPart;
982# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000983 tm->tv_usec += tm2->tv_usec;
984 tm->tv_sec += tm2->tv_sec;
985 if (tm->tv_usec >= 1000000)
986 {
987 tm->tv_usec -= 1000000;
988 ++tm->tv_sec;
989 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000990# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000991}
992
993/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000994 * Add the "self" time from the total time and the children's time.
995 */
996 void
997profile_self(self, total, children)
998 proftime_T *self, *total, *children;
999{
1000 /* Check that the result won't be negative. Can happen with recursive
1001 * calls. */
1002#ifdef WIN3264
1003 if (total->QuadPart <= children->QuadPart)
1004 return;
1005#else
1006 if (total->tv_sec < children->tv_sec
1007 || (total->tv_sec == children->tv_sec
1008 && total->tv_usec <= children->tv_usec))
1009 return;
1010#endif
1011 profile_add(self, total);
1012 profile_sub(self, children);
1013}
1014
1015/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001016 * Get the current waittime.
1017 */
1018 void
1019profile_get_wait(tm)
1020 proftime_T *tm;
1021{
1022 *tm = prof_wait_time;
1023}
1024
1025/*
1026 * Subtract the passed waittime since "tm" from "tma".
1027 */
1028 void
1029profile_sub_wait(tm, tma)
1030 proftime_T *tm, *tma;
1031{
1032 proftime_T tm3 = prof_wait_time;
1033
1034 profile_sub(&tm3, tm);
1035 profile_sub(tma, &tm3);
1036}
1037
1038/*
1039 * Return TRUE if "tm1" and "tm2" are equal.
1040 */
1041 int
1042profile_equal(tm1, tm2)
1043 proftime_T *tm1, *tm2;
1044{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001045# ifdef WIN3264
1046 return (tm1->QuadPart == tm2->QuadPart);
1047# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001048 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001049# endif
1050}
1051
1052/*
1053 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1054 */
1055 int
1056profile_cmp(tm1, tm2)
1057 proftime_T *tm1, *tm2;
1058{
1059# ifdef WIN3264
1060 return (int)(tm2->QuadPart - tm1->QuadPart);
1061# else
1062 if (tm1->tv_sec == tm2->tv_sec)
1063 return tm2->tv_usec - tm1->tv_usec;
1064 return tm2->tv_sec - tm1->tv_sec;
1065# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001066}
1067
Bram Moolenaar05159a02005-02-26 23:04:13 +00001068static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001069static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001070
1071/*
1072 * ":profile cmd args"
1073 */
1074 void
1075ex_profile(eap)
1076 exarg_T *eap;
1077{
1078 char_u *e;
1079 int len;
1080
1081 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001082 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001083 e = skipwhite(e);
1084
1085 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1086 {
1087 vim_free(profile_fname);
1088 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001089 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001090 profile_zero(&prof_wait_time);
1091 set_vim_var_nr(VV_PROFILING, 1L);
1092 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001093 else if (do_profiling == PROF_NONE)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001094 EMSG(_("E750: First use :profile start <fname>"));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001095 else if (STRCMP(eap->arg, "pause") == 0)
1096 {
1097 if (do_profiling == PROF_YES)
1098 profile_start(&pause_time);
1099 do_profiling = PROF_PAUSED;
1100 }
1101 else if (STRCMP(eap->arg, "continue") == 0)
1102 {
1103 if (do_profiling == PROF_PAUSED)
1104 {
1105 profile_end(&pause_time);
1106 profile_add(&prof_wait_time, &pause_time);
1107 }
1108 do_profiling = PROF_YES;
1109 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001110 else
1111 {
1112 /* The rest is similar to ":breakadd". */
1113 ex_breakadd(eap);
1114 }
1115}
1116
1117/*
1118 * Dump the profiling info.
1119 */
1120 void
1121profile_dump()
1122{
1123 FILE *fd;
1124
1125 if (profile_fname != NULL)
1126 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001127 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001128 if (fd == NULL)
1129 EMSG2(_(e_notopen), profile_fname);
1130 else
1131 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001132 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001133 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001134 fclose(fd);
1135 }
1136 }
1137}
1138
1139/*
1140 * Start profiling script "fp".
1141 */
1142 static void
1143script_do_profile(si)
1144 scriptitem_T *si;
1145{
1146 si->sn_pr_count = 0;
1147 profile_zero(&si->sn_pr_total);
1148 profile_zero(&si->sn_pr_self);
1149
1150 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1151 si->sn_prl_idx = -1;
1152 si->sn_prof_on = TRUE;
1153 si->sn_pr_nest = 0;
1154}
1155
1156/*
1157 * save time when starting to invoke another script or function.
1158 */
1159 void
1160script_prof_save(tm)
1161 proftime_T *tm; /* place to store wait time */
1162{
1163 scriptitem_T *si;
1164
1165 if (current_SID > 0 && current_SID <= script_items.ga_len)
1166 {
1167 si = &SCRIPT_ITEM(current_SID);
1168 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1169 profile_start(&si->sn_pr_child);
1170 }
1171 profile_get_wait(tm);
1172}
1173
1174/*
1175 * Count time spent in children after invoking another script or function.
1176 */
1177 void
1178script_prof_restore(tm)
1179 proftime_T *tm;
1180{
1181 scriptitem_T *si;
1182
1183 if (current_SID > 0 && current_SID <= script_items.ga_len)
1184 {
1185 si = &SCRIPT_ITEM(current_SID);
1186 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1187 {
1188 profile_end(&si->sn_pr_child);
1189 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1190 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1191 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1192 }
1193 }
1194}
1195
1196static proftime_T inchar_time;
1197
1198/*
1199 * Called when starting to wait for the user to type a character.
1200 */
1201 void
1202prof_inchar_enter()
1203{
1204 profile_start(&inchar_time);
1205}
1206
1207/*
1208 * Called when finished waiting for the user to type a character.
1209 */
1210 void
1211prof_inchar_exit()
1212{
1213 profile_end(&inchar_time);
1214 profile_add(&prof_wait_time, &inchar_time);
1215}
1216
1217/*
1218 * Dump the profiling results for all scripts in file "fd".
1219 */
1220 static void
1221script_dump_profile(fd)
1222 FILE *fd;
1223{
1224 int id;
1225 scriptitem_T *si;
1226 int i;
1227 FILE *sfd;
1228 sn_prl_T *pp;
1229
1230 for (id = 1; id <= script_items.ga_len; ++id)
1231 {
1232 si = &SCRIPT_ITEM(id);
1233 if (si->sn_prof_on)
1234 {
1235 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1236 if (si->sn_pr_count == 1)
1237 fprintf(fd, "Sourced 1 time\n");
1238 else
1239 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1240 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1241 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1242 fprintf(fd, "\n");
1243 fprintf(fd, "count total (s) self (s)\n");
1244
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001245 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001246 if (sfd == NULL)
1247 fprintf(fd, "Cannot open file!\n");
1248 else
1249 {
1250 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1251 {
1252 if (vim_fgets(IObuff, IOSIZE, sfd))
1253 break;
1254 pp = &PRL_ITEM(si, i);
1255 if (pp->snp_count > 0)
1256 {
1257 fprintf(fd, "%5d ", pp->snp_count);
1258 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1259 fprintf(fd, " ");
1260 else
1261 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1262 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1263 }
1264 else
1265 fprintf(fd, " ");
1266 fprintf(fd, "%s", IObuff);
1267 }
1268 fclose(sfd);
1269 }
1270 fprintf(fd, "\n");
1271 }
1272 }
1273}
1274
1275/*
1276 * Return TRUE when a function defined in the current script should be
1277 * profiled.
1278 */
1279 int
1280prof_def_func()
1281{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001282 if (current_SID > 0)
1283 return SCRIPT_ITEM(current_SID).sn_pr_force;
1284 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001285}
1286
1287# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288#endif
1289
1290/*
1291 * If 'autowrite' option set, try to write the file.
1292 * Careful: autocommands may make "buf" invalid!
1293 *
1294 * return FAIL for failure, OK otherwise
1295 */
1296 int
1297autowrite(buf, forceit)
1298 buf_T *buf;
1299 int forceit;
1300{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001301 int r;
1302
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303 if (!(p_aw || p_awa) || !p_write
1304#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001305 /* never autowrite a "nofile" or "nowrite" buffer */
1306 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001308 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001309 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001310 r = buf_write_all(buf, forceit);
1311
1312 /* Writing may succeed but the buffer still changed, e.g., when there is a
1313 * conversion error. We do want to return FAIL then. */
1314 if (buf_valid(buf) && bufIsChanged(buf))
1315 r = FAIL;
1316 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001317}
1318
1319/*
1320 * flush all buffers, except the ones that are readonly
1321 */
1322 void
1323autowrite_all()
1324{
1325 buf_T *buf;
1326
1327 if (!(p_aw || p_awa) || !p_write)
1328 return;
1329 for (buf = firstbuf; buf; buf = buf->b_next)
1330 if (bufIsChanged(buf) && !buf->b_p_ro)
1331 {
1332 (void)buf_write_all(buf, FALSE);
1333#ifdef FEAT_AUTOCMD
1334 /* an autocommand may have deleted the buffer */
1335 if (!buf_valid(buf))
1336 buf = firstbuf;
1337#endif
1338 }
1339}
1340
1341/*
1342 * return TRUE if buffer was changed and cannot be abandoned.
1343 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001344 int
1345check_changed(buf, checkaw, mult_win, forceit, allbuf)
1346 buf_T *buf;
1347 int checkaw; /* do autowrite if buffer was changed */
1348 int mult_win; /* check also when several wins for the buf */
1349 int forceit;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001350 int allbuf UNUSED; /* may write all buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001351{
1352 if ( !forceit
1353 && bufIsChanged(buf)
1354 && (mult_win || buf->b_nwindows <= 1)
1355 && (!checkaw || autowrite(buf, forceit) == FAIL))
1356 {
1357#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1358 if ((p_confirm || cmdmod.confirm) && p_write)
1359 {
1360 buf_T *buf2;
1361 int count = 0;
1362
1363 if (allbuf)
1364 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1365 if (bufIsChanged(buf2)
1366 && (buf2->b_ffname != NULL
1367# ifdef FEAT_BROWSE
1368 || cmdmod.browse
1369# endif
1370 ))
1371 ++count;
1372# ifdef FEAT_AUTOCMD
1373 if (!buf_valid(buf))
1374 /* Autocommand deleted buffer, oops! It's not changed now. */
1375 return FALSE;
1376# endif
1377 dialog_changed(buf, count > 1);
1378# ifdef FEAT_AUTOCMD
1379 if (!buf_valid(buf))
1380 /* Autocommand deleted buffer, oops! It's not changed now. */
1381 return FALSE;
1382# endif
1383 return bufIsChanged(buf);
1384 }
1385#endif
1386 EMSG(_(e_nowrtmsg));
1387 return TRUE;
1388 }
1389 return FALSE;
1390}
1391
1392#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1393
1394#if defined(FEAT_BROWSE) || defined(PROTO)
1395/*
1396 * When wanting to write a file without a file name, ask the user for a name.
1397 */
1398 void
1399browse_save_fname(buf)
1400 buf_T *buf;
1401{
1402 if (buf->b_fname == NULL)
1403 {
1404 char_u *fname;
1405
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001406 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1407 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001408 if (fname != NULL)
1409 {
1410 if (setfname(buf, fname, NULL, TRUE) == OK)
1411 buf->b_flags |= BF_NOTEDITED;
1412 vim_free(fname);
1413 }
1414 }
1415}
1416#endif
1417
1418/*
1419 * Ask the user what to do when abondoning a changed buffer.
1420 * Must check 'write' option first!
1421 */
1422 void
1423dialog_changed(buf, checkall)
1424 buf_T *buf;
1425 int checkall; /* may abandon all changed buffers */
1426{
1427 char_u buff[IOSIZE];
1428 int ret;
1429 buf_T *buf2;
1430
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001431 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001432 (buf->b_fname != NULL) ?
1433 buf->b_fname : (char_u *)_("Untitled"));
1434 if (checkall)
1435 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1436 else
1437 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1438
1439 if (ret == VIM_YES)
1440 {
1441#ifdef FEAT_BROWSE
1442 /* May get file name, when there is none */
1443 browse_save_fname(buf);
1444#endif
1445 if (buf->b_fname != NULL) /* didn't hit Cancel */
1446 (void)buf_write_all(buf, FALSE);
1447 }
1448 else if (ret == VIM_NO)
1449 {
1450 unchanged(buf, TRUE);
1451 }
1452 else if (ret == VIM_ALL)
1453 {
1454 /*
1455 * Write all modified files that can be written.
1456 * Skip readonly buffers, these need to be confirmed
1457 * individually.
1458 */
1459 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1460 {
1461 if (bufIsChanged(buf2)
1462 && (buf2->b_ffname != NULL
1463#ifdef FEAT_BROWSE
1464 || cmdmod.browse
1465#endif
1466 )
1467 && !buf2->b_p_ro)
1468 {
1469#ifdef FEAT_BROWSE
1470 /* May get file name, when there is none */
1471 browse_save_fname(buf2);
1472#endif
1473 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1474 (void)buf_write_all(buf2, FALSE);
1475#ifdef FEAT_AUTOCMD
1476 /* an autocommand may have deleted the buffer */
1477 if (!buf_valid(buf2))
1478 buf2 = firstbuf;
1479#endif
1480 }
1481 }
1482 }
1483 else if (ret == VIM_DISCARDALL)
1484 {
1485 /*
1486 * mark all buffers as unchanged
1487 */
1488 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1489 unchanged(buf2, TRUE);
1490 }
1491}
1492#endif
1493
1494/*
1495 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1496 * hidden, autowriting it or unloading it.
1497 */
1498 int
1499can_abandon(buf, forceit)
1500 buf_T *buf;
1501 int forceit;
1502{
1503 return ( P_HID(buf)
1504 || !bufIsChanged(buf)
1505 || buf->b_nwindows > 1
1506 || autowrite(buf, forceit) == OK
1507 || forceit);
1508}
1509
1510/*
1511 * Return TRUE if any buffer was changed and cannot be abandoned.
1512 * That changed buffer becomes the current buffer.
1513 */
1514 int
1515check_changed_any(hidden)
1516 int hidden; /* Only check hidden buffers */
1517{
1518 buf_T *buf;
1519 int save;
1520#ifdef FEAT_WINDOWS
1521 win_T *wp;
1522#endif
1523
1524 for (;;)
1525 {
1526 /* check curbuf first: if it was changed we can't abandon it */
1527 if (!hidden && curbufIsChanged())
1528 buf = curbuf;
1529 else
1530 {
1531 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1532 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1533 break;
1534 }
1535 if (buf == NULL) /* No buffers changed */
1536 return FALSE;
1537
Bram Moolenaar373154b2007-02-13 05:19:30 +00001538 /* Try auto-writing the buffer. If this fails but the buffer no
1539 * longer exists it's not changed, that's OK. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001540 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1541 break; /* didn't save - still changes */
1542 }
1543
1544 exiting = FALSE;
1545#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1546 /*
1547 * When ":confirm" used, don't give an error message.
1548 */
1549 if (!(p_confirm || cmdmod.confirm))
1550#endif
1551 {
1552 /* There must be a wait_return for this message, do_buffer()
1553 * may cause a redraw. But wait_return() is a no-op when vgetc()
1554 * is busy (Quit used from window menu), then make sure we don't
1555 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001556 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001557 {
1558 msg_row = cmdline_row;
1559 msg_col = 0;
1560 msg_didout = FALSE;
1561 }
1562 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1563 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1564 buf->b_fname))
1565 {
1566 save = no_wait_return;
1567 no_wait_return = FALSE;
1568 wait_return(FALSE);
1569 no_wait_return = save;
1570 }
1571 }
1572
1573#ifdef FEAT_WINDOWS
1574 /* Try to find a window that contains the buffer. */
1575 if (buf != curbuf)
1576 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1577 if (wp->w_buffer == buf)
1578 {
1579 win_goto(wp);
1580# ifdef FEAT_AUTOCMD
1581 /* Paranoia: did autocms wipe out the buffer with changes? */
1582 if (!buf_valid(buf))
1583 return TRUE;
1584# endif
1585 break;
1586 }
1587#endif
1588
1589 /* Open the changed buffer in the current window. */
1590 if (buf != curbuf)
1591 set_curbuf(buf, DOBUF_GOTO);
1592
1593 return TRUE;
1594}
1595
1596/*
1597 * return FAIL if there is no file name, OK if there is one
1598 * give error message for FAIL
1599 */
1600 int
1601check_fname()
1602{
1603 if (curbuf->b_ffname == NULL)
1604 {
1605 EMSG(_(e_noname));
1606 return FAIL;
1607 }
1608 return OK;
1609}
1610
1611/*
1612 * flush the contents of a buffer, unless it has no file name
1613 *
1614 * return FAIL for failure, OK otherwise
1615 */
1616 int
1617buf_write_all(buf, forceit)
1618 buf_T *buf;
1619 int forceit;
1620{
1621 int retval;
1622#ifdef FEAT_AUTOCMD
1623 buf_T *old_curbuf = curbuf;
1624#endif
1625
1626 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1627 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1628 FALSE, forceit, TRUE, FALSE));
1629#ifdef FEAT_AUTOCMD
1630 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001631 {
1632 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001634 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001635#endif
1636 return retval;
1637}
1638
1639/*
1640 * Code to handle the argument list.
1641 */
1642
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001643static char_u *do_one_arg __ARGS((char_u *str));
1644static int do_arglist __ARGS((char_u *str, int what, int after));
1645static void alist_check_arg_idx __ARGS((void));
1646static int editing_arg_idx __ARGS((win_T *win));
1647#ifdef FEAT_LISTCMDS
1648static int alist_add_list __ARGS((int count, char_u **files, int after));
1649#endif
1650#define AL_SET 1
1651#define AL_ADD 2
1652#define AL_DEL 3
1653
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001655 * Isolate one argument, taking backticks.
1656 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001657 * Return a pointer to the start of the next argument.
1658 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001659 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001660do_one_arg(str)
1661 char_u *str;
1662{
1663 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664 int inbacktick;
1665
Bram Moolenaar071d4272004-06-13 20:20:40 +00001666 inbacktick = FALSE;
1667 for (p = str; *str; ++str)
1668 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001669 /* When the backslash is used for escaping the special meaning of a
1670 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001671 if (rem_backslash(str))
1672 {
1673 *p++ = *str++;
1674 *p++ = *str;
1675 }
1676 else
1677 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001678 /* An item ends at a space not in backticks */
1679 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001680 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001681 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001682 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001683 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684 }
1685 }
1686 str = skipwhite(str);
1687 *p = NUL;
1688
1689 return str;
1690}
1691
Bram Moolenaar86b68352004-12-27 21:59:20 +00001692/*
1693 * Separate the arguments in "str" and return a list of pointers in the
1694 * growarray "gap".
1695 */
1696 int
1697get_arglist(gap, str)
1698 garray_T *gap;
1699 char_u *str;
1700{
1701 ga_init2(gap, (int)sizeof(char_u *), 20);
1702 while (*str != NUL)
1703 {
1704 if (ga_grow(gap, 1) == FAIL)
1705 {
1706 ga_clear(gap);
1707 return FAIL;
1708 }
1709 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1710
1711 /* Isolate one argument, change it in-place, put a NUL after it. */
1712 str = do_one_arg(str);
1713 }
1714 return OK;
1715}
1716
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001717#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001718/*
1719 * Parse a list of arguments (file names), expand them and return in
1720 * "fnames[fcountp]".
1721 * Return FAIL or OK.
1722 */
1723 int
1724get_arglist_exp(str, fcountp, fnamesp)
1725 char_u *str;
1726 int *fcountp;
1727 char_u ***fnamesp;
1728{
1729 garray_T ga;
1730 int i;
1731
1732 if (get_arglist(&ga, str) == FAIL)
1733 return FAIL;
1734 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1735 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1736 ga_clear(&ga);
1737 return i;
1738}
1739#endif
1740
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1742/*
1743 * Redefine the argument list.
1744 */
1745 void
1746set_arglist(str)
1747 char_u *str;
1748{
1749 do_arglist(str, AL_SET, 0);
1750}
1751#endif
1752
1753/*
1754 * "what" == AL_SET: Redefine the argument list to 'str'.
1755 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1756 * "what" == AL_DEL: remove files in 'str' from the argument list.
1757 *
1758 * Return FAIL for failure, OK otherwise.
1759 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760 static int
1761do_arglist(str, what, after)
1762 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001763 int what UNUSED;
1764 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765{
1766 garray_T new_ga;
1767 int exp_count;
1768 char_u **exp_files;
1769 int i;
1770#ifdef FEAT_LISTCMDS
1771 char_u *p;
1772 int match;
1773#endif
1774
1775 /*
1776 * Collect all file name arguments in "new_ga".
1777 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001778 if (get_arglist(&new_ga, str) == FAIL)
1779 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780
1781#ifdef FEAT_LISTCMDS
1782 if (what == AL_DEL)
1783 {
1784 regmatch_T regmatch;
1785 int didone;
1786
1787 /*
1788 * Delete the items: use each item as a regexp and find a match in the
1789 * argument list.
1790 */
1791#ifdef CASE_INSENSITIVE_FILENAME
1792 regmatch.rm_ic = TRUE; /* Always ignore case */
1793#else
1794 regmatch.rm_ic = FALSE; /* Never ignore case */
1795#endif
1796 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1797 {
1798 p = ((char_u **)new_ga.ga_data)[i];
1799 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1800 if (p == NULL)
1801 break;
1802 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1803 if (regmatch.regprog == NULL)
1804 {
1805 vim_free(p);
1806 break;
1807 }
1808
1809 didone = FALSE;
1810 for (match = 0; match < ARGCOUNT; ++match)
1811 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1812 (colnr_T)0))
1813 {
1814 didone = TRUE;
1815 vim_free(ARGLIST[match].ae_fname);
1816 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1817 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1818 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819 if (curwin->w_arg_idx > match)
1820 --curwin->w_arg_idx;
1821 --match;
1822 }
1823
1824 vim_free(regmatch.regprog);
1825 vim_free(p);
1826 if (!didone)
1827 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1828 }
1829 ga_clear(&new_ga);
1830 }
1831 else
1832#endif
1833 {
1834 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1835 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1836 ga_clear(&new_ga);
1837 if (i == FAIL)
1838 return FAIL;
1839 if (exp_count == 0)
1840 {
1841 EMSG(_(e_nomatch));
1842 return FAIL;
1843 }
1844
1845#ifdef FEAT_LISTCMDS
1846 if (what == AL_ADD)
1847 {
1848 (void)alist_add_list(exp_count, exp_files, after);
1849 vim_free(exp_files);
1850 }
1851 else /* what == AL_SET */
1852#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001853 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854 }
1855
1856 alist_check_arg_idx();
1857
1858 return OK;
1859}
1860
1861/*
1862 * Check the validity of the arg_idx for each other window.
1863 */
1864 static void
1865alist_check_arg_idx()
1866{
1867#ifdef FEAT_WINDOWS
1868 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001869 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001870
Bram Moolenaarf740b292006-02-16 22:11:02 +00001871 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 if (win->w_alist == curwin->w_alist)
1873 check_arg_idx(win);
1874#else
1875 check_arg_idx(curwin);
1876#endif
1877}
1878
1879/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001880 * Return TRUE if window "win" is editing then file at the current argument
1881 * index.
1882 */
1883 static int
1884editing_arg_idx(win)
1885 win_T *win;
1886{
1887 return !(win->w_arg_idx >= WARGCOUNT(win)
1888 || (win->w_buffer->b_fnum
1889 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1890 && (win->w_buffer->b_ffname == NULL
1891 || !(fullpathcmp(
1892 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1893 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1894}
1895
1896/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897 * Check if window "win" is editing the w_arg_idx file in its argument list.
1898 */
1899 void
1900check_arg_idx(win)
1901 win_T *win;
1902{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001903 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 {
1905 /* We are not editing the current entry in the argument list.
1906 * Set "arg_had_last" if we are editing the last one. */
1907 win->w_arg_idx_invalid = TRUE;
1908 if (win->w_arg_idx != WARGCOUNT(win) - 1
1909 && arg_had_last == FALSE
1910#ifdef FEAT_WINDOWS
1911 && ALIST(win) == &global_alist
1912#endif
1913 && GARGCOUNT > 0
1914 && win->w_arg_idx < GARGCOUNT
1915 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1916 || (win->w_buffer->b_ffname != NULL
1917 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1918 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1919 arg_had_last = TRUE;
1920 }
1921 else
1922 {
1923 /* We are editing the current entry in the argument list.
1924 * Set "arg_had_last" if it's also the last one */
1925 win->w_arg_idx_invalid = FALSE;
1926 if (win->w_arg_idx == WARGCOUNT(win) - 1
1927#ifdef FEAT_WINDOWS
1928 && win->w_alist == &global_alist
1929#endif
1930 )
1931 arg_had_last = TRUE;
1932 }
1933}
1934
1935/*
1936 * ":args", ":argslocal" and ":argsglobal".
1937 */
1938 void
1939ex_args(eap)
1940 exarg_T *eap;
1941{
1942 int i;
1943
1944 if (eap->cmdidx != CMD_args)
1945 {
1946#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1947 alist_unlink(ALIST(curwin));
1948 if (eap->cmdidx == CMD_argglobal)
1949 ALIST(curwin) = &global_alist;
1950 else /* eap->cmdidx == CMD_arglocal */
1951 alist_new();
1952#else
1953 ex_ni(eap);
1954 return;
1955#endif
1956 }
1957
1958 if (!ends_excmd(*eap->arg))
1959 {
1960 /*
1961 * ":args file ..": define new argument list, handle like ":next"
1962 * Also for ":argslocal file .." and ":argsglobal file ..".
1963 */
1964 ex_next(eap);
1965 }
1966 else
1967#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1968 if (eap->cmdidx == CMD_args)
1969#endif
1970 {
1971 /*
1972 * ":args": list arguments.
1973 */
1974 if (ARGCOUNT > 0)
1975 {
1976 /* Overwrite the command, for a short list there is no scrolling
1977 * required and no wait_return(). */
1978 gotocmdline(TRUE);
1979 for (i = 0; i < ARGCOUNT; ++i)
1980 {
1981 if (i == curwin->w_arg_idx)
1982 msg_putchar('[');
1983 msg_outtrans(alist_name(&ARGLIST[i]));
1984 if (i == curwin->w_arg_idx)
1985 msg_putchar(']');
1986 msg_putchar(' ');
1987 }
1988 }
1989 }
1990#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1991 else if (eap->cmdidx == CMD_arglocal)
1992 {
1993 garray_T *gap = &curwin->w_alist->al_ga;
1994
1995 /*
1996 * ":argslocal": make a local copy of the global argument list.
1997 */
1998 if (ga_grow(gap, GARGCOUNT) == OK)
1999 for (i = 0; i < GARGCOUNT; ++i)
2000 if (GARGLIST[i].ae_fname != NULL)
2001 {
2002 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2003 vim_strsave(GARGLIST[i].ae_fname);
2004 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2005 GARGLIST[i].ae_fnum;
2006 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002007 }
2008 }
2009#endif
2010}
2011
2012/*
2013 * ":previous", ":sprevious", ":Next" and ":sNext".
2014 */
2015 void
2016ex_previous(eap)
2017 exarg_T *eap;
2018{
2019 /* If past the last one already, go to the last one. */
2020 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2021 do_argfile(eap, ARGCOUNT - 1);
2022 else
2023 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2024}
2025
2026/*
2027 * ":rewind", ":first", ":sfirst" and ":srewind".
2028 */
2029 void
2030ex_rewind(eap)
2031 exarg_T *eap;
2032{
2033 do_argfile(eap, 0);
2034}
2035
2036/*
2037 * ":last" and ":slast".
2038 */
2039 void
2040ex_last(eap)
2041 exarg_T *eap;
2042{
2043 do_argfile(eap, ARGCOUNT - 1);
2044}
2045
2046/*
2047 * ":argument" and ":sargument".
2048 */
2049 void
2050ex_argument(eap)
2051 exarg_T *eap;
2052{
2053 int i;
2054
2055 if (eap->addr_count > 0)
2056 i = eap->line2 - 1;
2057 else
2058 i = curwin->w_arg_idx;
2059 do_argfile(eap, i);
2060}
2061
2062/*
2063 * Edit file "argn" of the argument lists.
2064 */
2065 void
2066do_argfile(eap, argn)
2067 exarg_T *eap;
2068 int argn;
2069{
2070 int other;
2071 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002072 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073
2074 if (argn < 0 || argn >= ARGCOUNT)
2075 {
2076 if (ARGCOUNT <= 1)
2077 EMSG(_("E163: There is only one file to edit"));
2078 else if (argn < 0)
2079 EMSG(_("E164: Cannot go before first file"));
2080 else
2081 EMSG(_("E165: Cannot go beyond last file"));
2082 }
2083 else
2084 {
2085 setpcmark();
2086#ifdef FEAT_GUI
2087 need_mouse_correct = TRUE;
2088#endif
2089
2090#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002091 /* split window or create new tab page first */
2092 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093 {
2094 if (win_split(0, 0) == FAIL)
2095 return;
2096# ifdef FEAT_SCROLLBIND
2097 curwin->w_p_scb = FALSE;
2098# endif
2099 }
2100 else
2101#endif
2102 {
2103 /*
2104 * if 'hidden' set, only check for changed file when re-editing
2105 * the same buffer
2106 */
2107 other = TRUE;
2108 if (P_HID(curbuf))
2109 {
2110 p = fix_fname(alist_name(&ARGLIST[argn]));
2111 other = otherfile(p);
2112 vim_free(p);
2113 }
2114 if ((!P_HID(curbuf) || !other)
2115 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2116 return;
2117 }
2118
2119 curwin->w_arg_idx = argn;
2120 if (argn == ARGCOUNT - 1
2121#ifdef FEAT_WINDOWS
2122 && curwin->w_alist == &global_alist
2123#endif
2124 )
2125 arg_had_last = TRUE;
2126
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002127 /* Edit the file; always use the last known line number.
2128 * When it fails (e.g. Abort for already edited file) restore the
2129 * argument index. */
2130 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002132 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2133 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002134 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002135 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002136 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137 setmark('\'');
2138 }
2139}
2140
2141/*
2142 * ":next", and commands that behave like it.
2143 */
2144 void
2145ex_next(eap)
2146 exarg_T *eap;
2147{
2148 int i;
2149
2150 /*
2151 * check for changed buffer now, if this fails the argument list is not
2152 * redefined.
2153 */
2154 if ( P_HID(curbuf)
2155 || eap->cmdidx == CMD_snext
2156 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2157 {
2158 if (*eap->arg != NUL) /* redefine file list */
2159 {
2160 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2161 return;
2162 i = 0;
2163 }
2164 else
2165 i = curwin->w_arg_idx + (int)eap->line2;
2166 do_argfile(eap, i);
2167 }
2168}
2169
2170#ifdef FEAT_LISTCMDS
2171/*
2172 * ":argedit"
2173 */
2174 void
2175ex_argedit(eap)
2176 exarg_T *eap;
2177{
2178 int fnum;
2179 int i;
2180 char_u *s;
2181
2182 /* Add the argument to the buffer list and get the buffer number. */
2183 fnum = buflist_add(eap->arg, BLN_LISTED);
2184
2185 /* Check if this argument is already in the argument list. */
2186 for (i = 0; i < ARGCOUNT; ++i)
2187 if (ARGLIST[i].ae_fnum == fnum)
2188 break;
2189 if (i == ARGCOUNT)
2190 {
2191 /* Can't find it, add it to the argument list. */
2192 s = vim_strsave(eap->arg);
2193 if (s == NULL)
2194 return;
2195 i = alist_add_list(1, &s,
2196 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2197 if (i < 0)
2198 return;
2199 curwin->w_arg_idx = i;
2200 }
2201
2202 alist_check_arg_idx();
2203
2204 /* Edit the argument. */
2205 do_argfile(eap, i);
2206}
2207
2208/*
2209 * ":argadd"
2210 */
2211 void
2212ex_argadd(eap)
2213 exarg_T *eap;
2214{
2215 do_arglist(eap->arg, AL_ADD,
2216 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2217#ifdef FEAT_TITLE
2218 maketitle();
2219#endif
2220}
2221
2222/*
2223 * ":argdelete"
2224 */
2225 void
2226ex_argdelete(eap)
2227 exarg_T *eap;
2228{
2229 int i;
2230 int n;
2231
2232 if (eap->addr_count > 0)
2233 {
2234 /* ":1,4argdel": Delete all arguments in the range. */
2235 if (eap->line2 > ARGCOUNT)
2236 eap->line2 = ARGCOUNT;
2237 n = eap->line2 - eap->line1 + 1;
2238 if (*eap->arg != NUL || n <= 0)
2239 EMSG(_(e_invarg));
2240 else
2241 {
2242 for (i = eap->line1; i <= eap->line2; ++i)
2243 vim_free(ARGLIST[i - 1].ae_fname);
2244 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2245 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2246 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002247 if (curwin->w_arg_idx >= eap->line2)
2248 curwin->w_arg_idx -= n;
2249 else if (curwin->w_arg_idx > eap->line1)
2250 curwin->w_arg_idx = eap->line1;
2251 }
2252 }
2253 else if (*eap->arg == NUL)
2254 EMSG(_(e_argreq));
2255 else
2256 do_arglist(eap->arg, AL_DEL, 0);
2257#ifdef FEAT_TITLE
2258 maketitle();
2259#endif
2260}
2261
2262/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002263 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002264 */
2265 void
2266ex_listdo(eap)
2267 exarg_T *eap;
2268{
2269 int i;
2270#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002271 win_T *wp;
2272 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273#endif
2274 buf_T *buf;
2275 int next_fnum = 0;
2276#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2277 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002279 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002280
2281#ifndef FEAT_WINDOWS
2282 if (eap->cmdidx == CMD_windo)
2283 {
2284 ex_ni(eap);
2285 return;
2286 }
2287#endif
2288
2289#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002290 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002291 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2292 * great speed improvement. */
2293 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002294#endif
2295
2296 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002297 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002298 || P_HID(curbuf)
2299 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2300 {
2301 /* start at the first argument/window/buffer */
2302 i = 0;
2303#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002304 wp = firstwin;
2305 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306#endif
2307 /* set pcmark now */
2308 if (eap->cmdidx == CMD_bufdo)
2309 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2310 else
2311 setpcmark();
2312 listcmd_busy = TRUE; /* avoids setting pcmark below */
2313
2314 while (!got_int)
2315 {
2316 if (eap->cmdidx == CMD_argdo)
2317 {
2318 /* go to argument "i" */
2319 if (i == ARGCOUNT)
2320 break;
2321 /* Don't call do_argfile() when already there, it will try
2322 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002323 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002324 {
2325 /* Clear 'shm' to avoid that the file message overwrites
2326 * any output from the command. */
2327 p_shm_save = vim_strsave(p_shm);
2328 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002330 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2331 vim_free(p_shm_save);
2332 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333 if (curwin->w_arg_idx != i)
2334 break;
2335 ++i;
2336 }
2337#ifdef FEAT_WINDOWS
2338 else if (eap->cmdidx == CMD_windo)
2339 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002340 /* go to window "wp" */
2341 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002343 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002344 if (curwin != wp)
2345 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002346 wp = curwin->w_next;
2347 }
2348 else if (eap->cmdidx == CMD_tabdo)
2349 {
2350 /* go to window "tp" */
2351 if (!valid_tabpage(tp))
2352 break;
2353 goto_tabpage_tp(tp);
2354 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355 }
2356#endif
2357 else if (eap->cmdidx == CMD_bufdo)
2358 {
2359 /* Remember the number of the next listed buffer, in case
2360 * ":bwipe" is used or autocommands do something strange. */
2361 next_fnum = -1;
2362 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2363 if (buf->b_p_bl)
2364 {
2365 next_fnum = buf->b_fnum;
2366 break;
2367 }
2368 }
2369
2370 /* execute the command */
2371 do_cmdline(eap->arg, eap->getline, eap->cookie,
2372 DOCMD_VERBOSE + DOCMD_NOWAIT);
2373
2374 if (eap->cmdidx == CMD_bufdo)
2375 {
2376 /* Done? */
2377 if (next_fnum < 0)
2378 break;
2379 /* Check if the buffer still exists. */
2380 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2381 if (buf->b_fnum == next_fnum)
2382 break;
2383 if (buf == NULL)
2384 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002385
2386 /* Go to the next buffer. Clear 'shm' to avoid that the file
2387 * message overwrites any output from the command. */
2388 p_shm_save = vim_strsave(p_shm);
2389 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002391 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2392 vim_free(p_shm_save);
2393
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394 /* If autocommands took us elsewhere, quit here */
2395 if (curbuf->b_fnum != next_fnum)
2396 break;
2397 }
2398
2399 if (eap->cmdidx == CMD_windo)
2400 {
2401 validate_cursor(); /* cursor may have moved */
2402#ifdef FEAT_SCROLLBIND
2403 /* required when 'scrollbind' has been set */
2404 if (curwin->w_p_scb)
2405 do_check_scrollbind(TRUE);
2406#endif
2407 }
2408 }
2409 listcmd_busy = FALSE;
2410 }
2411
2412#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002413 if (save_ei != NULL)
2414 {
2415 au_event_restore(save_ei);
2416 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2417 curbuf->b_fname, TRUE, curbuf);
2418 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002419#endif
2420}
2421
2422/*
2423 * Add files[count] to the arglist of the current window after arg "after".
2424 * The file names in files[count] must have been allocated and are taken over.
2425 * Files[] itself is not taken over.
2426 * Returns index of first added argument. Returns -1 when failed (out of mem).
2427 */
2428 static int
2429alist_add_list(count, files, after)
2430 int count;
2431 char_u **files;
2432 int after; /* where to add: 0 = before first one */
2433{
2434 int i;
2435
2436 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2437 {
2438 if (after < 0)
2439 after = 0;
2440 if (after > ARGCOUNT)
2441 after = ARGCOUNT;
2442 if (after < ARGCOUNT)
2443 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2444 (ARGCOUNT - after) * sizeof(aentry_T));
2445 for (i = 0; i < count; ++i)
2446 {
2447 ARGLIST[after + i].ae_fname = files[i];
2448 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2449 }
2450 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451 if (curwin->w_arg_idx >= after)
2452 ++curwin->w_arg_idx;
2453 return after;
2454 }
2455
2456 for (i = 0; i < count; ++i)
2457 vim_free(files[i]);
2458 return -1;
2459}
2460
2461#endif /* FEAT_LISTCMDS */
2462
2463#ifdef FEAT_EVAL
2464/*
2465 * ":compiler[!] {name}"
2466 */
2467 void
2468ex_compiler(eap)
2469 exarg_T *eap;
2470{
2471 char_u *buf;
2472 char_u *old_cur_comp = NULL;
2473 char_u *p;
2474
2475 if (*eap->arg == NUL)
2476 {
2477 /* List all compiler scripts. */
2478 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2479 /* ) keep the indenter happy... */
2480 }
2481 else
2482 {
2483 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2484 if (buf != NULL)
2485 {
2486 if (eap->forceit)
2487 {
2488 /* ":compiler! {name}" sets global options */
2489 do_cmdline_cmd((char_u *)
2490 "command -nargs=* CompilerSet set <args>");
2491 }
2492 else
2493 {
2494 /* ":compiler! {name}" sets local options.
2495 * To remain backwards compatible "current_compiler" is always
2496 * used. A user's compiler plugin may set it, the distributed
2497 * plugin will then skip the settings. Afterwards set
2498 * "b:current_compiler" and restore "current_compiler". */
2499 old_cur_comp = get_var_value((char_u *)"current_compiler");
2500 if (old_cur_comp != NULL)
2501 old_cur_comp = vim_strsave(old_cur_comp);
2502 do_cmdline_cmd((char_u *)
2503 "command -nargs=* CompilerSet setlocal <args>");
2504 }
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002505 do_unlet((char_u *)"current_compiler", TRUE);
2506 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507
2508 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002509 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2511 vim_free(buf);
2512
2513 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2514
2515 /* Set "b:current_compiler" from "current_compiler". */
2516 p = get_var_value((char_u *)"current_compiler");
2517 if (p != NULL)
2518 set_internal_string_var((char_u *)"b:current_compiler", p);
2519
2520 /* Restore "current_compiler" for ":compiler {name}". */
2521 if (!eap->forceit)
2522 {
2523 if (old_cur_comp != NULL)
2524 {
2525 set_internal_string_var((char_u *)"current_compiler",
2526 old_cur_comp);
2527 vim_free(old_cur_comp);
2528 }
2529 else
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002530 do_unlet((char_u *)"current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531 }
2532 }
2533 }
2534}
2535#endif
2536
2537/*
2538 * ":runtime {name}"
2539 */
2540 void
2541ex_runtime(eap)
2542 exarg_T *eap;
2543{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002544 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002545}
2546
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002547static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548
2549 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002550source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002551 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002552 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002553{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002554 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555}
2556
2557/*
2558 * Source the file "name" from all directories in 'runtimepath'.
2559 * "name" can contain wildcards.
2560 * When "all" is TRUE, source all files, otherwise only the first one.
2561 * return FAIL when no file could be sourced, OK otherwise.
2562 */
2563 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002564source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565 char_u *name;
2566 int all;
2567{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002568 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002569}
2570
2571/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002572 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2573 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2575 * used.
2576 * Returns OK when at least one match found, FAIL otherwise.
2577 */
2578 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002579do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580 char_u *name;
2581 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002582 void (*callback)__ARGS((char_u *fname, void *ck));
2583 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584{
2585 char_u *rtp;
2586 char_u *np;
2587 char_u *buf;
2588 char_u *rtp_copy;
2589 char_u *tail;
2590 int num_files;
2591 char_u **files;
2592 int i;
2593 int did_one = FALSE;
2594#ifdef AMIGA
2595 struct Process *proc = (struct Process *)FindTask(0L);
2596 APTR save_winptr = proc->pr_WindowPtr;
2597
2598 /* Avoid a requester here for a volume that doesn't exist. */
2599 proc->pr_WindowPtr = (APTR)-1L;
2600#endif
2601
2602 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2603 * value. */
2604 rtp_copy = vim_strsave(p_rtp);
2605 buf = alloc(MAXPATHL);
2606 if (buf != NULL && rtp_copy != NULL)
2607 {
2608 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002609 {
2610 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002611 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002613 verbose_leave();
2614 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002615
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616 /* Loop over all entries in 'runtimepath'. */
2617 rtp = rtp_copy;
2618 while (*rtp != NUL && (all || !did_one))
2619 {
2620 /* Copy the path from 'runtimepath' to buf[]. */
2621 copy_option_part(&rtp, buf, MAXPATHL, ",");
2622 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2623 {
2624 add_pathsep(buf);
2625 tail = buf + STRLEN(buf);
2626
2627 /* Loop over all patterns in "name" */
2628 np = name;
2629 while (*np != NUL && (all || !did_one))
2630 {
2631 /* Append the pattern from "name" to buf[]. */
2632 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2633 "\t ");
2634
2635 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002636 {
2637 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002638 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002639 verbose_leave();
2640 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641
2642 /* Expand wildcards, invoke the callback for each match. */
2643 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2644 EW_FILE) == OK)
2645 {
2646 for (i = 0; i < num_files; ++i)
2647 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002648 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649 did_one = TRUE;
2650 if (!all)
2651 break;
2652 }
2653 FreeWild(num_files, files);
2654 }
2655 }
2656 }
2657 }
2658 }
2659 vim_free(buf);
2660 vim_free(rtp_copy);
2661 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002662 {
2663 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002664 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002665 verbose_leave();
2666 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667
2668#ifdef AMIGA
2669 proc->pr_WindowPtr = save_winptr;
2670#endif
2671
2672 return did_one ? OK : FAIL;
2673}
2674
2675#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2676/*
2677 * ":options"
2678 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679 void
2680ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002681 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682{
2683 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2684}
2685#endif
2686
2687/*
2688 * ":source {fname}"
2689 */
2690 void
2691ex_source(eap)
2692 exarg_T *eap;
2693{
2694#ifdef FEAT_BROWSE
2695 if (cmdmod.browse)
2696 {
2697 char_u *fname = NULL;
2698
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002699 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2701 if (fname != NULL)
2702 {
2703 cmd_source(fname, eap);
2704 vim_free(fname);
2705 }
2706 }
2707 else
2708#endif
2709 cmd_source(eap->arg, eap);
2710}
2711
2712 static void
2713cmd_source(fname, eap)
2714 char_u *fname;
2715 exarg_T *eap;
2716{
2717 if (*fname == NUL)
2718 EMSG(_(e_argreq));
2719
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002721 /* ":source!": read Normal mdoe commands
2722 * Need to execute the commands directly. This is required at least
2723 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 * - ":g" command busy
2725 * - after ":argdo", ":windo" or ":bufdo"
2726 * - another command follows
2727 * - inside a loop
2728 */
2729 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2730#ifdef FEAT_EVAL
2731 || eap->cstack->cs_idx >= 0
2732#endif
2733 );
2734
2735 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002736 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 EMSG2(_(e_notopen), fname);
2738}
2739
2740/*
2741 * ":source" and associated commands.
2742 */
2743/*
2744 * Structure used to store info for each sourced file.
2745 * It is shared between do_source() and getsourceline().
2746 * This is required, because it needs to be handed to do_cmdline() and
2747 * sourcing can be done recursively.
2748 */
2749struct source_cookie
2750{
2751 FILE *fp; /* opened file for sourcing */
2752 char_u *nextline; /* if not NULL: line that was read ahead */
2753 int finished; /* ":finish" used */
2754#if defined (USE_CRNL) || defined (USE_CR)
2755 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2756 int error; /* TRUE if LF found after CR-LF */
2757#endif
2758#ifdef FEAT_EVAL
2759 linenr_T breakpoint; /* next line with breakpoint or zero */
2760 char_u *fname; /* name of sourced file */
2761 int dbg_tick; /* debug_tick when breakpoint was set */
2762 int level; /* top nesting level of sourced file */
2763#endif
2764#ifdef FEAT_MBYTE
2765 vimconv_T conv; /* type of conversion */
2766#endif
2767};
2768
2769#ifdef FEAT_EVAL
2770/*
2771 * Return the address holding the next breakpoint line for a source cookie.
2772 */
2773 linenr_T *
2774source_breakpoint(cookie)
2775 void *cookie;
2776{
2777 return &((struct source_cookie *)cookie)->breakpoint;
2778}
2779
2780/*
2781 * Return the address holding the debug tick for a source cookie.
2782 */
2783 int *
2784source_dbg_tick(cookie)
2785 void *cookie;
2786{
2787 return &((struct source_cookie *)cookie)->dbg_tick;
2788}
2789
2790/*
2791 * Return the nesting level for a source cookie.
2792 */
2793 int
2794source_level(cookie)
2795 void *cookie;
2796{
2797 return ((struct source_cookie *)cookie)->level;
2798}
2799#endif
2800
2801static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2802
Bram Moolenaar071d4272004-06-13 20:20:40 +00002803#if defined(WIN32) && defined(FEAT_CSCOPE)
2804static FILE *fopen_noinh_readbin __ARGS((char *filename));
2805
2806/*
2807 * Special function to open a file without handle inheritance.
2808 */
2809 static FILE *
2810fopen_noinh_readbin(filename)
2811 char *filename;
2812{
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00002813 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814
2815 if (fd_tmp == -1)
2816 return NULL;
2817 return fdopen(fd_tmp, READBIN);
2818}
2819#endif
2820
2821
2822/*
2823 * do_source: Read the file "fname" and execute its lines as EX commands.
2824 *
2825 * This function may be called recursively!
2826 *
2827 * return FAIL if file could not be opened, OK otherwise
2828 */
2829 int
2830do_source(fname, check_other, is_vimrc)
2831 char_u *fname;
2832 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002833 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002834{
2835 struct source_cookie cookie;
2836 char_u *save_sourcing_name;
2837 linenr_T save_sourcing_lnum;
2838 char_u *p;
2839 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002840 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841 int retval = FAIL;
2842#ifdef FEAT_EVAL
2843 scid_T save_current_SID;
2844 static scid_T last_current_SID = 0;
2845 void *save_funccalp;
2846 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002847 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848# ifdef UNIX
2849 struct stat st;
2850 int stat_ok;
2851# endif
2852#endif
2853#ifdef STARTUPTIME
2854 struct timeval tv_rel;
2855 struct timeval tv_start;
2856#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002857#ifdef FEAT_PROFILE
2858 proftime_T wait_start;
2859#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002860
2861#ifdef RISCOS
2862 p = mch_munge_fname(fname);
2863#else
2864 p = expand_env_save(fname);
2865#endif
2866 if (p == NULL)
2867 return retval;
2868 fname_exp = fix_fname(p);
2869 vim_free(p);
2870 if (fname_exp == NULL)
2871 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872 if (mch_isdir(fname_exp))
2873 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002874 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002875 goto theend;
2876 }
2877
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002878#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002879 /* Apply SourceCmd autocommands, they should get the file and source it. */
2880 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2881 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2882 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002883 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002884# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002885 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002886# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002887 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002888# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002889 goto theend;
2890 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002891
2892 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002893 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2894#endif
2895
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896#if defined(WIN32) && defined(FEAT_CSCOPE)
2897 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2898#else
2899 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2900#endif
2901 if (cookie.fp == NULL && check_other)
2902 {
2903 /*
2904 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2905 * and ".exrc" by "_exrc" or vice versa.
2906 */
2907 p = gettail(fname_exp);
2908 if ((*p == '.' || *p == '_')
2909 && (STRICMP(p + 1, "vimrc") == 0
2910 || STRICMP(p + 1, "gvimrc") == 0
2911 || STRICMP(p + 1, "exrc") == 0))
2912 {
2913 if (*p == '_')
2914 *p = '.';
2915 else
2916 *p = '_';
2917#if defined(WIN32) && defined(FEAT_CSCOPE)
2918 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2919#else
2920 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2921#endif
2922 }
2923 }
2924
2925 if (cookie.fp == NULL)
2926 {
2927 if (p_verbose > 0)
2928 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002929 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002930 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002931 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932 else
2933 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002934 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002935 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936 }
2937 goto theend;
2938 }
2939
2940 /*
2941 * The file exists.
2942 * - In verbose mode, give a message.
2943 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2944 */
2945 if (p_verbose > 1)
2946 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002947 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002949 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950 else
2951 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002952 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002953 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002955 if (is_vimrc == DOSO_VIMRC)
2956 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
2957 else if (is_vimrc == DOSO_GVIMRC)
2958 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959
2960#ifdef USE_CRNL
2961 /* If no automatic file format: Set default to CR-NL. */
2962 if (*p_ffs == NUL)
2963 cookie.fileformat = EOL_DOS;
2964 else
2965 cookie.fileformat = EOL_UNKNOWN;
2966 cookie.error = FALSE;
2967#endif
2968
2969#ifdef USE_CR
2970 /* If no automatic file format: Set default to CR. */
2971 if (*p_ffs == NUL)
2972 cookie.fileformat = EOL_MAC;
2973 else
2974 cookie.fileformat = EOL_UNKNOWN;
2975 cookie.error = FALSE;
2976#endif
2977
2978 cookie.nextline = NULL;
2979 cookie.finished = FALSE;
2980
2981#ifdef FEAT_EVAL
2982 /*
2983 * Check if this script has a breakpoint.
2984 */
2985 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2986 cookie.fname = fname_exp;
2987 cookie.dbg_tick = debug_tick;
2988
2989 cookie.level = ex_nesting_level;
2990#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002991
2992 /*
2993 * Keep the sourcing name/lnum, for recursive calls.
2994 */
2995 save_sourcing_name = sourcing_name;
2996 sourcing_name = fname_exp;
2997 save_sourcing_lnum = sourcing_lnum;
2998 sourcing_lnum = 0;
2999
Bram Moolenaar73881402009-02-04 16:50:47 +00003000#ifdef FEAT_MBYTE
3001 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3002
3003 /* Read the first line so we can check for a UTF-8 BOM. */
3004 firstline = getsourceline(0, (void *)&cookie, 0);
3005 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3006 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3007 {
3008 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3009 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3010 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003011 if (p == NULL)
3012 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003013 if (p != NULL)
3014 {
3015 vim_free(firstline);
3016 firstline = p;
3017 }
3018 }
3019#endif
3020
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021#ifdef STARTUPTIME
3022 time_push(&tv_rel, &tv_start);
3023#endif
3024
3025#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003026# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003027 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003028 prof_child_enter(&wait_start); /* entering a child now */
3029# endif
3030
3031 /* Don't use local function variables, if called from a function.
3032 * Also starts profiling timer for nested script. */
3033 save_funccalp = save_funccal();
3034
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035 /*
3036 * Check if this script was sourced before to finds its SID.
3037 * If it's new, generate a new SID.
3038 */
3039 save_current_SID = current_SID;
3040# ifdef UNIX
3041 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3042# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003043 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3044 {
3045 si = &SCRIPT_ITEM(current_SID);
3046 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003047 && (
3048# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003049 /* Compare dev/ino when possible, it catches symbolic
3050 * links. Also compare file names, the inode may change
3051 * when the file was edited. */
Bram Moolenaar05159a02005-02-26 23:04:13 +00003052 ((stat_ok && si->sn_dev != -1)
3053 && (si->sn_dev == st.st_dev
3054 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003056 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003058 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059 if (current_SID == 0)
3060 {
3061 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003062 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3063 == FAIL)
3064 goto almosttheend;
3065 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003067 ++script_items.ga_len;
3068 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3069# ifdef FEAT_PROFILE
3070 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003073 si = &SCRIPT_ITEM(current_SID);
3074 si->sn_name = fname_exp;
3075 fname_exp = NULL;
3076# ifdef UNIX
3077 if (stat_ok)
3078 {
3079 si->sn_dev = st.st_dev;
3080 si->sn_ino = st.st_ino;
3081 }
3082 else
3083 si->sn_dev = -1;
3084# endif
3085
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086 /* Allocate the local script variables to use for this script. */
3087 new_script_vars(current_SID);
3088 }
3089
Bram Moolenaar05159a02005-02-26 23:04:13 +00003090# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003091 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003092 {
3093 int forceit;
3094
3095 /* Check if we do profiling for this script. */
3096 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3097 {
3098 script_do_profile(si);
3099 si->sn_pr_force = forceit;
3100 }
3101 if (si->sn_prof_on)
3102 {
3103 ++si->sn_pr_count;
3104 profile_start(&si->sn_pr_start);
3105 profile_zero(&si->sn_pr_children);
3106 }
3107 }
3108# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003109#endif
3110
3111 /*
3112 * Call do_cmdline, which will call getsourceline() to get the lines.
3113 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003114 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003115 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003117
3118#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003119 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003120 {
3121 /* Get "si" again, "script_items" may have been reallocated. */
3122 si = &SCRIPT_ITEM(current_SID);
3123 if (si->sn_prof_on)
3124 {
3125 profile_end(&si->sn_pr_start);
3126 profile_sub_wait(&wait_start, &si->sn_pr_start);
3127 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003128 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3129 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003130 }
3131 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132#endif
3133
3134 if (got_int)
3135 EMSG(_(e_interr));
3136 sourcing_name = save_sourcing_name;
3137 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 if (p_verbose > 1)
3139 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003140 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003141 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003143 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003144 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145 }
3146#ifdef STARTUPTIME
Bram Moolenaare511f292008-09-07 13:50:37 +00003147 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3148 time_msg((char *)IObuff, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149 time_pop(&tv_rel);
3150#endif
3151
3152#ifdef FEAT_EVAL
3153 /*
3154 * After a "finish" in debug mode, need to break at first command of next
3155 * sourced file.
3156 */
3157 if (save_debug_break_level > ex_nesting_level
3158 && debug_break_level == ex_nesting_level)
3159 ++debug_break_level;
3160#endif
3161
Bram Moolenaar05159a02005-02-26 23:04:13 +00003162#ifdef FEAT_EVAL
3163almosttheend:
3164 current_SID = save_current_SID;
3165 restore_funccal(save_funccalp);
3166# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003167 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003168 prof_child_exit(&wait_start); /* leaving a child now */
3169# endif
3170#endif
3171 fclose(cookie.fp);
3172 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003173 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003174#ifdef FEAT_MBYTE
3175 convert_setup(&cookie.conv, NULL, NULL);
3176#endif
3177
Bram Moolenaar071d4272004-06-13 20:20:40 +00003178theend:
3179 vim_free(fname_exp);
3180 return retval;
3181}
3182
3183#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003184
Bram Moolenaar071d4272004-06-13 20:20:40 +00003185/*
3186 * ":scriptnames"
3187 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003188 void
3189ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003190 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003191{
3192 int i;
3193
Bram Moolenaar05159a02005-02-26 23:04:13 +00003194 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3195 if (SCRIPT_ITEM(i).sn_name != NULL)
3196 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197}
3198
3199# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3200/*
3201 * Fix slashes in the list of script names for 'shellslash'.
3202 */
3203 void
3204scriptnames_slash_adjust()
3205{
3206 int i;
3207
Bram Moolenaar05159a02005-02-26 23:04:13 +00003208 for (i = 1; i <= script_items.ga_len; ++i)
3209 if (SCRIPT_ITEM(i).sn_name != NULL)
3210 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211}
3212# endif
3213
3214/*
3215 * Get a pointer to a script name. Used for ":verbose set".
3216 */
3217 char_u *
3218get_scriptname(id)
3219 scid_T id;
3220{
3221 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003222 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003224 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003226 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003228 return (char_u *)_("environment variable");
3229 if (id == SID_ERROR)
3230 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003231 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003232}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003233
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003234# if defined(EXITFREE) || defined(PROTO)
3235 void
3236free_scriptnames()
3237{
3238 int i;
3239
3240 for (i = script_items.ga_len; i > 0; --i)
3241 vim_free(SCRIPT_ITEM(i).sn_name);
3242 ga_clear(&script_items);
3243}
3244# endif
3245
Bram Moolenaar071d4272004-06-13 20:20:40 +00003246#endif
3247
3248#if defined(USE_CR) || defined(PROTO)
3249
3250# if defined(__MSL__) && (__MSL__ >= 22)
3251/*
3252 * Newer version of the Metrowerks library handle DOS and UNIX files
3253 * without help.
3254 * Test with earlier versions, MSL 2.2 is the library supplied with
3255 * Codewarrior Pro 2.
3256 */
3257 char *
3258fgets_cr(s, n, stream)
3259 char *s;
3260 int n;
3261 FILE *stream;
3262{
3263 return fgets(s, n, stream);
3264}
3265# else
3266/*
3267 * Version of fgets() which also works for lines ending in a <CR> only
3268 * (Macintosh format).
3269 * For older versions of the Metrowerks library.
3270 * At least CodeWarrior 9 needed this code.
3271 */
3272 char *
3273fgets_cr(s, n, stream)
3274 char *s;
3275 int n;
3276 FILE *stream;
3277{
3278 int c = 0;
3279 int char_read = 0;
3280
3281 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3282 {
3283 c = fgetc(stream);
3284 s[char_read++] = c;
3285 /* If the file is in DOS format, we need to skip a NL after a CR. I
3286 * thought it was the other way around, but this appears to work... */
3287 if (c == '\n')
3288 {
3289 c = fgetc(stream);
3290 if (c != '\r')
3291 ungetc(c, stream);
3292 }
3293 }
3294
3295 s[char_read] = 0;
3296 if (char_read == 0)
3297 return NULL;
3298
3299 if (feof(stream) && char_read == 1)
3300 return NULL;
3301
3302 return s;
3303}
3304# endif
3305#endif
3306
3307/*
3308 * Get one full line from a sourced file.
3309 * Called by do_cmdline() when it's called from do_source().
3310 *
3311 * Return a pointer to the line in allocated memory.
3312 * Return NULL for end-of-file or some error.
3313 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314 char_u *
3315getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003316 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003318 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319{
3320 struct source_cookie *sp = (struct source_cookie *)cookie;
3321 char_u *line;
3322 char_u *p, *s;
3323
3324#ifdef FEAT_EVAL
3325 /* If breakpoints have been added/deleted need to check for it. */
3326 if (sp->dbg_tick < debug_tick)
3327 {
3328 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3329 sp->dbg_tick = debug_tick;
3330 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003331# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003332 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003333 script_line_end();
3334# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335#endif
3336 /*
3337 * Get current line. If there is a read-ahead line, use it, otherwise get
3338 * one now.
3339 */
3340 if (sp->finished)
3341 line = NULL;
3342 else if (sp->nextline == NULL)
3343 line = get_one_sourceline(sp);
3344 else
3345 {
3346 line = sp->nextline;
3347 sp->nextline = NULL;
3348 ++sourcing_lnum;
3349 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003350#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003351 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003352 script_line_start();
3353#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354
3355 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3356 * contain the 'C' flag. */
3357 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3358 {
3359 /* compensate for the one line read-ahead */
3360 --sourcing_lnum;
3361 for (;;)
3362 {
3363 sp->nextline = get_one_sourceline(sp);
3364 if (sp->nextline == NULL)
3365 break;
3366 p = skipwhite(sp->nextline);
3367 if (*p != '\\')
3368 break;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00003369 s = alloc((unsigned)(STRLEN(line) + STRLEN(p)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 if (s == NULL) /* out of memory */
3371 break;
3372 STRCPY(s, line);
3373 STRCAT(s, p + 1);
3374 vim_free(line);
3375 line = s;
3376 vim_free(sp->nextline);
3377 }
3378 }
3379
3380#ifdef FEAT_MBYTE
3381 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3382 {
3383 /* Convert the encoding of the script line. */
3384 s = string_convert(&sp->conv, line, NULL);
3385 if (s != NULL)
3386 {
3387 vim_free(line);
3388 line = s;
3389 }
3390 }
3391#endif
3392
3393#ifdef FEAT_EVAL
3394 /* Did we encounter a breakpoint? */
3395 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3396 {
3397 dbg_breakpoint(sp->fname, sourcing_lnum);
3398 /* Find next breakpoint. */
3399 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3400 sp->dbg_tick = debug_tick;
3401 }
3402#endif
3403
3404 return line;
3405}
3406
3407 static char_u *
3408get_one_sourceline(sp)
3409 struct source_cookie *sp;
3410{
3411 garray_T ga;
3412 int len;
3413 int c;
3414 char_u *buf;
3415#ifdef USE_CRNL
3416 int has_cr; /* CR-LF found */
3417#endif
3418#ifdef USE_CR
3419 char_u *scan;
3420#endif
3421 int have_read = FALSE;
3422
3423 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003424 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425
3426 /*
3427 * Loop until there is a finished line (or end-of-file).
3428 */
3429 sourcing_lnum++;
3430 for (;;)
3431 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003432 /* make room to read at least 120 (more) characters */
3433 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003434 break;
3435 buf = (char_u *)ga.ga_data;
3436
3437#ifdef USE_CR
3438 if (sp->fileformat == EOL_MAC)
3439 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003440 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3441 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003442 break;
3443 }
3444 else
3445#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003446 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3447 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003449 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003450#ifdef USE_CRNL
3451 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3452 * CTRL-Z by its own, or after a NL. */
3453 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3454 && sp->fileformat == EOL_DOS
3455 && buf[len - 1] == Ctrl_Z)
3456 {
3457 buf[len - 1] = NUL;
3458 break;
3459 }
3460#endif
3461
3462#ifdef USE_CR
3463 /* If the read doesn't stop on a new line, and there's
3464 * some CR then we assume a Mac format */
3465 if (sp->fileformat == EOL_UNKNOWN)
3466 {
3467 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3468 sp->fileformat = EOL_MAC;
3469 else
3470 sp->fileformat = EOL_UNIX;
3471 }
3472
3473 if (sp->fileformat == EOL_MAC)
3474 {
3475 scan = vim_strchr(buf, '\r');
3476
3477 if (scan != NULL)
3478 {
3479 *scan = '\n';
3480 if (*(scan + 1) != 0)
3481 {
3482 *(scan + 1) = 0;
3483 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3484 }
3485 }
3486 len = STRLEN(buf);
3487 }
3488#endif
3489
3490 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491 ga.ga_len = len;
3492
3493 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003494 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003495 continue;
3496
3497 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3498 {
3499#ifdef USE_CRNL
3500 has_cr = (len >= 2 && buf[len - 2] == '\r');
3501 if (sp->fileformat == EOL_UNKNOWN)
3502 {
3503 if (has_cr)
3504 sp->fileformat = EOL_DOS;
3505 else
3506 sp->fileformat = EOL_UNIX;
3507 }
3508
3509 if (sp->fileformat == EOL_DOS)
3510 {
3511 if (has_cr) /* replace trailing CR */
3512 {
3513 buf[len - 2] = '\n';
3514 --len;
3515 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003516 }
3517 else /* lines like ":map xx yy^M" will have failed */
3518 {
3519 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003520 {
3521 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003522 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003523 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003524 sp->error = TRUE;
3525 sp->fileformat = EOL_UNIX;
3526 }
3527 }
3528#endif
3529 /* The '\n' is escaped if there is an odd number of ^V's just
3530 * before it, first set "c" just before the 'V's and then check
3531 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3532 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3533 ;
3534 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3535 {
3536 sourcing_lnum++;
3537 continue;
3538 }
3539
3540 buf[len - 1] = NUL; /* remove the NL */
3541 }
3542
3543 /*
3544 * Check for ^C here now and then, so recursive :so can be broken.
3545 */
3546 line_breakcheck();
3547 break;
3548 }
3549
3550 if (have_read)
3551 return (char_u *)ga.ga_data;
3552
3553 vim_free(ga.ga_data);
3554 return NULL;
3555}
3556
Bram Moolenaar05159a02005-02-26 23:04:13 +00003557#if defined(FEAT_PROFILE) || defined(PROTO)
3558/*
3559 * Called when starting to read a script line.
3560 * "sourcing_lnum" must be correct!
3561 * When skipping lines it may not actually be executed, but we won't find out
3562 * until later and we need to store the time now.
3563 */
3564 void
3565script_line_start()
3566{
3567 scriptitem_T *si;
3568 sn_prl_T *pp;
3569
3570 if (current_SID <= 0 || current_SID > script_items.ga_len)
3571 return;
3572 si = &SCRIPT_ITEM(current_SID);
3573 if (si->sn_prof_on && sourcing_lnum >= 1)
3574 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003575 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003576 * here isn't counted. */
3577 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3578 si->sn_prl_idx = sourcing_lnum - 1;
3579 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3580 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3581 {
3582 /* Zero counters for a line that was not used before. */
3583 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3584 pp->snp_count = 0;
3585 profile_zero(&pp->sn_prl_total);
3586 profile_zero(&pp->sn_prl_self);
3587 ++si->sn_prl_ga.ga_len;
3588 }
3589 si->sn_prl_execed = FALSE;
3590 profile_start(&si->sn_prl_start);
3591 profile_zero(&si->sn_prl_children);
3592 profile_get_wait(&si->sn_prl_wait);
3593 }
3594}
3595
3596/*
3597 * Called when actually executing a function line.
3598 */
3599 void
3600script_line_exec()
3601{
3602 scriptitem_T *si;
3603
3604 if (current_SID <= 0 || current_SID > script_items.ga_len)
3605 return;
3606 si = &SCRIPT_ITEM(current_SID);
3607 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3608 si->sn_prl_execed = TRUE;
3609}
3610
3611/*
3612 * Called when done with a function line.
3613 */
3614 void
3615script_line_end()
3616{
3617 scriptitem_T *si;
3618 sn_prl_T *pp;
3619
3620 if (current_SID <= 0 || current_SID > script_items.ga_len)
3621 return;
3622 si = &SCRIPT_ITEM(current_SID);
3623 if (si->sn_prof_on && si->sn_prl_idx >= 0
3624 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3625 {
3626 if (si->sn_prl_execed)
3627 {
3628 pp = &PRL_ITEM(si, si->sn_prl_idx);
3629 ++pp->snp_count;
3630 profile_end(&si->sn_prl_start);
3631 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003632 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003633 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3634 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003635 }
3636 si->sn_prl_idx = -1;
3637 }
3638}
3639#endif
3640
Bram Moolenaar071d4272004-06-13 20:20:40 +00003641/*
3642 * ":scriptencoding": Set encoding conversion for a sourced script.
3643 * Without the multi-byte feature it's simply ignored.
3644 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003645 void
3646ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003647 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003648{
3649#ifdef FEAT_MBYTE
3650 struct source_cookie *sp;
3651 char_u *name;
3652
3653 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3654 {
3655 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3656 return;
3657 }
3658
3659 if (*eap->arg != NUL)
3660 {
3661 name = enc_canonize(eap->arg);
3662 if (name == NULL) /* out of memory */
3663 return;
3664 }
3665 else
3666 name = eap->arg;
3667
3668 /* Setup for conversion from the specified encoding to 'encoding'. */
3669 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3670 convert_setup(&sp->conv, name, p_enc);
3671
3672 if (name != eap->arg)
3673 vim_free(name);
3674#endif
3675}
3676
3677#if defined(FEAT_EVAL) || defined(PROTO)
3678/*
3679 * ":finish": Mark a sourced file as finished.
3680 */
3681 void
3682ex_finish(eap)
3683 exarg_T *eap;
3684{
3685 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3686 do_finish(eap, FALSE);
3687 else
3688 EMSG(_("E168: :finish used outside of a sourced file"));
3689}
3690
3691/*
3692 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3693 * Also called for a pending finish at the ":endtry" or after returning from
3694 * an extra do_cmdline(). "reanimate" is used in the latter case.
3695 */
3696 void
3697do_finish(eap, reanimate)
3698 exarg_T *eap;
3699 int reanimate;
3700{
3701 int idx;
3702
3703 if (reanimate)
3704 ((struct source_cookie *)getline_cookie(eap->getline,
3705 eap->cookie))->finished = FALSE;
3706
3707 /*
3708 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3709 * not in its finally clause (which then is to be executed next) is found.
3710 * In this case, make the ":finish" pending for execution at the ":endtry".
3711 * Otherwise, finish normally.
3712 */
3713 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3714 if (idx >= 0)
3715 {
3716 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3717 report_make_pending(CSTP_FINISH, NULL);
3718 }
3719 else
3720 ((struct source_cookie *)getline_cookie(eap->getline,
3721 eap->cookie))->finished = TRUE;
3722}
3723
3724
3725/*
3726 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3727 * message for missing ":endif".
3728 * Return FALSE when not sourcing a file.
3729 */
3730 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003731source_finished(fgetline, cookie)
3732 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733 void *cookie;
3734{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003735 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003737 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003738}
3739#endif
3740
3741#if defined(FEAT_LISTCMDS) || defined(PROTO)
3742/*
3743 * ":checktime [buffer]"
3744 */
3745 void
3746ex_checktime(eap)
3747 exarg_T *eap;
3748{
3749 buf_T *buf;
3750 int save_no_check_timestamps = no_check_timestamps;
3751
3752 no_check_timestamps = 0;
3753 if (eap->addr_count == 0) /* default is all buffers */
3754 check_timestamps(FALSE);
3755 else
3756 {
3757 buf = buflist_findnr((int)eap->line2);
3758 if (buf != NULL) /* cannot happen? */
3759 (void)buf_check_timestamp(buf, FALSE);
3760 }
3761 no_check_timestamps = save_no_check_timestamps;
3762}
3763#endif
3764
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3766 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3767static char *get_locale_val __ARGS((int what));
3768
3769 static char *
3770get_locale_val(what)
3771 int what;
3772{
3773 char *loc;
3774
3775 /* Obtain the locale value from the libraries. For DJGPP this is
3776 * redefined and it doesn't use the arguments. */
3777 loc = setlocale(what, NULL);
3778
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003779# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003780 if (loc != NULL)
3781 {
3782 char_u *p;
3783
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003784 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3785 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003786 p = vim_strchr(loc, '=');
3787 if (p != NULL)
3788 {
3789 loc = ++p;
3790 while (*p != NUL) /* remove trailing newline */
3791 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003792 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003793 {
3794 *p = NUL;
3795 break;
3796 }
3797 ++p;
3798 }
3799 }
3800 }
3801# endif
3802
3803 return loc;
3804}
3805#endif
3806
3807
3808#ifdef WIN32
3809/*
3810 * On MS-Windows locale names are strings like "German_Germany.1252", but
3811 * gettext expects "de". Try to translate one into another here for a few
3812 * supported languages.
3813 */
3814 static char_u *
3815gettext_lang(char_u *name)
3816{
3817 int i;
3818 static char *(mtable[]) = {
3819 "afrikaans", "af",
3820 "czech", "cs",
3821 "dutch", "nl",
3822 "german", "de",
3823 "english_united kingdom", "en_GB",
3824 "spanish", "es",
3825 "french", "fr",
3826 "italian", "it",
3827 "japanese", "ja",
3828 "korean", "ko",
3829 "norwegian", "no",
3830 "polish", "pl",
3831 "russian", "ru",
3832 "slovak", "sk",
3833 "swedish", "sv",
3834 "ukrainian", "uk",
3835 "chinese_china", "zh_CN",
3836 "chinese_taiwan", "zh_TW",
3837 NULL};
3838
3839 for (i = 0; mtable[i] != NULL; i += 2)
3840 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3841 return mtable[i + 1];
3842 return name;
3843}
3844#endif
3845
3846#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3847/*
3848 * Obtain the current messages language. Used to set the default for
3849 * 'helplang'. May return NULL or an empty string.
3850 */
3851 char_u *
3852get_mess_lang()
3853{
3854 char_u *p;
3855
3856# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3857# if defined(LC_MESSAGES)
3858 p = (char_u *)get_locale_val(LC_MESSAGES);
3859# else
3860 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003861 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3862 * and LC_MONETARY may be set differently for a Japanese working in the
3863 * US. */
3864 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003865# endif
3866# else
3867 p = mch_getenv((char_u *)"LC_ALL");
3868 if (p == NULL || *p == NUL)
3869 {
3870 p = mch_getenv((char_u *)"LC_MESSAGES");
3871 if (p == NULL || *p == NUL)
3872 p = mch_getenv((char_u *)"LANG");
3873 }
3874# endif
3875# ifdef WIN32
3876 p = gettext_lang(p);
3877# endif
3878 return p;
3879}
3880#endif
3881
Bram Moolenaardef9e822004-12-31 20:58:58 +00003882/* Complicated #if; matches with where get_mess_env() is used below. */
3883#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3884 && defined(LC_MESSAGES))) \
3885 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3886 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3887 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888static char_u *get_mess_env __ARGS((void));
3889
3890/*
3891 * Get the language used for messages from the environment.
3892 */
3893 static char_u *
3894get_mess_env()
3895{
3896 char_u *p;
3897
3898 p = mch_getenv((char_u *)"LC_ALL");
3899 if (p == NULL || *p == NUL)
3900 {
3901 p = mch_getenv((char_u *)"LC_MESSAGES");
3902 if (p == NULL || *p == NUL)
3903 {
3904 p = mch_getenv((char_u *)"LANG");
3905 if (p != NULL && VIM_ISDIGIT(*p))
3906 p = NULL; /* ignore something like "1043" */
3907# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3908 if (p == NULL || *p == NUL)
3909 p = (char_u *)get_locale_val(LC_CTYPE);
3910# endif
3911 }
3912 }
3913 return p;
3914}
3915#endif
3916
3917#if defined(FEAT_EVAL) || defined(PROTO)
3918
3919/*
3920 * Set the "v:lang" variable according to the current locale setting.
3921 * Also do "v:lc_time"and "v:ctype".
3922 */
3923 void
3924set_lang_var()
3925{
3926 char_u *loc;
3927
3928# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3929 loc = (char_u *)get_locale_val(LC_CTYPE);
3930# else
3931 /* setlocale() not supported: use the default value */
3932 loc = (char_u *)"C";
3933# endif
3934 set_vim_var_string(VV_CTYPE, loc, -1);
3935
3936 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3937 * back to LC_CTYPE if it's empty. */
3938# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
3939 loc = (char_u *)get_locale_val(LC_MESSAGES);
3940# else
3941 loc = get_mess_env();
3942# endif
3943 set_vim_var_string(VV_LANG, loc, -1);
3944
3945# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3946 loc = (char_u *)get_locale_val(LC_TIME);
3947# endif
3948 set_vim_var_string(VV_LC_TIME, loc, -1);
3949}
3950#endif
3951
3952#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3953 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
3954/*
3955 * ":language": Set the language (locale).
3956 */
3957 void
3958ex_language(eap)
3959 exarg_T *eap;
3960{
3961 char *loc;
3962 char_u *p;
3963 char_u *name;
3964 int what = LC_ALL;
3965 char *whatstr = "";
3966#ifdef LC_MESSAGES
3967# define VIM_LC_MESSAGES LC_MESSAGES
3968#else
3969# define VIM_LC_MESSAGES 6789
3970#endif
3971
3972 name = eap->arg;
3973
3974 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3975 * Allow abbreviation, but require at least 3 characters to avoid
3976 * confusion with a two letter language name "me" or "ct". */
3977 p = skiptowhite(eap->arg);
3978 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
3979 {
3980 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3981 {
3982 what = VIM_LC_MESSAGES;
3983 name = skipwhite(p);
3984 whatstr = "messages ";
3985 }
3986 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3987 {
3988 what = LC_CTYPE;
3989 name = skipwhite(p);
3990 whatstr = "ctype ";
3991 }
3992 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
3993 {
3994 what = LC_TIME;
3995 name = skipwhite(p);
3996 whatstr = "time ";
3997 }
3998 }
3999
4000 if (*name == NUL)
4001 {
4002#ifndef LC_MESSAGES
4003 if (what == VIM_LC_MESSAGES)
4004 p = get_mess_env();
4005 else
4006#endif
4007 p = (char_u *)setlocale(what, NULL);
4008 if (p == NULL || *p == NUL)
4009 p = (char_u *)"Unknown";
4010 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4011 }
4012 else
4013 {
4014#ifndef LC_MESSAGES
4015 if (what == VIM_LC_MESSAGES)
4016 loc = "";
4017 else
4018#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004019 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004020 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004021#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4022 /* Make sure strtod() uses a decimal point, not a comma. */
4023 setlocale(LC_NUMERIC, "C");
4024#endif
4025 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004026 if (loc == NULL)
4027 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4028 else
4029 {
4030#ifdef HAVE_NL_MSG_CAT_CNTR
4031 /* Need to do this for GNU gettext, otherwise cached translations
4032 * will be used again. */
4033 extern int _nl_msg_cat_cntr;
4034
4035 ++_nl_msg_cat_cntr;
4036#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004037 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004038 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4039
4040 if (what != LC_TIME)
4041 {
4042 /* Tell gettext() what to translate to. It apparently doesn't
4043 * use the currently effective locale. Also do this when
4044 * FEAT_GETTEXT isn't defined, so that shell commands use this
4045 * value. */
4046 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004047 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004048 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004049# ifdef WIN32
4050 /* Apparently MS-Windows printf() may cause a crash when
4051 * we give it 8-bit text while it's expecting text in the
4052 * current locale. This call avoids that. */
4053 setlocale(LC_CTYPE, "C");
4054# endif
4055 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004056 if (what != LC_CTYPE)
4057 {
4058 char_u *mname;
4059#ifdef WIN32
4060 mname = gettext_lang(name);
4061#else
4062 mname = name;
4063#endif
4064 vim_setenv((char_u *)"LC_MESSAGES", mname);
4065#ifdef FEAT_MULTI_LANG
4066 set_helplang_default(mname);
4067#endif
4068 }
4069
4070 /* Set $LC_CTYPE, because it overrules $LANG, and
4071 * gtk_set_locale() calls setlocale() again. gnome_init()
4072 * sets $LC_CTYPE to "en_US" (that's a bug!). */
4073 if (what != VIM_LC_MESSAGES)
4074 vim_setenv((char_u *)"LC_CTYPE", name);
4075# ifdef FEAT_GUI_GTK
4076 /* Let GTK know what locale we're using. Not sure this is
4077 * really needed... */
4078 if (gui.in_use)
4079 (void)gtk_set_locale();
4080# endif
4081 }
4082
4083# ifdef FEAT_EVAL
4084 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4085 set_lang_var();
4086# endif
4087 }
4088 }
4089}
4090
4091# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4092/*
4093 * Function given to ExpandGeneric() to obtain the possible arguments of the
4094 * ":language" command.
4095 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096 char_u *
4097get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004098 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004099 int idx;
4100{
4101 if (idx == 0)
4102 return (char_u *)"messages";
4103 if (idx == 1)
4104 return (char_u *)"ctype";
4105 if (idx == 2)
4106 return (char_u *)"time";
4107 return NULL;
4108}
4109# endif
4110
4111#endif