blob: 2eeb7527d3566524573e77e994af65d16acce3a1 [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
14#if defined(WIN32) && defined(FEAT_CSCOPE)
Bram Moolenaar362e1a32006-03-06 23:29:24 +000015# include "vimio.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000016#endif
17
18#include "vim.h"
19
20#if defined(WIN32) && defined(FEAT_CSCOPE)
21# include <fcntl.h>
22#endif
23
24#include "version.h"
25
26static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
27
Bram Moolenaar05159a02005-02-26 23:04:13 +000028#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000029/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000030 * For Unix also store the dev/ino, so that we don't have to stat() each
31 * script when going through the list. */
32typedef struct scriptitem_S
33{
34 char_u *sn_name;
35# ifdef UNIX
36 int sn_dev;
37 ino_t sn_ino;
38# endif
39# ifdef FEAT_PROFILE
40 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000041 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000042 proftime_T sn_pr_child; /* time set when going into first child */
43 int sn_pr_nest; /* nesting for sn_pr_child */
44 /* profiling the script as a whole */
45 int sn_pr_count; /* nr of times sourced */
46 proftime_T sn_pr_total; /* time spend in script + children */
47 proftime_T sn_pr_self; /* time spend in script itself */
48 proftime_T sn_pr_start; /* time at script start */
49 proftime_T sn_pr_children; /* time in children after script start */
50 /* profiling the script per line */
51 garray_T sn_prl_ga; /* things stored for every line */
52 proftime_T sn_prl_start; /* start time for current line */
53 proftime_T sn_prl_children; /* time spent in children for this line */
54 proftime_T sn_prl_wait; /* wait start time for current line */
55 int sn_prl_idx; /* index of line being timed; -1 if none */
56 int sn_prl_execed; /* line being timed was executed */
57# endif
58} scriptitem_T;
59
60static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
61#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
62
63# ifdef FEAT_PROFILE
64/* Struct used in sn_prl_ga for every line of a script. */
65typedef struct sn_prl_S
66{
67 int snp_count; /* nr of times line was executed */
68 proftime_T sn_prl_total; /* time spend in a line + children */
69 proftime_T sn_prl_self; /* time spend in a line itself */
70} sn_prl_T;
71
72# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
73# endif
74#endif
75
Bram Moolenaar071d4272004-06-13 20:20:40 +000076#if defined(FEAT_EVAL) || defined(PROTO)
77static int debug_greedy = FALSE; /* batch mode debugging: don't save
78 and restore typeahead. */
79
80/*
81 * do_debug(): Debug mode.
82 * Repeatedly get Ex commands, until told to continue normal execution.
83 */
84 void
85do_debug(cmd)
86 char_u *cmd;
87{
88 int save_msg_scroll = msg_scroll;
89 int save_State = State;
90 int save_did_emsg = did_emsg;
91 int save_cmd_silent = cmd_silent;
92 int save_msg_silent = msg_silent;
93 int save_emsg_silent = emsg_silent;
94 int save_redir_off = redir_off;
95 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000096 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000097 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000098# ifdef FEAT_EX_EXTRA
99 int save_ex_normal_busy;
100# endif
101 int n;
102 char_u *cmdline = NULL;
103 char_u *p;
104 char *tail = NULL;
105 static int last_cmd = 0;
106#define CMD_CONT 1
107#define CMD_NEXT 2
108#define CMD_STEP 3
109#define CMD_FINISH 4
110#define CMD_QUIT 5
111#define CMD_INTERRUPT 6
112
113#ifdef ALWAYS_USE_GUI
114 /* Can't do this when there is no terminal for input/output. */
115 if (!gui.in_use)
116 {
117 /* Break as soon as possible. */
118 debug_break_level = 9999;
119 return;
120 }
121#endif
122
123 /* Make sure we are in raw mode and start termcap mode. Might have side
124 * effects... */
125 settmode(TMODE_RAW);
126 starttermcap();
127
128 ++RedrawingDisabled; /* don't redisplay the window */
129 ++no_wait_return; /* don't wait for return */
130 did_emsg = FALSE; /* don't use error from debugged stuff */
131 cmd_silent = FALSE; /* display commands */
132 msg_silent = FALSE; /* display messages */
133 emsg_silent = FALSE; /* display error messages */
134 redir_off = TRUE; /* don't redirect debug commands */
135
136 State = NORMAL;
137#ifdef FEAT_SNIFF
138 want_sniff_request = 0; /* No K_SNIFF wanted */
139#endif
140
141 if (!debug_did_msg)
142 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
143 if (sourcing_name != NULL)
144 msg(sourcing_name);
145 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000146 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000148 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149
150 /*
151 * Repeat getting a command and executing it.
152 */
153 for (;;)
154 {
155 msg_scroll = TRUE;
156 need_wait_return = FALSE;
157#ifdef FEAT_SNIFF
158 ProcessSniffRequests();
159#endif
160 /* Save the current typeahead buffer and replace it with an empty one.
161 * This makes sure we get input from the user here and don't interfere
162 * with the commands being executed. Reset "ex_normal_busy" to avoid
163 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000164 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165# ifdef FEAT_EX_EXTRA
166 save_ex_normal_busy = ex_normal_busy;
167 ex_normal_busy = 0;
168# endif
169 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000170 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000172 typeahead_saved = TRUE;
173 save_ignore_script = ignore_script;
174 ignore_script = TRUE;
175 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000177 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000178
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000179 if (typeahead_saved)
180 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000182 ignore_script = save_ignore_script;
183 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184# ifdef FEAT_EX_EXTRA
185 ex_normal_busy = save_ex_normal_busy;
186# endif
187
188 cmdline_row = msg_row;
189 if (cmdline != NULL)
190 {
191 /* If this is a debug command, set "last_cmd".
192 * If not, reset "last_cmd".
193 * For a blank line use previous command. */
194 p = skipwhite(cmdline);
195 if (*p != NUL)
196 {
197 switch (*p)
198 {
199 case 'c': last_cmd = CMD_CONT;
200 tail = "ont";
201 break;
202 case 'n': last_cmd = CMD_NEXT;
203 tail = "ext";
204 break;
205 case 's': last_cmd = CMD_STEP;
206 tail = "tep";
207 break;
208 case 'f': last_cmd = CMD_FINISH;
209 tail = "inish";
210 break;
211 case 'q': last_cmd = CMD_QUIT;
212 tail = "uit";
213 break;
214 case 'i': last_cmd = CMD_INTERRUPT;
215 tail = "nterrupt";
216 break;
217 default: last_cmd = 0;
218 }
219 if (last_cmd != 0)
220 {
221 /* Check that the tail matches. */
222 ++p;
223 while (*p != NUL && *p == *tail)
224 {
225 ++p;
226 ++tail;
227 }
228 if (ASCII_ISALPHA(*p))
229 last_cmd = 0;
230 }
231 }
232
233 if (last_cmd != 0)
234 {
235 /* Execute debug command: decided where to break next and
236 * return. */
237 switch (last_cmd)
238 {
239 case CMD_CONT:
240 debug_break_level = -1;
241 break;
242 case CMD_NEXT:
243 debug_break_level = ex_nesting_level;
244 break;
245 case CMD_STEP:
246 debug_break_level = 9999;
247 break;
248 case CMD_FINISH:
249 debug_break_level = ex_nesting_level - 1;
250 break;
251 case CMD_QUIT:
252 got_int = TRUE;
253 debug_break_level = -1;
254 break;
255 case CMD_INTERRUPT:
256 got_int = TRUE;
257 debug_break_level = 9999;
258 /* Do not repeat ">interrupt" cmd, continue stepping. */
259 last_cmd = CMD_STEP;
260 break;
261 }
262 break;
263 }
264
265 /* don't debug this command */
266 n = debug_break_level;
267 debug_break_level = -1;
268 (void)do_cmdline(cmdline, getexline, NULL,
269 DOCMD_VERBOSE|DOCMD_EXCRESET);
270 debug_break_level = n;
271
272 vim_free(cmdline);
273 }
274 lines_left = Rows - 1;
275 }
276 vim_free(cmdline);
277
278 --RedrawingDisabled;
279 --no_wait_return;
280 redraw_all_later(NOT_VALID);
281 need_wait_return = FALSE;
282 msg_scroll = save_msg_scroll;
283 lines_left = Rows - 1;
284 State = save_State;
285 did_emsg = save_did_emsg;
286 cmd_silent = save_cmd_silent;
287 msg_silent = save_msg_silent;
288 emsg_silent = save_emsg_silent;
289 redir_off = save_redir_off;
290
291 /* Only print the message again when typing a command before coming back
292 * here. */
293 debug_did_msg = TRUE;
294}
295
296/*
297 * ":debug".
298 */
299 void
300ex_debug(eap)
301 exarg_T *eap;
302{
303 int debug_break_level_save = debug_break_level;
304
305 debug_break_level = 9999;
306 do_cmdline_cmd(eap->arg);
307 debug_break_level = debug_break_level_save;
308}
309
310static char_u *debug_breakpoint_name = NULL;
311static linenr_T debug_breakpoint_lnum;
312
313/*
314 * When debugging or a breakpoint is set on a skipped command, no debug prompt
315 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
316 * debug_skipped_name is then set to the source name in the breakpoint case. If
317 * a skipped command decides itself that a debug prompt should be displayed, it
318 * can do so by calling dbg_check_skipped().
319 */
320static int debug_skipped;
321static char_u *debug_skipped_name;
322
323/*
324 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
325 * at or below the break level. But only when the line is actually
326 * executed. Return TRUE and set breakpoint_name for skipped commands that
327 * decide to execute something themselves.
328 * Called from do_one_cmd() before executing a command.
329 */
330 void
331dbg_check_breakpoint(eap)
332 exarg_T *eap;
333{
334 char_u *p;
335
336 debug_skipped = FALSE;
337 if (debug_breakpoint_name != NULL)
338 {
339 if (!eap->skip)
340 {
341 /* replace K_SNR with "<SNR>" */
342 if (debug_breakpoint_name[0] == K_SPECIAL
343 && debug_breakpoint_name[1] == KS_EXTRA
344 && debug_breakpoint_name[2] == (int)KE_SNR)
345 p = (char_u *)"<SNR>";
346 else
347 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000348 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
349 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 debug_breakpoint_name + (*p == NUL ? 0 : 3),
351 (long)debug_breakpoint_lnum);
352 debug_breakpoint_name = NULL;
353 do_debug(eap->cmd);
354 }
355 else
356 {
357 debug_skipped = TRUE;
358 debug_skipped_name = debug_breakpoint_name;
359 debug_breakpoint_name = NULL;
360 }
361 }
362 else if (ex_nesting_level <= debug_break_level)
363 {
364 if (!eap->skip)
365 do_debug(eap->cmd);
366 else
367 {
368 debug_skipped = TRUE;
369 debug_skipped_name = NULL;
370 }
371 }
372}
373
374/*
375 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
376 * set. Return TRUE when the debug mode is entered this time.
377 */
378 int
379dbg_check_skipped(eap)
380 exarg_T *eap;
381{
382 int prev_got_int;
383
384 if (debug_skipped)
385 {
386 /*
387 * Save the value of got_int and reset it. We don't want a previous
388 * interruption cause flushing the input buffer.
389 */
390 prev_got_int = got_int;
391 got_int = FALSE;
392 debug_breakpoint_name = debug_skipped_name;
393 /* eap->skip is TRUE */
394 eap->skip = FALSE;
395 (void)dbg_check_breakpoint(eap);
396 eap->skip = TRUE;
397 got_int |= prev_got_int;
398 return TRUE;
399 }
400 return FALSE;
401}
402
403/*
404 * The list of breakpoints: dbg_breakp.
405 * This is a grow-array of structs.
406 */
407struct debuggy
408{
409 int dbg_nr; /* breakpoint number */
410 int dbg_type; /* DBG_FUNC or DBG_FILE */
411 char_u *dbg_name; /* function or file name */
412 regprog_T *dbg_prog; /* regexp program */
413 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000414 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415};
416
417static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000418#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
419#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000420static int last_breakp = 0; /* nr of last defined breakpoint */
421
Bram Moolenaar05159a02005-02-26 23:04:13 +0000422#ifdef FEAT_PROFILE
423/* Profiling uses file and func names similar to breakpoints. */
424static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
425#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000426#define DBG_FUNC 1
427#define DBG_FILE 2
428
Bram Moolenaar05159a02005-02-26 23:04:13 +0000429static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
430static 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 +0000431
432/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000433 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
434 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
435 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000436 * Returns FAIL for failure.
437 */
438 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000439dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000440 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000441 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000442{
443 char_u *p = arg;
444 char_u *q;
445 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000446 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000447
Bram Moolenaar05159a02005-02-26 23:04:13 +0000448 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000449 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000450 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000451
452 /* Find "func" or "file". */
453 if (STRNCMP(p, "func", 4) == 0)
454 bp->dbg_type = DBG_FUNC;
455 else if (STRNCMP(p, "file", 4) == 0)
456 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000457 else if (
458#ifdef FEAT_PROFILE
459 gap != &prof_ga &&
460#endif
461 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000462 {
463 if (curbuf->b_ffname == NULL)
464 {
465 EMSG(_(e_noname));
466 return FAIL;
467 }
468 bp->dbg_type = DBG_FILE;
469 here = TRUE;
470 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000471 else
472 {
473 EMSG2(_(e_invarg2), p);
474 return FAIL;
475 }
476 p = skipwhite(p + 4);
477
478 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000479 if (here)
480 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000481 else if (
482#ifdef FEAT_PROFILE
483 gap != &prof_ga &&
484#endif
485 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000486 {
487 bp->dbg_lnum = getdigits(&p);
488 p = skipwhite(p);
489 }
490 else
491 bp->dbg_lnum = 0;
492
493 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000494 if ((!here && *p == NUL)
495 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
497 {
498 EMSG2(_(e_invarg2), arg);
499 return FAIL;
500 }
501
502 if (bp->dbg_type == DBG_FUNC)
503 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000504 else if (here)
505 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 else
507 {
508 /* Expand the file name in the same way as do_source(). This means
509 * doing it twice, so that $DIR/file gets expanded when $DIR is
510 * "~/dir". */
511#ifdef RISCOS
512 q = mch_munge_fname(p);
513#else
514 q = expand_env_save(p);
515#endif
516 if (q == NULL)
517 return FAIL;
518#ifdef RISCOS
519 p = mch_munge_fname(q);
520#else
521 p = expand_env_save(q);
522#endif
523 vim_free(q);
524 if (p == NULL)
525 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000526 if (*p != '*')
527 {
528 bp->dbg_name = fix_fname(p);
529 vim_free(p);
530 }
531 else
532 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000533 }
534
535 if (bp->dbg_name == NULL)
536 return FAIL;
537 return OK;
538}
539
540/*
541 * ":breakadd".
542 */
543 void
544ex_breakadd(eap)
545 exarg_T *eap;
546{
547 struct debuggy *bp;
548 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000549 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550
Bram Moolenaar05159a02005-02-26 23:04:13 +0000551 gap = &dbg_breakp;
552#ifdef FEAT_PROFILE
553 if (eap->cmdidx == CMD_profile)
554 gap = &prof_ga;
555#endif
556
557 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000559 bp = &DEBUGGY(gap, gap->ga_len);
560 bp->dbg_forceit = eap->forceit;
561
Bram Moolenaar071d4272004-06-13 20:20:40 +0000562 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
563 if (pat != NULL)
564 {
565 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
566 vim_free(pat);
567 }
568 if (pat == NULL || bp->dbg_prog == NULL)
569 vim_free(bp->dbg_name);
570 else
571 {
572 if (bp->dbg_lnum == 0) /* default line number is 1 */
573 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000574#ifdef FEAT_PROFILE
575 if (eap->cmdidx != CMD_profile)
576#endif
577 {
578 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
579 ++debug_tick;
580 }
581 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000582 }
583 }
584}
585
586/*
587 * ":debuggreedy".
588 */
589 void
590ex_debuggreedy(eap)
591 exarg_T *eap;
592{
593 if (eap->addr_count == 0 || eap->line2 != 0)
594 debug_greedy = TRUE;
595 else
596 debug_greedy = FALSE;
597}
598
599/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000600 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000601 */
602 void
603ex_breakdel(eap)
604 exarg_T *eap;
605{
606 struct debuggy *bp, *bpi;
607 int nr;
608 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000609 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610 int i;
611 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000612 garray_T *gap;
613
614 gap = &dbg_breakp;
615#ifdef FEAT_PROFILE
616 if (eap->cmdidx == CMD_profdel)
617 gap = &prof_ga;
618#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000619
620 if (vim_isdigit(*eap->arg))
621 {
622 /* ":breakdel {nr}" */
623 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000624 for (i = 0; i < gap->ga_len; ++i)
625 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626 {
627 todel = i;
628 break;
629 }
630 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000631 else if (*eap->arg == '*')
632 {
633 todel = 0;
634 del_all = TRUE;
635 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000636 else
637 {
638 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000639 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000641 bp = &DEBUGGY(gap, gap->ga_len);
642 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000644 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645 if (bp->dbg_type == bpi->dbg_type
646 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
647 && (bp->dbg_lnum == bpi->dbg_lnum
648 || (bp->dbg_lnum == 0
649 && (best_lnum == 0
650 || bpi->dbg_lnum < best_lnum))))
651 {
652 todel = i;
653 best_lnum = bpi->dbg_lnum;
654 }
655 }
656 vim_free(bp->dbg_name);
657 }
658
659 if (todel < 0)
660 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
661 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000662 {
663 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000664 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000665 vim_free(DEBUGGY(gap, todel).dbg_name);
666 vim_free(DEBUGGY(gap, todel).dbg_prog);
667 --gap->ga_len;
668 if (todel < gap->ga_len)
669 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
670 (gap->ga_len - todel) * sizeof(struct debuggy));
671#ifdef FEAT_PROFILE
672 if (eap->cmdidx == CMD_breakdel)
673#endif
674 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000675 if (!del_all)
676 break;
677 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000678
679 /* If all breakpoints were removed clear the array. */
680 if (gap->ga_len == 0)
681 ga_clear(gap);
682 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683}
684
685/*
686 * ":breaklist".
687 */
688/*ARGSUSED*/
689 void
690ex_breaklist(eap)
691 exarg_T *eap;
692{
693 struct debuggy *bp;
694 int i;
695
696 if (dbg_breakp.ga_len == 0)
697 MSG(_("No breakpoints defined"));
698 else
699 for (i = 0; i < dbg_breakp.ga_len; ++i)
700 {
701 bp = &BREAKP(i);
702 smsg((char_u *)_("%3d %s %s line %ld"),
703 bp->dbg_nr,
704 bp->dbg_type == DBG_FUNC ? "func" : "file",
705 bp->dbg_name,
706 (long)bp->dbg_lnum);
707 }
708}
709
710/*
711 * Find a breakpoint for a function or sourced file.
712 * Returns line number at which to break; zero when no matching breakpoint.
713 */
714 linenr_T
715dbg_find_breakpoint(file, fname, after)
716 int file; /* TRUE for a file, FALSE for a function */
717 char_u *fname; /* file or function name */
718 linenr_T after; /* after this line number */
719{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000720 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
721}
722
723#if defined(FEAT_PROFILE) || defined(PROTO)
724/*
725 * Return TRUE if profiling is on for a function or sourced file.
726 */
727 int
728has_profiling(file, fname, fp)
729 int file; /* TRUE for a file, FALSE for a function */
730 char_u *fname; /* file or function name */
731 int *fp; /* return: forceit */
732{
733 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
734 != (linenr_T)0);
735}
736#endif
737
738/*
739 * Common code for dbg_find_breakpoint() and has_profiling().
740 */
741 static linenr_T
742debuggy_find(file, fname, after, gap, fp)
743 int file; /* TRUE for a file, FALSE for a function */
744 char_u *fname; /* file or function name */
745 linenr_T after; /* after this line number */
746 garray_T *gap; /* either &dbg_breakp or &prof_ga */
747 int *fp; /* if not NULL: return forceit */
748{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 struct debuggy *bp;
750 int i;
751 linenr_T lnum = 0;
752 regmatch_T regmatch;
753 char_u *name = fname;
754 int prev_got_int;
755
Bram Moolenaar05159a02005-02-26 23:04:13 +0000756 /* Return quickly when there are no breakpoints. */
757 if (gap->ga_len == 0)
758 return (linenr_T)0;
759
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760 /* Replace K_SNR in function name with "<SNR>". */
761 if (!file && fname[0] == K_SPECIAL)
762 {
763 name = alloc((unsigned)STRLEN(fname) + 3);
764 if (name == NULL)
765 name = fname;
766 else
767 {
768 STRCPY(name, "<SNR>");
769 STRCPY(name + 5, fname + 3);
770 }
771 }
772
Bram Moolenaar05159a02005-02-26 23:04:13 +0000773 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000775 /* Skip entries that are not useful or are for a line that is beyond
776 * an already found breakpoint. */
777 bp = &DEBUGGY(gap, i);
778 if (((bp->dbg_type == DBG_FILE) == file && (
779#ifdef FEAT_PROFILE
780 gap == &prof_ga ||
781#endif
782 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783 {
784 regmatch.regprog = bp->dbg_prog;
785 regmatch.rm_ic = FALSE;
786 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000787 * Save the value of got_int and reset it. We don't want a
788 * previous interruption cancel matching, only hitting CTRL-C
789 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 */
791 prev_got_int = got_int;
792 got_int = FALSE;
793 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000794 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000796 if (fp != NULL)
797 *fp = bp->dbg_forceit;
798 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000799 got_int |= prev_got_int;
800 }
801 }
802 if (name != fname)
803 vim_free(name);
804
805 return lnum;
806}
807
808/*
809 * Called when a breakpoint was encountered.
810 */
811 void
812dbg_breakpoint(name, lnum)
813 char_u *name;
814 linenr_T lnum;
815{
816 /* We need to check if this line is actually executed in do_one_cmd() */
817 debug_breakpoint_name = name;
818 debug_breakpoint_lnum = lnum;
819}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000820
821
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000822# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000823/*
824 * Store the current time in "tm".
825 */
826 void
827profile_start(tm)
828 proftime_T *tm;
829{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000830# ifdef WIN3264
831 QueryPerformanceCounter(tm);
832# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000833 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000834# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000835}
836
837/*
838 * Compute the elapsed time from "tm" till now and store in "tm".
839 */
840 void
841profile_end(tm)
842 proftime_T *tm;
843{
844 proftime_T now;
845
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000846# ifdef WIN3264
847 QueryPerformanceCounter(&now);
848 tm->QuadPart = now.QuadPart - tm->QuadPart;
849# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000850 gettimeofday(&now, NULL);
851 tm->tv_usec = now.tv_usec - tm->tv_usec;
852 tm->tv_sec = now.tv_sec - tm->tv_sec;
853 if (tm->tv_usec < 0)
854 {
855 tm->tv_usec += 1000000;
856 --tm->tv_sec;
857 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000858# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000859}
860
861/*
862 * Subtract the time "tm2" from "tm".
863 */
864 void
865profile_sub(tm, tm2)
866 proftime_T *tm, *tm2;
867{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000868# ifdef WIN3264
869 tm->QuadPart -= tm2->QuadPart;
870# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000871 tm->tv_usec -= tm2->tv_usec;
872 tm->tv_sec -= tm2->tv_sec;
873 if (tm->tv_usec < 0)
874 {
875 tm->tv_usec += 1000000;
876 --tm->tv_sec;
877 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000878# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000879}
880
881/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000882 * Return a string that represents the time in "tm".
883 * Uses a static buffer!
884 */
885 char *
886profile_msg(tm)
887 proftime_T *tm;
888{
889 static char buf[50];
890
891# ifdef WIN3264
892 LARGE_INTEGER fr;
893
894 QueryPerformanceFrequency(&fr);
895 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
896# else
897 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000898# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000899 return buf;
900}
901
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000902/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000903 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000904 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000905 void
906profile_setlimit(msec, tm)
907 long msec;
908 proftime_T *tm;
909{
910 if (msec <= 0) /* no limit */
911 profile_zero(tm);
912 else
913 {
914# ifdef WIN3264
915 LARGE_INTEGER fr;
916
917 QueryPerformanceCounter(tm);
918 QueryPerformanceFrequency(&fr);
919 tm->QuadPart += (double)msec / 1000.0 * (double)fr.QuadPart;
920# else
921 long usec;
922
923 gettimeofday(tm, NULL);
924 usec = (long)tm->tv_usec + (long)msec * 1000;
925 tm->tv_usec = usec % 1000000L;
926 tm->tv_sec += usec / 1000000L;
927# endif
928 }
929}
930
931/*
932 * Return TRUE if the current time is past "tm".
933 */
934 int
935profile_passed_limit(tm)
936 proftime_T *tm;
937{
938 proftime_T now;
939
940# ifdef WIN3264
941 if (tm->QuadPart == 0) /* timer was not set */
942 return FALSE;
943 QueryPerformanceCounter(&now);
944 return (now.QuadPart > tm->QuadPart);
945# else
946 if (tm->tv_sec == 0) /* timer was not set */
947 return FALSE;
948 gettimeofday(&now, NULL);
949 return (now.tv_sec > tm->tv_sec
950 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
951# endif
952}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000953
954/*
955 * Set the time in "tm" to zero.
956 */
957 void
958profile_zero(tm)
959 proftime_T *tm;
960{
961# ifdef WIN3264
962 tm->QuadPart = 0;
963# else
964 tm->tv_usec = 0;
965 tm->tv_sec = 0;
966# endif
967}
968
Bram Moolenaar76929292008-01-06 19:07:36 +0000969# endif /* FEAT_PROFILE || FEAT_RELTIME */
970
971# if defined(FEAT_PROFILE) || defined(PROTO)
972/*
973 * Functions for profiling.
974 */
975static void script_do_profile __ARGS((scriptitem_T *si));
976static void script_dump_profile __ARGS((FILE *fd));
977static proftime_T prof_wait_time;
978
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000979/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000980 * Add the time "tm2" to "tm".
981 */
982 void
983profile_add(tm, tm2)
984 proftime_T *tm, *tm2;
985{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000986# ifdef WIN3264
987 tm->QuadPart += tm2->QuadPart;
988# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000989 tm->tv_usec += tm2->tv_usec;
990 tm->tv_sec += tm2->tv_sec;
991 if (tm->tv_usec >= 1000000)
992 {
993 tm->tv_usec -= 1000000;
994 ++tm->tv_sec;
995 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000996# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000997}
998
999/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001000 * Add the "self" time from the total time and the children's time.
1001 */
1002 void
1003profile_self(self, total, children)
1004 proftime_T *self, *total, *children;
1005{
1006 /* Check that the result won't be negative. Can happen with recursive
1007 * calls. */
1008#ifdef WIN3264
1009 if (total->QuadPart <= children->QuadPart)
1010 return;
1011#else
1012 if (total->tv_sec < children->tv_sec
1013 || (total->tv_sec == children->tv_sec
1014 && total->tv_usec <= children->tv_usec))
1015 return;
1016#endif
1017 profile_add(self, total);
1018 profile_sub(self, children);
1019}
1020
1021/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001022 * Get the current waittime.
1023 */
1024 void
1025profile_get_wait(tm)
1026 proftime_T *tm;
1027{
1028 *tm = prof_wait_time;
1029}
1030
1031/*
1032 * Subtract the passed waittime since "tm" from "tma".
1033 */
1034 void
1035profile_sub_wait(tm, tma)
1036 proftime_T *tm, *tma;
1037{
1038 proftime_T tm3 = prof_wait_time;
1039
1040 profile_sub(&tm3, tm);
1041 profile_sub(tma, &tm3);
1042}
1043
1044/*
1045 * Return TRUE if "tm1" and "tm2" are equal.
1046 */
1047 int
1048profile_equal(tm1, tm2)
1049 proftime_T *tm1, *tm2;
1050{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001051# ifdef WIN3264
1052 return (tm1->QuadPart == tm2->QuadPart);
1053# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001054 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001055# endif
1056}
1057
1058/*
1059 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1060 */
1061 int
1062profile_cmp(tm1, tm2)
1063 proftime_T *tm1, *tm2;
1064{
1065# ifdef WIN3264
1066 return (int)(tm2->QuadPart - tm1->QuadPart);
1067# else
1068 if (tm1->tv_sec == tm2->tv_sec)
1069 return tm2->tv_usec - tm1->tv_usec;
1070 return tm2->tv_sec - tm1->tv_sec;
1071# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001072}
1073
Bram Moolenaar05159a02005-02-26 23:04:13 +00001074static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001075static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001076
1077/*
1078 * ":profile cmd args"
1079 */
1080 void
1081ex_profile(eap)
1082 exarg_T *eap;
1083{
1084 char_u *e;
1085 int len;
1086
1087 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001088 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001089 e = skipwhite(e);
1090
1091 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1092 {
1093 vim_free(profile_fname);
1094 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001095 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001096 profile_zero(&prof_wait_time);
1097 set_vim_var_nr(VV_PROFILING, 1L);
1098 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001099 else if (do_profiling == PROF_NONE)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001100 EMSG(_("E750: First use :profile start <fname>"));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001101 else if (STRCMP(eap->arg, "pause") == 0)
1102 {
1103 if (do_profiling == PROF_YES)
1104 profile_start(&pause_time);
1105 do_profiling = PROF_PAUSED;
1106 }
1107 else if (STRCMP(eap->arg, "continue") == 0)
1108 {
1109 if (do_profiling == PROF_PAUSED)
1110 {
1111 profile_end(&pause_time);
1112 profile_add(&prof_wait_time, &pause_time);
1113 }
1114 do_profiling = PROF_YES;
1115 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001116 else
1117 {
1118 /* The rest is similar to ":breakadd". */
1119 ex_breakadd(eap);
1120 }
1121}
1122
1123/*
1124 * Dump the profiling info.
1125 */
1126 void
1127profile_dump()
1128{
1129 FILE *fd;
1130
1131 if (profile_fname != NULL)
1132 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001133 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001134 if (fd == NULL)
1135 EMSG2(_(e_notopen), profile_fname);
1136 else
1137 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001138 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001139 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001140 fclose(fd);
1141 }
1142 }
1143}
1144
1145/*
1146 * Start profiling script "fp".
1147 */
1148 static void
1149script_do_profile(si)
1150 scriptitem_T *si;
1151{
1152 si->sn_pr_count = 0;
1153 profile_zero(&si->sn_pr_total);
1154 profile_zero(&si->sn_pr_self);
1155
1156 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1157 si->sn_prl_idx = -1;
1158 si->sn_prof_on = TRUE;
1159 si->sn_pr_nest = 0;
1160}
1161
1162/*
1163 * save time when starting to invoke another script or function.
1164 */
1165 void
1166script_prof_save(tm)
1167 proftime_T *tm; /* place to store wait time */
1168{
1169 scriptitem_T *si;
1170
1171 if (current_SID > 0 && current_SID <= script_items.ga_len)
1172 {
1173 si = &SCRIPT_ITEM(current_SID);
1174 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1175 profile_start(&si->sn_pr_child);
1176 }
1177 profile_get_wait(tm);
1178}
1179
1180/*
1181 * Count time spent in children after invoking another script or function.
1182 */
1183 void
1184script_prof_restore(tm)
1185 proftime_T *tm;
1186{
1187 scriptitem_T *si;
1188
1189 if (current_SID > 0 && current_SID <= script_items.ga_len)
1190 {
1191 si = &SCRIPT_ITEM(current_SID);
1192 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1193 {
1194 profile_end(&si->sn_pr_child);
1195 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1196 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1197 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1198 }
1199 }
1200}
1201
1202static proftime_T inchar_time;
1203
1204/*
1205 * Called when starting to wait for the user to type a character.
1206 */
1207 void
1208prof_inchar_enter()
1209{
1210 profile_start(&inchar_time);
1211}
1212
1213/*
1214 * Called when finished waiting for the user to type a character.
1215 */
1216 void
1217prof_inchar_exit()
1218{
1219 profile_end(&inchar_time);
1220 profile_add(&prof_wait_time, &inchar_time);
1221}
1222
1223/*
1224 * Dump the profiling results for all scripts in file "fd".
1225 */
1226 static void
1227script_dump_profile(fd)
1228 FILE *fd;
1229{
1230 int id;
1231 scriptitem_T *si;
1232 int i;
1233 FILE *sfd;
1234 sn_prl_T *pp;
1235
1236 for (id = 1; id <= script_items.ga_len; ++id)
1237 {
1238 si = &SCRIPT_ITEM(id);
1239 if (si->sn_prof_on)
1240 {
1241 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1242 if (si->sn_pr_count == 1)
1243 fprintf(fd, "Sourced 1 time\n");
1244 else
1245 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1246 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1247 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1248 fprintf(fd, "\n");
1249 fprintf(fd, "count total (s) self (s)\n");
1250
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001251 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001252 if (sfd == NULL)
1253 fprintf(fd, "Cannot open file!\n");
1254 else
1255 {
1256 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1257 {
1258 if (vim_fgets(IObuff, IOSIZE, sfd))
1259 break;
1260 pp = &PRL_ITEM(si, i);
1261 if (pp->snp_count > 0)
1262 {
1263 fprintf(fd, "%5d ", pp->snp_count);
1264 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1265 fprintf(fd, " ");
1266 else
1267 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1268 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1269 }
1270 else
1271 fprintf(fd, " ");
1272 fprintf(fd, "%s", IObuff);
1273 }
1274 fclose(sfd);
1275 }
1276 fprintf(fd, "\n");
1277 }
1278 }
1279}
1280
1281/*
1282 * Return TRUE when a function defined in the current script should be
1283 * profiled.
1284 */
1285 int
1286prof_def_func()
1287{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001288 if (current_SID > 0)
1289 return SCRIPT_ITEM(current_SID).sn_pr_force;
1290 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001291}
1292
1293# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294#endif
1295
1296/*
1297 * If 'autowrite' option set, try to write the file.
1298 * Careful: autocommands may make "buf" invalid!
1299 *
1300 * return FAIL for failure, OK otherwise
1301 */
1302 int
1303autowrite(buf, forceit)
1304 buf_T *buf;
1305 int forceit;
1306{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001307 int r;
1308
Bram Moolenaar071d4272004-06-13 20:20:40 +00001309 if (!(p_aw || p_awa) || !p_write
1310#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001311 /* never autowrite a "nofile" or "nowrite" buffer */
1312 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001314 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001316 r = buf_write_all(buf, forceit);
1317
1318 /* Writing may succeed but the buffer still changed, e.g., when there is a
1319 * conversion error. We do want to return FAIL then. */
1320 if (buf_valid(buf) && bufIsChanged(buf))
1321 r = FAIL;
1322 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001323}
1324
1325/*
1326 * flush all buffers, except the ones that are readonly
1327 */
1328 void
1329autowrite_all()
1330{
1331 buf_T *buf;
1332
1333 if (!(p_aw || p_awa) || !p_write)
1334 return;
1335 for (buf = firstbuf; buf; buf = buf->b_next)
1336 if (bufIsChanged(buf) && !buf->b_p_ro)
1337 {
1338 (void)buf_write_all(buf, FALSE);
1339#ifdef FEAT_AUTOCMD
1340 /* an autocommand may have deleted the buffer */
1341 if (!buf_valid(buf))
1342 buf = firstbuf;
1343#endif
1344 }
1345}
1346
1347/*
1348 * return TRUE if buffer was changed and cannot be abandoned.
1349 */
1350/*ARGSUSED*/
1351 int
1352check_changed(buf, checkaw, mult_win, forceit, allbuf)
1353 buf_T *buf;
1354 int checkaw; /* do autowrite if buffer was changed */
1355 int mult_win; /* check also when several wins for the buf */
1356 int forceit;
1357 int allbuf; /* may write all buffers */
1358{
1359 if ( !forceit
1360 && bufIsChanged(buf)
1361 && (mult_win || buf->b_nwindows <= 1)
1362 && (!checkaw || autowrite(buf, forceit) == FAIL))
1363 {
1364#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1365 if ((p_confirm || cmdmod.confirm) && p_write)
1366 {
1367 buf_T *buf2;
1368 int count = 0;
1369
1370 if (allbuf)
1371 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1372 if (bufIsChanged(buf2)
1373 && (buf2->b_ffname != NULL
1374# ifdef FEAT_BROWSE
1375 || cmdmod.browse
1376# endif
1377 ))
1378 ++count;
1379# ifdef FEAT_AUTOCMD
1380 if (!buf_valid(buf))
1381 /* Autocommand deleted buffer, oops! It's not changed now. */
1382 return FALSE;
1383# endif
1384 dialog_changed(buf, count > 1);
1385# ifdef FEAT_AUTOCMD
1386 if (!buf_valid(buf))
1387 /* Autocommand deleted buffer, oops! It's not changed now. */
1388 return FALSE;
1389# endif
1390 return bufIsChanged(buf);
1391 }
1392#endif
1393 EMSG(_(e_nowrtmsg));
1394 return TRUE;
1395 }
1396 return FALSE;
1397}
1398
1399#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1400
1401#if defined(FEAT_BROWSE) || defined(PROTO)
1402/*
1403 * When wanting to write a file without a file name, ask the user for a name.
1404 */
1405 void
1406browse_save_fname(buf)
1407 buf_T *buf;
1408{
1409 if (buf->b_fname == NULL)
1410 {
1411 char_u *fname;
1412
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001413 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1414 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001415 if (fname != NULL)
1416 {
1417 if (setfname(buf, fname, NULL, TRUE) == OK)
1418 buf->b_flags |= BF_NOTEDITED;
1419 vim_free(fname);
1420 }
1421 }
1422}
1423#endif
1424
1425/*
1426 * Ask the user what to do when abondoning a changed buffer.
1427 * Must check 'write' option first!
1428 */
1429 void
1430dialog_changed(buf, checkall)
1431 buf_T *buf;
1432 int checkall; /* may abandon all changed buffers */
1433{
1434 char_u buff[IOSIZE];
1435 int ret;
1436 buf_T *buf2;
1437
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001438 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001439 (buf->b_fname != NULL) ?
1440 buf->b_fname : (char_u *)_("Untitled"));
1441 if (checkall)
1442 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1443 else
1444 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1445
1446 if (ret == VIM_YES)
1447 {
1448#ifdef FEAT_BROWSE
1449 /* May get file name, when there is none */
1450 browse_save_fname(buf);
1451#endif
1452 if (buf->b_fname != NULL) /* didn't hit Cancel */
1453 (void)buf_write_all(buf, FALSE);
1454 }
1455 else if (ret == VIM_NO)
1456 {
1457 unchanged(buf, TRUE);
1458 }
1459 else if (ret == VIM_ALL)
1460 {
1461 /*
1462 * Write all modified files that can be written.
1463 * Skip readonly buffers, these need to be confirmed
1464 * individually.
1465 */
1466 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1467 {
1468 if (bufIsChanged(buf2)
1469 && (buf2->b_ffname != NULL
1470#ifdef FEAT_BROWSE
1471 || cmdmod.browse
1472#endif
1473 )
1474 && !buf2->b_p_ro)
1475 {
1476#ifdef FEAT_BROWSE
1477 /* May get file name, when there is none */
1478 browse_save_fname(buf2);
1479#endif
1480 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1481 (void)buf_write_all(buf2, FALSE);
1482#ifdef FEAT_AUTOCMD
1483 /* an autocommand may have deleted the buffer */
1484 if (!buf_valid(buf2))
1485 buf2 = firstbuf;
1486#endif
1487 }
1488 }
1489 }
1490 else if (ret == VIM_DISCARDALL)
1491 {
1492 /*
1493 * mark all buffers as unchanged
1494 */
1495 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1496 unchanged(buf2, TRUE);
1497 }
1498}
1499#endif
1500
1501/*
1502 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1503 * hidden, autowriting it or unloading it.
1504 */
1505 int
1506can_abandon(buf, forceit)
1507 buf_T *buf;
1508 int forceit;
1509{
1510 return ( P_HID(buf)
1511 || !bufIsChanged(buf)
1512 || buf->b_nwindows > 1
1513 || autowrite(buf, forceit) == OK
1514 || forceit);
1515}
1516
1517/*
1518 * Return TRUE if any buffer was changed and cannot be abandoned.
1519 * That changed buffer becomes the current buffer.
1520 */
1521 int
1522check_changed_any(hidden)
1523 int hidden; /* Only check hidden buffers */
1524{
1525 buf_T *buf;
1526 int save;
1527#ifdef FEAT_WINDOWS
1528 win_T *wp;
1529#endif
1530
1531 for (;;)
1532 {
1533 /* check curbuf first: if it was changed we can't abandon it */
1534 if (!hidden && curbufIsChanged())
1535 buf = curbuf;
1536 else
1537 {
1538 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1539 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1540 break;
1541 }
1542 if (buf == NULL) /* No buffers changed */
1543 return FALSE;
1544
Bram Moolenaar373154b2007-02-13 05:19:30 +00001545 /* Try auto-writing the buffer. If this fails but the buffer no
1546 * longer exists it's not changed, that's OK. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001547 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1548 break; /* didn't save - still changes */
1549 }
1550
1551 exiting = FALSE;
1552#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1553 /*
1554 * When ":confirm" used, don't give an error message.
1555 */
1556 if (!(p_confirm || cmdmod.confirm))
1557#endif
1558 {
1559 /* There must be a wait_return for this message, do_buffer()
1560 * may cause a redraw. But wait_return() is a no-op when vgetc()
1561 * is busy (Quit used from window menu), then make sure we don't
1562 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001563 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001564 {
1565 msg_row = cmdline_row;
1566 msg_col = 0;
1567 msg_didout = FALSE;
1568 }
1569 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1570 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1571 buf->b_fname))
1572 {
1573 save = no_wait_return;
1574 no_wait_return = FALSE;
1575 wait_return(FALSE);
1576 no_wait_return = save;
1577 }
1578 }
1579
1580#ifdef FEAT_WINDOWS
1581 /* Try to find a window that contains the buffer. */
1582 if (buf != curbuf)
1583 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1584 if (wp->w_buffer == buf)
1585 {
1586 win_goto(wp);
1587# ifdef FEAT_AUTOCMD
1588 /* Paranoia: did autocms wipe out the buffer with changes? */
1589 if (!buf_valid(buf))
1590 return TRUE;
1591# endif
1592 break;
1593 }
1594#endif
1595
1596 /* Open the changed buffer in the current window. */
1597 if (buf != curbuf)
1598 set_curbuf(buf, DOBUF_GOTO);
1599
1600 return TRUE;
1601}
1602
1603/*
1604 * return FAIL if there is no file name, OK if there is one
1605 * give error message for FAIL
1606 */
1607 int
1608check_fname()
1609{
1610 if (curbuf->b_ffname == NULL)
1611 {
1612 EMSG(_(e_noname));
1613 return FAIL;
1614 }
1615 return OK;
1616}
1617
1618/*
1619 * flush the contents of a buffer, unless it has no file name
1620 *
1621 * return FAIL for failure, OK otherwise
1622 */
1623 int
1624buf_write_all(buf, forceit)
1625 buf_T *buf;
1626 int forceit;
1627{
1628 int retval;
1629#ifdef FEAT_AUTOCMD
1630 buf_T *old_curbuf = curbuf;
1631#endif
1632
1633 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1634 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1635 FALSE, forceit, TRUE, FALSE));
1636#ifdef FEAT_AUTOCMD
1637 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001638 {
1639 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001640 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001641 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001642#endif
1643 return retval;
1644}
1645
1646/*
1647 * Code to handle the argument list.
1648 */
1649
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001650static char_u *do_one_arg __ARGS((char_u *str));
1651static int do_arglist __ARGS((char_u *str, int what, int after));
1652static void alist_check_arg_idx __ARGS((void));
1653static int editing_arg_idx __ARGS((win_T *win));
1654#ifdef FEAT_LISTCMDS
1655static int alist_add_list __ARGS((int count, char_u **files, int after));
1656#endif
1657#define AL_SET 1
1658#define AL_ADD 2
1659#define AL_DEL 3
1660
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001662 * Isolate one argument, taking backticks.
1663 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664 * Return a pointer to the start of the next argument.
1665 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001666 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667do_one_arg(str)
1668 char_u *str;
1669{
1670 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001671 int inbacktick;
1672
Bram Moolenaar071d4272004-06-13 20:20:40 +00001673 inbacktick = FALSE;
1674 for (p = str; *str; ++str)
1675 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001676 /* When the backslash is used for escaping the special meaning of a
1677 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678 if (rem_backslash(str))
1679 {
1680 *p++ = *str++;
1681 *p++ = *str;
1682 }
1683 else
1684 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001685 /* An item ends at a space not in backticks */
1686 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001687 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001688 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001690 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691 }
1692 }
1693 str = skipwhite(str);
1694 *p = NUL;
1695
1696 return str;
1697}
1698
Bram Moolenaar86b68352004-12-27 21:59:20 +00001699/*
1700 * Separate the arguments in "str" and return a list of pointers in the
1701 * growarray "gap".
1702 */
1703 int
1704get_arglist(gap, str)
1705 garray_T *gap;
1706 char_u *str;
1707{
1708 ga_init2(gap, (int)sizeof(char_u *), 20);
1709 while (*str != NUL)
1710 {
1711 if (ga_grow(gap, 1) == FAIL)
1712 {
1713 ga_clear(gap);
1714 return FAIL;
1715 }
1716 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1717
1718 /* Isolate one argument, change it in-place, put a NUL after it. */
1719 str = do_one_arg(str);
1720 }
1721 return OK;
1722}
1723
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001724#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001725/*
1726 * Parse a list of arguments (file names), expand them and return in
1727 * "fnames[fcountp]".
1728 * Return FAIL or OK.
1729 */
1730 int
1731get_arglist_exp(str, fcountp, fnamesp)
1732 char_u *str;
1733 int *fcountp;
1734 char_u ***fnamesp;
1735{
1736 garray_T ga;
1737 int i;
1738
1739 if (get_arglist(&ga, str) == FAIL)
1740 return FAIL;
1741 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1742 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1743 ga_clear(&ga);
1744 return i;
1745}
1746#endif
1747
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1749/*
1750 * Redefine the argument list.
1751 */
1752 void
1753set_arglist(str)
1754 char_u *str;
1755{
1756 do_arglist(str, AL_SET, 0);
1757}
1758#endif
1759
1760/*
1761 * "what" == AL_SET: Redefine the argument list to 'str'.
1762 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1763 * "what" == AL_DEL: remove files in 'str' from the argument list.
1764 *
1765 * Return FAIL for failure, OK otherwise.
1766 */
1767/*ARGSUSED*/
1768 static int
1769do_arglist(str, what, after)
1770 char_u *str;
1771 int what;
1772 int after; /* 0 means before first one */
1773{
1774 garray_T new_ga;
1775 int exp_count;
1776 char_u **exp_files;
1777 int i;
1778#ifdef FEAT_LISTCMDS
1779 char_u *p;
1780 int match;
1781#endif
1782
1783 /*
1784 * Collect all file name arguments in "new_ga".
1785 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001786 if (get_arglist(&new_ga, str) == FAIL)
1787 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788
1789#ifdef FEAT_LISTCMDS
1790 if (what == AL_DEL)
1791 {
1792 regmatch_T regmatch;
1793 int didone;
1794
1795 /*
1796 * Delete the items: use each item as a regexp and find a match in the
1797 * argument list.
1798 */
1799#ifdef CASE_INSENSITIVE_FILENAME
1800 regmatch.rm_ic = TRUE; /* Always ignore case */
1801#else
1802 regmatch.rm_ic = FALSE; /* Never ignore case */
1803#endif
1804 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1805 {
1806 p = ((char_u **)new_ga.ga_data)[i];
1807 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1808 if (p == NULL)
1809 break;
1810 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1811 if (regmatch.regprog == NULL)
1812 {
1813 vim_free(p);
1814 break;
1815 }
1816
1817 didone = FALSE;
1818 for (match = 0; match < ARGCOUNT; ++match)
1819 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1820 (colnr_T)0))
1821 {
1822 didone = TRUE;
1823 vim_free(ARGLIST[match].ae_fname);
1824 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1825 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1826 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827 if (curwin->w_arg_idx > match)
1828 --curwin->w_arg_idx;
1829 --match;
1830 }
1831
1832 vim_free(regmatch.regprog);
1833 vim_free(p);
1834 if (!didone)
1835 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1836 }
1837 ga_clear(&new_ga);
1838 }
1839 else
1840#endif
1841 {
1842 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1843 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1844 ga_clear(&new_ga);
1845 if (i == FAIL)
1846 return FAIL;
1847 if (exp_count == 0)
1848 {
1849 EMSG(_(e_nomatch));
1850 return FAIL;
1851 }
1852
1853#ifdef FEAT_LISTCMDS
1854 if (what == AL_ADD)
1855 {
1856 (void)alist_add_list(exp_count, exp_files, after);
1857 vim_free(exp_files);
1858 }
1859 else /* what == AL_SET */
1860#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001861 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862 }
1863
1864 alist_check_arg_idx();
1865
1866 return OK;
1867}
1868
1869/*
1870 * Check the validity of the arg_idx for each other window.
1871 */
1872 static void
1873alist_check_arg_idx()
1874{
1875#ifdef FEAT_WINDOWS
1876 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001877 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001878
Bram Moolenaarf740b292006-02-16 22:11:02 +00001879 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880 if (win->w_alist == curwin->w_alist)
1881 check_arg_idx(win);
1882#else
1883 check_arg_idx(curwin);
1884#endif
1885}
1886
1887/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001888 * Return TRUE if window "win" is editing then file at the current argument
1889 * index.
1890 */
1891 static int
1892editing_arg_idx(win)
1893 win_T *win;
1894{
1895 return !(win->w_arg_idx >= WARGCOUNT(win)
1896 || (win->w_buffer->b_fnum
1897 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1898 && (win->w_buffer->b_ffname == NULL
1899 || !(fullpathcmp(
1900 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1901 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1902}
1903
1904/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905 * Check if window "win" is editing the w_arg_idx file in its argument list.
1906 */
1907 void
1908check_arg_idx(win)
1909 win_T *win;
1910{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001911 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912 {
1913 /* We are not editing the current entry in the argument list.
1914 * Set "arg_had_last" if we are editing the last one. */
1915 win->w_arg_idx_invalid = TRUE;
1916 if (win->w_arg_idx != WARGCOUNT(win) - 1
1917 && arg_had_last == FALSE
1918#ifdef FEAT_WINDOWS
1919 && ALIST(win) == &global_alist
1920#endif
1921 && GARGCOUNT > 0
1922 && win->w_arg_idx < GARGCOUNT
1923 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1924 || (win->w_buffer->b_ffname != NULL
1925 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1926 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1927 arg_had_last = TRUE;
1928 }
1929 else
1930 {
1931 /* We are editing the current entry in the argument list.
1932 * Set "arg_had_last" if it's also the last one */
1933 win->w_arg_idx_invalid = FALSE;
1934 if (win->w_arg_idx == WARGCOUNT(win) - 1
1935#ifdef FEAT_WINDOWS
1936 && win->w_alist == &global_alist
1937#endif
1938 )
1939 arg_had_last = TRUE;
1940 }
1941}
1942
1943/*
1944 * ":args", ":argslocal" and ":argsglobal".
1945 */
1946 void
1947ex_args(eap)
1948 exarg_T *eap;
1949{
1950 int i;
1951
1952 if (eap->cmdidx != CMD_args)
1953 {
1954#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1955 alist_unlink(ALIST(curwin));
1956 if (eap->cmdidx == CMD_argglobal)
1957 ALIST(curwin) = &global_alist;
1958 else /* eap->cmdidx == CMD_arglocal */
1959 alist_new();
1960#else
1961 ex_ni(eap);
1962 return;
1963#endif
1964 }
1965
1966 if (!ends_excmd(*eap->arg))
1967 {
1968 /*
1969 * ":args file ..": define new argument list, handle like ":next"
1970 * Also for ":argslocal file .." and ":argsglobal file ..".
1971 */
1972 ex_next(eap);
1973 }
1974 else
1975#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1976 if (eap->cmdidx == CMD_args)
1977#endif
1978 {
1979 /*
1980 * ":args": list arguments.
1981 */
1982 if (ARGCOUNT > 0)
1983 {
1984 /* Overwrite the command, for a short list there is no scrolling
1985 * required and no wait_return(). */
1986 gotocmdline(TRUE);
1987 for (i = 0; i < ARGCOUNT; ++i)
1988 {
1989 if (i == curwin->w_arg_idx)
1990 msg_putchar('[');
1991 msg_outtrans(alist_name(&ARGLIST[i]));
1992 if (i == curwin->w_arg_idx)
1993 msg_putchar(']');
1994 msg_putchar(' ');
1995 }
1996 }
1997 }
1998#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1999 else if (eap->cmdidx == CMD_arglocal)
2000 {
2001 garray_T *gap = &curwin->w_alist->al_ga;
2002
2003 /*
2004 * ":argslocal": make a local copy of the global argument list.
2005 */
2006 if (ga_grow(gap, GARGCOUNT) == OK)
2007 for (i = 0; i < GARGCOUNT; ++i)
2008 if (GARGLIST[i].ae_fname != NULL)
2009 {
2010 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2011 vim_strsave(GARGLIST[i].ae_fname);
2012 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2013 GARGLIST[i].ae_fnum;
2014 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002015 }
2016 }
2017#endif
2018}
2019
2020/*
2021 * ":previous", ":sprevious", ":Next" and ":sNext".
2022 */
2023 void
2024ex_previous(eap)
2025 exarg_T *eap;
2026{
2027 /* If past the last one already, go to the last one. */
2028 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2029 do_argfile(eap, ARGCOUNT - 1);
2030 else
2031 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2032}
2033
2034/*
2035 * ":rewind", ":first", ":sfirst" and ":srewind".
2036 */
2037 void
2038ex_rewind(eap)
2039 exarg_T *eap;
2040{
2041 do_argfile(eap, 0);
2042}
2043
2044/*
2045 * ":last" and ":slast".
2046 */
2047 void
2048ex_last(eap)
2049 exarg_T *eap;
2050{
2051 do_argfile(eap, ARGCOUNT - 1);
2052}
2053
2054/*
2055 * ":argument" and ":sargument".
2056 */
2057 void
2058ex_argument(eap)
2059 exarg_T *eap;
2060{
2061 int i;
2062
2063 if (eap->addr_count > 0)
2064 i = eap->line2 - 1;
2065 else
2066 i = curwin->w_arg_idx;
2067 do_argfile(eap, i);
2068}
2069
2070/*
2071 * Edit file "argn" of the argument lists.
2072 */
2073 void
2074do_argfile(eap, argn)
2075 exarg_T *eap;
2076 int argn;
2077{
2078 int other;
2079 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002080 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081
2082 if (argn < 0 || argn >= ARGCOUNT)
2083 {
2084 if (ARGCOUNT <= 1)
2085 EMSG(_("E163: There is only one file to edit"));
2086 else if (argn < 0)
2087 EMSG(_("E164: Cannot go before first file"));
2088 else
2089 EMSG(_("E165: Cannot go beyond last file"));
2090 }
2091 else
2092 {
2093 setpcmark();
2094#ifdef FEAT_GUI
2095 need_mouse_correct = TRUE;
2096#endif
2097
2098#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002099 /* split window or create new tab page first */
2100 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002101 {
2102 if (win_split(0, 0) == FAIL)
2103 return;
2104# ifdef FEAT_SCROLLBIND
2105 curwin->w_p_scb = FALSE;
2106# endif
2107 }
2108 else
2109#endif
2110 {
2111 /*
2112 * if 'hidden' set, only check for changed file when re-editing
2113 * the same buffer
2114 */
2115 other = TRUE;
2116 if (P_HID(curbuf))
2117 {
2118 p = fix_fname(alist_name(&ARGLIST[argn]));
2119 other = otherfile(p);
2120 vim_free(p);
2121 }
2122 if ((!P_HID(curbuf) || !other)
2123 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2124 return;
2125 }
2126
2127 curwin->w_arg_idx = argn;
2128 if (argn == ARGCOUNT - 1
2129#ifdef FEAT_WINDOWS
2130 && curwin->w_alist == &global_alist
2131#endif
2132 )
2133 arg_had_last = TRUE;
2134
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002135 /* Edit the file; always use the last known line number.
2136 * When it fails (e.g. Abort for already edited file) restore the
2137 * argument index. */
2138 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002139 eap, ECMD_LAST,
2140 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) +
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002141 (eap->forceit ? ECMD_FORCEIT : 0)) == FAIL)
2142 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002144 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145 setmark('\'');
2146 }
2147}
2148
2149/*
2150 * ":next", and commands that behave like it.
2151 */
2152 void
2153ex_next(eap)
2154 exarg_T *eap;
2155{
2156 int i;
2157
2158 /*
2159 * check for changed buffer now, if this fails the argument list is not
2160 * redefined.
2161 */
2162 if ( P_HID(curbuf)
2163 || eap->cmdidx == CMD_snext
2164 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2165 {
2166 if (*eap->arg != NUL) /* redefine file list */
2167 {
2168 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2169 return;
2170 i = 0;
2171 }
2172 else
2173 i = curwin->w_arg_idx + (int)eap->line2;
2174 do_argfile(eap, i);
2175 }
2176}
2177
2178#ifdef FEAT_LISTCMDS
2179/*
2180 * ":argedit"
2181 */
2182 void
2183ex_argedit(eap)
2184 exarg_T *eap;
2185{
2186 int fnum;
2187 int i;
2188 char_u *s;
2189
2190 /* Add the argument to the buffer list and get the buffer number. */
2191 fnum = buflist_add(eap->arg, BLN_LISTED);
2192
2193 /* Check if this argument is already in the argument list. */
2194 for (i = 0; i < ARGCOUNT; ++i)
2195 if (ARGLIST[i].ae_fnum == fnum)
2196 break;
2197 if (i == ARGCOUNT)
2198 {
2199 /* Can't find it, add it to the argument list. */
2200 s = vim_strsave(eap->arg);
2201 if (s == NULL)
2202 return;
2203 i = alist_add_list(1, &s,
2204 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2205 if (i < 0)
2206 return;
2207 curwin->w_arg_idx = i;
2208 }
2209
2210 alist_check_arg_idx();
2211
2212 /* Edit the argument. */
2213 do_argfile(eap, i);
2214}
2215
2216/*
2217 * ":argadd"
2218 */
2219 void
2220ex_argadd(eap)
2221 exarg_T *eap;
2222{
2223 do_arglist(eap->arg, AL_ADD,
2224 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2225#ifdef FEAT_TITLE
2226 maketitle();
2227#endif
2228}
2229
2230/*
2231 * ":argdelete"
2232 */
2233 void
2234ex_argdelete(eap)
2235 exarg_T *eap;
2236{
2237 int i;
2238 int n;
2239
2240 if (eap->addr_count > 0)
2241 {
2242 /* ":1,4argdel": Delete all arguments in the range. */
2243 if (eap->line2 > ARGCOUNT)
2244 eap->line2 = ARGCOUNT;
2245 n = eap->line2 - eap->line1 + 1;
2246 if (*eap->arg != NUL || n <= 0)
2247 EMSG(_(e_invarg));
2248 else
2249 {
2250 for (i = eap->line1; i <= eap->line2; ++i)
2251 vim_free(ARGLIST[i - 1].ae_fname);
2252 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2253 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2254 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255 if (curwin->w_arg_idx >= eap->line2)
2256 curwin->w_arg_idx -= n;
2257 else if (curwin->w_arg_idx > eap->line1)
2258 curwin->w_arg_idx = eap->line1;
2259 }
2260 }
2261 else if (*eap->arg == NUL)
2262 EMSG(_(e_argreq));
2263 else
2264 do_arglist(eap->arg, AL_DEL, 0);
2265#ifdef FEAT_TITLE
2266 maketitle();
2267#endif
2268}
2269
2270/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002271 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002272 */
2273 void
2274ex_listdo(eap)
2275 exarg_T *eap;
2276{
2277 int i;
2278#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002279 win_T *wp;
2280 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002281#endif
2282 buf_T *buf;
2283 int next_fnum = 0;
2284#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2285 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002287 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002288
2289#ifndef FEAT_WINDOWS
2290 if (eap->cmdidx == CMD_windo)
2291 {
2292 ex_ni(eap);
2293 return;
2294 }
2295#endif
2296
2297#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002298 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002299 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2300 * great speed improvement. */
2301 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002302#endif
2303
2304 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002305 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306 || P_HID(curbuf)
2307 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2308 {
2309 /* start at the first argument/window/buffer */
2310 i = 0;
2311#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002312 wp = firstwin;
2313 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002314#endif
2315 /* set pcmark now */
2316 if (eap->cmdidx == CMD_bufdo)
2317 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2318 else
2319 setpcmark();
2320 listcmd_busy = TRUE; /* avoids setting pcmark below */
2321
2322 while (!got_int)
2323 {
2324 if (eap->cmdidx == CMD_argdo)
2325 {
2326 /* go to argument "i" */
2327 if (i == ARGCOUNT)
2328 break;
2329 /* Don't call do_argfile() when already there, it will try
2330 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002331 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002332 {
2333 /* Clear 'shm' to avoid that the file message overwrites
2334 * any output from the command. */
2335 p_shm_save = vim_strsave(p_shm);
2336 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002338 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2339 vim_free(p_shm_save);
2340 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002341 if (curwin->w_arg_idx != i)
2342 break;
2343 ++i;
2344 }
2345#ifdef FEAT_WINDOWS
2346 else if (eap->cmdidx == CMD_windo)
2347 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002348 /* go to window "wp" */
2349 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002351 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002352 if (curwin != wp)
2353 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002354 wp = curwin->w_next;
2355 }
2356 else if (eap->cmdidx == CMD_tabdo)
2357 {
2358 /* go to window "tp" */
2359 if (!valid_tabpage(tp))
2360 break;
2361 goto_tabpage_tp(tp);
2362 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 }
2364#endif
2365 else if (eap->cmdidx == CMD_bufdo)
2366 {
2367 /* Remember the number of the next listed buffer, in case
2368 * ":bwipe" is used or autocommands do something strange. */
2369 next_fnum = -1;
2370 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2371 if (buf->b_p_bl)
2372 {
2373 next_fnum = buf->b_fnum;
2374 break;
2375 }
2376 }
2377
2378 /* execute the command */
2379 do_cmdline(eap->arg, eap->getline, eap->cookie,
2380 DOCMD_VERBOSE + DOCMD_NOWAIT);
2381
2382 if (eap->cmdidx == CMD_bufdo)
2383 {
2384 /* Done? */
2385 if (next_fnum < 0)
2386 break;
2387 /* Check if the buffer still exists. */
2388 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2389 if (buf->b_fnum == next_fnum)
2390 break;
2391 if (buf == NULL)
2392 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002393
2394 /* Go to the next buffer. Clear 'shm' to avoid that the file
2395 * message overwrites any output from the command. */
2396 p_shm_save = vim_strsave(p_shm);
2397 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002399 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2400 vim_free(p_shm_save);
2401
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402 /* If autocommands took us elsewhere, quit here */
2403 if (curbuf->b_fnum != next_fnum)
2404 break;
2405 }
2406
2407 if (eap->cmdidx == CMD_windo)
2408 {
2409 validate_cursor(); /* cursor may have moved */
2410#ifdef FEAT_SCROLLBIND
2411 /* required when 'scrollbind' has been set */
2412 if (curwin->w_p_scb)
2413 do_check_scrollbind(TRUE);
2414#endif
2415 }
2416 }
2417 listcmd_busy = FALSE;
2418 }
2419
2420#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002421 if (save_ei != NULL)
2422 {
2423 au_event_restore(save_ei);
2424 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2425 curbuf->b_fname, TRUE, curbuf);
2426 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002427#endif
2428}
2429
2430/*
2431 * Add files[count] to the arglist of the current window after arg "after".
2432 * The file names in files[count] must have been allocated and are taken over.
2433 * Files[] itself is not taken over.
2434 * Returns index of first added argument. Returns -1 when failed (out of mem).
2435 */
2436 static int
2437alist_add_list(count, files, after)
2438 int count;
2439 char_u **files;
2440 int after; /* where to add: 0 = before first one */
2441{
2442 int i;
2443
2444 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2445 {
2446 if (after < 0)
2447 after = 0;
2448 if (after > ARGCOUNT)
2449 after = ARGCOUNT;
2450 if (after < ARGCOUNT)
2451 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2452 (ARGCOUNT - after) * sizeof(aentry_T));
2453 for (i = 0; i < count; ++i)
2454 {
2455 ARGLIST[after + i].ae_fname = files[i];
2456 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2457 }
2458 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 if (curwin->w_arg_idx >= after)
2460 ++curwin->w_arg_idx;
2461 return after;
2462 }
2463
2464 for (i = 0; i < count; ++i)
2465 vim_free(files[i]);
2466 return -1;
2467}
2468
2469#endif /* FEAT_LISTCMDS */
2470
2471#ifdef FEAT_EVAL
2472/*
2473 * ":compiler[!] {name}"
2474 */
2475 void
2476ex_compiler(eap)
2477 exarg_T *eap;
2478{
2479 char_u *buf;
2480 char_u *old_cur_comp = NULL;
2481 char_u *p;
2482
2483 if (*eap->arg == NUL)
2484 {
2485 /* List all compiler scripts. */
2486 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2487 /* ) keep the indenter happy... */
2488 }
2489 else
2490 {
2491 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2492 if (buf != NULL)
2493 {
2494 if (eap->forceit)
2495 {
2496 /* ":compiler! {name}" sets global options */
2497 do_cmdline_cmd((char_u *)
2498 "command -nargs=* CompilerSet set <args>");
2499 }
2500 else
2501 {
2502 /* ":compiler! {name}" sets local options.
2503 * To remain backwards compatible "current_compiler" is always
2504 * used. A user's compiler plugin may set it, the distributed
2505 * plugin will then skip the settings. Afterwards set
2506 * "b:current_compiler" and restore "current_compiler". */
2507 old_cur_comp = get_var_value((char_u *)"current_compiler");
2508 if (old_cur_comp != NULL)
2509 old_cur_comp = vim_strsave(old_cur_comp);
2510 do_cmdline_cmd((char_u *)
2511 "command -nargs=* CompilerSet setlocal <args>");
2512 }
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002513 do_unlet((char_u *)"current_compiler", TRUE);
2514 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515
2516 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002517 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2519 vim_free(buf);
2520
2521 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2522
2523 /* Set "b:current_compiler" from "current_compiler". */
2524 p = get_var_value((char_u *)"current_compiler");
2525 if (p != NULL)
2526 set_internal_string_var((char_u *)"b:current_compiler", p);
2527
2528 /* Restore "current_compiler" for ":compiler {name}". */
2529 if (!eap->forceit)
2530 {
2531 if (old_cur_comp != NULL)
2532 {
2533 set_internal_string_var((char_u *)"current_compiler",
2534 old_cur_comp);
2535 vim_free(old_cur_comp);
2536 }
2537 else
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002538 do_unlet((char_u *)"current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539 }
2540 }
2541 }
2542}
2543#endif
2544
2545/*
2546 * ":runtime {name}"
2547 */
2548 void
2549ex_runtime(eap)
2550 exarg_T *eap;
2551{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002552 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002553}
2554
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002555static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002557/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002559source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 char_u *fname;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002561 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002563 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564}
2565
2566/*
2567 * Source the file "name" from all directories in 'runtimepath'.
2568 * "name" can contain wildcards.
2569 * When "all" is TRUE, source all files, otherwise only the first one.
2570 * return FAIL when no file could be sourced, OK otherwise.
2571 */
2572 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002573source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574 char_u *name;
2575 int all;
2576{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002577 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578}
2579
2580/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002581 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2582 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2584 * used.
2585 * Returns OK when at least one match found, FAIL otherwise.
2586 */
2587 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002588do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 char_u *name;
2590 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002591 void (*callback)__ARGS((char_u *fname, void *ck));
2592 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593{
2594 char_u *rtp;
2595 char_u *np;
2596 char_u *buf;
2597 char_u *rtp_copy;
2598 char_u *tail;
2599 int num_files;
2600 char_u **files;
2601 int i;
2602 int did_one = FALSE;
2603#ifdef AMIGA
2604 struct Process *proc = (struct Process *)FindTask(0L);
2605 APTR save_winptr = proc->pr_WindowPtr;
2606
2607 /* Avoid a requester here for a volume that doesn't exist. */
2608 proc->pr_WindowPtr = (APTR)-1L;
2609#endif
2610
2611 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2612 * value. */
2613 rtp_copy = vim_strsave(p_rtp);
2614 buf = alloc(MAXPATHL);
2615 if (buf != NULL && rtp_copy != NULL)
2616 {
2617 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002618 {
2619 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002620 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002621 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002622 verbose_leave();
2623 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002624
Bram Moolenaar071d4272004-06-13 20:20:40 +00002625 /* Loop over all entries in 'runtimepath'. */
2626 rtp = rtp_copy;
2627 while (*rtp != NUL && (all || !did_one))
2628 {
2629 /* Copy the path from 'runtimepath' to buf[]. */
2630 copy_option_part(&rtp, buf, MAXPATHL, ",");
2631 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2632 {
2633 add_pathsep(buf);
2634 tail = buf + STRLEN(buf);
2635
2636 /* Loop over all patterns in "name" */
2637 np = name;
2638 while (*np != NUL && (all || !did_one))
2639 {
2640 /* Append the pattern from "name" to buf[]. */
2641 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2642 "\t ");
2643
2644 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002645 {
2646 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002647 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002648 verbose_leave();
2649 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650
2651 /* Expand wildcards, invoke the callback for each match. */
2652 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2653 EW_FILE) == OK)
2654 {
2655 for (i = 0; i < num_files; ++i)
2656 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002657 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 did_one = TRUE;
2659 if (!all)
2660 break;
2661 }
2662 FreeWild(num_files, files);
2663 }
2664 }
2665 }
2666 }
2667 }
2668 vim_free(buf);
2669 vim_free(rtp_copy);
2670 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002671 {
2672 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002673 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002674 verbose_leave();
2675 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676
2677#ifdef AMIGA
2678 proc->pr_WindowPtr = save_winptr;
2679#endif
2680
2681 return did_one ? OK : FAIL;
2682}
2683
2684#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2685/*
2686 * ":options"
2687 */
2688/*ARGSUSED*/
2689 void
2690ex_options(eap)
2691 exarg_T *eap;
2692{
2693 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2694}
2695#endif
2696
2697/*
2698 * ":source {fname}"
2699 */
2700 void
2701ex_source(eap)
2702 exarg_T *eap;
2703{
2704#ifdef FEAT_BROWSE
2705 if (cmdmod.browse)
2706 {
2707 char_u *fname = NULL;
2708
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002709 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2711 if (fname != NULL)
2712 {
2713 cmd_source(fname, eap);
2714 vim_free(fname);
2715 }
2716 }
2717 else
2718#endif
2719 cmd_source(eap->arg, eap);
2720}
2721
2722 static void
2723cmd_source(fname, eap)
2724 char_u *fname;
2725 exarg_T *eap;
2726{
2727 if (*fname == NUL)
2728 EMSG(_(e_argreq));
2729
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002731 /* ":source!": read Normal mdoe commands
2732 * Need to execute the commands directly. This is required at least
2733 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734 * - ":g" command busy
2735 * - after ":argdo", ":windo" or ":bufdo"
2736 * - another command follows
2737 * - inside a loop
2738 */
2739 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2740#ifdef FEAT_EVAL
2741 || eap->cstack->cs_idx >= 0
2742#endif
2743 );
2744
2745 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002746 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747 EMSG2(_(e_notopen), fname);
2748}
2749
2750/*
2751 * ":source" and associated commands.
2752 */
2753/*
2754 * Structure used to store info for each sourced file.
2755 * It is shared between do_source() and getsourceline().
2756 * This is required, because it needs to be handed to do_cmdline() and
2757 * sourcing can be done recursively.
2758 */
2759struct source_cookie
2760{
2761 FILE *fp; /* opened file for sourcing */
2762 char_u *nextline; /* if not NULL: line that was read ahead */
2763 int finished; /* ":finish" used */
2764#if defined (USE_CRNL) || defined (USE_CR)
2765 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2766 int error; /* TRUE if LF found after CR-LF */
2767#endif
2768#ifdef FEAT_EVAL
2769 linenr_T breakpoint; /* next line with breakpoint or zero */
2770 char_u *fname; /* name of sourced file */
2771 int dbg_tick; /* debug_tick when breakpoint was set */
2772 int level; /* top nesting level of sourced file */
2773#endif
2774#ifdef FEAT_MBYTE
2775 vimconv_T conv; /* type of conversion */
2776#endif
2777};
2778
2779#ifdef FEAT_EVAL
2780/*
2781 * Return the address holding the next breakpoint line for a source cookie.
2782 */
2783 linenr_T *
2784source_breakpoint(cookie)
2785 void *cookie;
2786{
2787 return &((struct source_cookie *)cookie)->breakpoint;
2788}
2789
2790/*
2791 * Return the address holding the debug tick for a source cookie.
2792 */
2793 int *
2794source_dbg_tick(cookie)
2795 void *cookie;
2796{
2797 return &((struct source_cookie *)cookie)->dbg_tick;
2798}
2799
2800/*
2801 * Return the nesting level for a source cookie.
2802 */
2803 int
2804source_level(cookie)
2805 void *cookie;
2806{
2807 return ((struct source_cookie *)cookie)->level;
2808}
2809#endif
2810
2811static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2812
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813#if defined(WIN32) && defined(FEAT_CSCOPE)
2814static FILE *fopen_noinh_readbin __ARGS((char *filename));
2815
2816/*
2817 * Special function to open a file without handle inheritance.
2818 */
2819 static FILE *
2820fopen_noinh_readbin(filename)
2821 char *filename;
2822{
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00002823 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824
2825 if (fd_tmp == -1)
2826 return NULL;
2827 return fdopen(fd_tmp, READBIN);
2828}
2829#endif
2830
2831
2832/*
2833 * do_source: Read the file "fname" and execute its lines as EX commands.
2834 *
2835 * This function may be called recursively!
2836 *
2837 * return FAIL if file could not be opened, OK otherwise
2838 */
2839 int
2840do_source(fname, check_other, is_vimrc)
2841 char_u *fname;
2842 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002843 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844{
2845 struct source_cookie cookie;
2846 char_u *save_sourcing_name;
2847 linenr_T save_sourcing_lnum;
2848 char_u *p;
2849 char_u *fname_exp;
2850 int retval = FAIL;
2851#ifdef FEAT_EVAL
2852 scid_T save_current_SID;
2853 static scid_T last_current_SID = 0;
2854 void *save_funccalp;
2855 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002856 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857# ifdef UNIX
2858 struct stat st;
2859 int stat_ok;
2860# endif
2861#endif
2862#ifdef STARTUPTIME
2863 struct timeval tv_rel;
2864 struct timeval tv_start;
2865#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002866#ifdef FEAT_PROFILE
2867 proftime_T wait_start;
2868#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869
2870#ifdef RISCOS
2871 p = mch_munge_fname(fname);
2872#else
2873 p = expand_env_save(fname);
2874#endif
2875 if (p == NULL)
2876 return retval;
2877 fname_exp = fix_fname(p);
2878 vim_free(p);
2879 if (fname_exp == NULL)
2880 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881 if (mch_isdir(fname_exp))
2882 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002883 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884 goto theend;
2885 }
2886
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002887#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002888 /* Apply SourceCmd autocommands, they should get the file and source it. */
2889 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2890 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2891 FALSE, curbuf))
2892# ifdef FEAT_EVAL
2893 return aborting() ? FAIL : OK;
2894# else
2895 return OK;
2896# endif
2897
2898 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002899 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2900#endif
2901
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902#if defined(WIN32) && defined(FEAT_CSCOPE)
2903 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2904#else
2905 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2906#endif
2907 if (cookie.fp == NULL && check_other)
2908 {
2909 /*
2910 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2911 * and ".exrc" by "_exrc" or vice versa.
2912 */
2913 p = gettail(fname_exp);
2914 if ((*p == '.' || *p == '_')
2915 && (STRICMP(p + 1, "vimrc") == 0
2916 || STRICMP(p + 1, "gvimrc") == 0
2917 || STRICMP(p + 1, "exrc") == 0))
2918 {
2919 if (*p == '_')
2920 *p = '.';
2921 else
2922 *p = '_';
2923#if defined(WIN32) && defined(FEAT_CSCOPE)
2924 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2925#else
2926 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2927#endif
2928 }
2929 }
2930
2931 if (cookie.fp == NULL)
2932 {
2933 if (p_verbose > 0)
2934 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002935 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002937 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 else
2939 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002940 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002941 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 }
2943 goto theend;
2944 }
2945
2946 /*
2947 * The file exists.
2948 * - In verbose mode, give a message.
2949 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2950 */
2951 if (p_verbose > 1)
2952 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002953 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002955 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956 else
2957 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002958 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002959 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002961 if (is_vimrc == DOSO_VIMRC)
2962 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
2963 else if (is_vimrc == DOSO_GVIMRC)
2964 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965
2966#ifdef USE_CRNL
2967 /* If no automatic file format: Set default to CR-NL. */
2968 if (*p_ffs == NUL)
2969 cookie.fileformat = EOL_DOS;
2970 else
2971 cookie.fileformat = EOL_UNKNOWN;
2972 cookie.error = FALSE;
2973#endif
2974
2975#ifdef USE_CR
2976 /* If no automatic file format: Set default to CR. */
2977 if (*p_ffs == NUL)
2978 cookie.fileformat = EOL_MAC;
2979 else
2980 cookie.fileformat = EOL_UNKNOWN;
2981 cookie.error = FALSE;
2982#endif
2983
2984 cookie.nextline = NULL;
2985 cookie.finished = FALSE;
2986
2987#ifdef FEAT_EVAL
2988 /*
2989 * Check if this script has a breakpoint.
2990 */
2991 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2992 cookie.fname = fname_exp;
2993 cookie.dbg_tick = debug_tick;
2994
2995 cookie.level = ex_nesting_level;
2996#endif
2997#ifdef FEAT_MBYTE
2998 cookie.conv.vc_type = CONV_NONE; /* no conversion */
2999
3000 /* Try reading the first few bytes to check for a UTF-8 BOM. */
3001 {
3002 char_u buf[3];
3003
3004 if (fread((char *)buf, sizeof(char_u), (size_t)3, cookie.fp)
3005 == (size_t)3
3006 && buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf)
3007 /* Found BOM, setup conversion and skip over it. */
3008 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3009 else
3010 /* No BOM found, rewind. */
3011 fseek(cookie.fp, 0L, SEEK_SET);
3012 }
3013#endif
3014
3015 /*
3016 * Keep the sourcing name/lnum, for recursive calls.
3017 */
3018 save_sourcing_name = sourcing_name;
3019 sourcing_name = fname_exp;
3020 save_sourcing_lnum = sourcing_lnum;
3021 sourcing_lnum = 0;
3022
3023#ifdef STARTUPTIME
3024 time_push(&tv_rel, &tv_start);
3025#endif
3026
3027#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003028# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003029 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003030 prof_child_enter(&wait_start); /* entering a child now */
3031# endif
3032
3033 /* Don't use local function variables, if called from a function.
3034 * Also starts profiling timer for nested script. */
3035 save_funccalp = save_funccal();
3036
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037 /*
3038 * Check if this script was sourced before to finds its SID.
3039 * If it's new, generate a new SID.
3040 */
3041 save_current_SID = current_SID;
3042# ifdef UNIX
3043 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3044# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003045 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3046 {
3047 si = &SCRIPT_ITEM(current_SID);
3048 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049 && (
3050# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003051 /* Compare dev/ino when possible, it catches symbolic
3052 * links. Also compare file names, the inode may change
3053 * when the file was edited. */
Bram Moolenaar05159a02005-02-26 23:04:13 +00003054 ((stat_ok && si->sn_dev != -1)
3055 && (si->sn_dev == st.st_dev
3056 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003058 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003060 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061 if (current_SID == 0)
3062 {
3063 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003064 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3065 == FAIL)
3066 goto almosttheend;
3067 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003069 ++script_items.ga_len;
3070 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3071# ifdef FEAT_PROFILE
3072 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003075 si = &SCRIPT_ITEM(current_SID);
3076 si->sn_name = fname_exp;
3077 fname_exp = NULL;
3078# ifdef UNIX
3079 if (stat_ok)
3080 {
3081 si->sn_dev = st.st_dev;
3082 si->sn_ino = st.st_ino;
3083 }
3084 else
3085 si->sn_dev = -1;
3086# endif
3087
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088 /* Allocate the local script variables to use for this script. */
3089 new_script_vars(current_SID);
3090 }
3091
Bram Moolenaar05159a02005-02-26 23:04:13 +00003092# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003093 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003094 {
3095 int forceit;
3096
3097 /* Check if we do profiling for this script. */
3098 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3099 {
3100 script_do_profile(si);
3101 si->sn_pr_force = forceit;
3102 }
3103 if (si->sn_prof_on)
3104 {
3105 ++si->sn_pr_count;
3106 profile_start(&si->sn_pr_start);
3107 profile_zero(&si->sn_pr_children);
3108 }
3109 }
3110# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003111#endif
3112
3113 /*
3114 * Call do_cmdline, which will call getsourceline() to get the lines.
3115 */
3116 do_cmdline(NULL, getsourceline, (void *)&cookie,
3117 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
3118
3119 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003120
3121#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003122 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003123 {
3124 /* Get "si" again, "script_items" may have been reallocated. */
3125 si = &SCRIPT_ITEM(current_SID);
3126 if (si->sn_prof_on)
3127 {
3128 profile_end(&si->sn_pr_start);
3129 profile_sub_wait(&wait_start, &si->sn_pr_start);
3130 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003131 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3132 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003133 }
3134 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135#endif
3136
3137 if (got_int)
3138 EMSG(_(e_interr));
3139 sourcing_name = save_sourcing_name;
3140 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141 if (p_verbose > 1)
3142 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003143 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003144 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003146 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003147 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148 }
3149#ifdef STARTUPTIME
Bram Moolenaar555b2802005-05-19 21:08:39 +00003150 vim_snprintf(IObuff, IOSIZE, "sourcing %s", fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151 time_msg(IObuff, &tv_start);
3152 time_pop(&tv_rel);
3153#endif
3154
3155#ifdef FEAT_EVAL
3156 /*
3157 * After a "finish" in debug mode, need to break at first command of next
3158 * sourced file.
3159 */
3160 if (save_debug_break_level > ex_nesting_level
3161 && debug_break_level == ex_nesting_level)
3162 ++debug_break_level;
3163#endif
3164
Bram Moolenaar05159a02005-02-26 23:04:13 +00003165#ifdef FEAT_EVAL
3166almosttheend:
3167 current_SID = save_current_SID;
3168 restore_funccal(save_funccalp);
3169# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003170 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003171 prof_child_exit(&wait_start); /* leaving a child now */
3172# endif
3173#endif
3174 fclose(cookie.fp);
3175 vim_free(cookie.nextline);
3176#ifdef FEAT_MBYTE
3177 convert_setup(&cookie.conv, NULL, NULL);
3178#endif
3179
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180theend:
3181 vim_free(fname_exp);
3182 return retval;
3183}
3184
3185#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003186
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187/*
3188 * ":scriptnames"
3189 */
3190/*ARGSUSED*/
3191 void
3192ex_scriptnames(eap)
3193 exarg_T *eap;
3194{
3195 int i;
3196
Bram Moolenaar05159a02005-02-26 23:04:13 +00003197 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3198 if (SCRIPT_ITEM(i).sn_name != NULL)
3199 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003200}
3201
3202# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3203/*
3204 * Fix slashes in the list of script names for 'shellslash'.
3205 */
3206 void
3207scriptnames_slash_adjust()
3208{
3209 int i;
3210
Bram Moolenaar05159a02005-02-26 23:04:13 +00003211 for (i = 1; i <= script_items.ga_len; ++i)
3212 if (SCRIPT_ITEM(i).sn_name != NULL)
3213 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214}
3215# endif
3216
3217/*
3218 * Get a pointer to a script name. Used for ":verbose set".
3219 */
3220 char_u *
3221get_scriptname(id)
3222 scid_T id;
3223{
3224 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003225 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003227 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003229 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003230 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003231 return (char_u *)_("environment variable");
3232 if (id == SID_ERROR)
3233 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003234 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003235}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003236
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003237# if defined(EXITFREE) || defined(PROTO)
3238 void
3239free_scriptnames()
3240{
3241 int i;
3242
3243 for (i = script_items.ga_len; i > 0; --i)
3244 vim_free(SCRIPT_ITEM(i).sn_name);
3245 ga_clear(&script_items);
3246}
3247# endif
3248
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249#endif
3250
3251#if defined(USE_CR) || defined(PROTO)
3252
3253# if defined(__MSL__) && (__MSL__ >= 22)
3254/*
3255 * Newer version of the Metrowerks library handle DOS and UNIX files
3256 * without help.
3257 * Test with earlier versions, MSL 2.2 is the library supplied with
3258 * Codewarrior Pro 2.
3259 */
3260 char *
3261fgets_cr(s, n, stream)
3262 char *s;
3263 int n;
3264 FILE *stream;
3265{
3266 return fgets(s, n, stream);
3267}
3268# else
3269/*
3270 * Version of fgets() which also works for lines ending in a <CR> only
3271 * (Macintosh format).
3272 * For older versions of the Metrowerks library.
3273 * At least CodeWarrior 9 needed this code.
3274 */
3275 char *
3276fgets_cr(s, n, stream)
3277 char *s;
3278 int n;
3279 FILE *stream;
3280{
3281 int c = 0;
3282 int char_read = 0;
3283
3284 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3285 {
3286 c = fgetc(stream);
3287 s[char_read++] = c;
3288 /* If the file is in DOS format, we need to skip a NL after a CR. I
3289 * thought it was the other way around, but this appears to work... */
3290 if (c == '\n')
3291 {
3292 c = fgetc(stream);
3293 if (c != '\r')
3294 ungetc(c, stream);
3295 }
3296 }
3297
3298 s[char_read] = 0;
3299 if (char_read == 0)
3300 return NULL;
3301
3302 if (feof(stream) && char_read == 1)
3303 return NULL;
3304
3305 return s;
3306}
3307# endif
3308#endif
3309
3310/*
3311 * Get one full line from a sourced file.
3312 * Called by do_cmdline() when it's called from do_source().
3313 *
3314 * Return a pointer to the line in allocated memory.
3315 * Return NULL for end-of-file or some error.
3316 */
3317/* ARGSUSED */
3318 char_u *
3319getsourceline(c, cookie, indent)
3320 int c; /* not used */
3321 void *cookie;
3322 int indent; /* not used */
3323{
3324 struct source_cookie *sp = (struct source_cookie *)cookie;
3325 char_u *line;
3326 char_u *p, *s;
3327
3328#ifdef FEAT_EVAL
3329 /* If breakpoints have been added/deleted need to check for it. */
3330 if (sp->dbg_tick < debug_tick)
3331 {
3332 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3333 sp->dbg_tick = debug_tick;
3334 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003335# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003336 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003337 script_line_end();
3338# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339#endif
3340 /*
3341 * Get current line. If there is a read-ahead line, use it, otherwise get
3342 * one now.
3343 */
3344 if (sp->finished)
3345 line = NULL;
3346 else if (sp->nextline == NULL)
3347 line = get_one_sourceline(sp);
3348 else
3349 {
3350 line = sp->nextline;
3351 sp->nextline = NULL;
3352 ++sourcing_lnum;
3353 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003354#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003355 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003356 script_line_start();
3357#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358
3359 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3360 * contain the 'C' flag. */
3361 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3362 {
3363 /* compensate for the one line read-ahead */
3364 --sourcing_lnum;
3365 for (;;)
3366 {
3367 sp->nextline = get_one_sourceline(sp);
3368 if (sp->nextline == NULL)
3369 break;
3370 p = skipwhite(sp->nextline);
3371 if (*p != '\\')
3372 break;
3373 s = alloc((int)(STRLEN(line) + STRLEN(p)));
3374 if (s == NULL) /* out of memory */
3375 break;
3376 STRCPY(s, line);
3377 STRCAT(s, p + 1);
3378 vim_free(line);
3379 line = s;
3380 vim_free(sp->nextline);
3381 }
3382 }
3383
3384#ifdef FEAT_MBYTE
3385 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3386 {
3387 /* Convert the encoding of the script line. */
3388 s = string_convert(&sp->conv, line, NULL);
3389 if (s != NULL)
3390 {
3391 vim_free(line);
3392 line = s;
3393 }
3394 }
3395#endif
3396
3397#ifdef FEAT_EVAL
3398 /* Did we encounter a breakpoint? */
3399 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3400 {
3401 dbg_breakpoint(sp->fname, sourcing_lnum);
3402 /* Find next breakpoint. */
3403 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3404 sp->dbg_tick = debug_tick;
3405 }
3406#endif
3407
3408 return line;
3409}
3410
3411 static char_u *
3412get_one_sourceline(sp)
3413 struct source_cookie *sp;
3414{
3415 garray_T ga;
3416 int len;
3417 int c;
3418 char_u *buf;
3419#ifdef USE_CRNL
3420 int has_cr; /* CR-LF found */
3421#endif
3422#ifdef USE_CR
3423 char_u *scan;
3424#endif
3425 int have_read = FALSE;
3426
3427 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003428 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429
3430 /*
3431 * Loop until there is a finished line (or end-of-file).
3432 */
3433 sourcing_lnum++;
3434 for (;;)
3435 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003436 /* make room to read at least 120 (more) characters */
3437 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438 break;
3439 buf = (char_u *)ga.ga_data;
3440
3441#ifdef USE_CR
3442 if (sp->fileformat == EOL_MAC)
3443 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003444 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3445 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003446 break;
3447 }
3448 else
3449#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003450 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3451 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003452 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003453 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454#ifdef USE_CRNL
3455 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3456 * CTRL-Z by its own, or after a NL. */
3457 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3458 && sp->fileformat == EOL_DOS
3459 && buf[len - 1] == Ctrl_Z)
3460 {
3461 buf[len - 1] = NUL;
3462 break;
3463 }
3464#endif
3465
3466#ifdef USE_CR
3467 /* If the read doesn't stop on a new line, and there's
3468 * some CR then we assume a Mac format */
3469 if (sp->fileformat == EOL_UNKNOWN)
3470 {
3471 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3472 sp->fileformat = EOL_MAC;
3473 else
3474 sp->fileformat = EOL_UNIX;
3475 }
3476
3477 if (sp->fileformat == EOL_MAC)
3478 {
3479 scan = vim_strchr(buf, '\r');
3480
3481 if (scan != NULL)
3482 {
3483 *scan = '\n';
3484 if (*(scan + 1) != 0)
3485 {
3486 *(scan + 1) = 0;
3487 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3488 }
3489 }
3490 len = STRLEN(buf);
3491 }
3492#endif
3493
3494 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003495 ga.ga_len = len;
3496
3497 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003498 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003499 continue;
3500
3501 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3502 {
3503#ifdef USE_CRNL
3504 has_cr = (len >= 2 && buf[len - 2] == '\r');
3505 if (sp->fileformat == EOL_UNKNOWN)
3506 {
3507 if (has_cr)
3508 sp->fileformat = EOL_DOS;
3509 else
3510 sp->fileformat = EOL_UNIX;
3511 }
3512
3513 if (sp->fileformat == EOL_DOS)
3514 {
3515 if (has_cr) /* replace trailing CR */
3516 {
3517 buf[len - 2] = '\n';
3518 --len;
3519 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520 }
3521 else /* lines like ":map xx yy^M" will have failed */
3522 {
3523 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003524 {
3525 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003527 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003528 sp->error = TRUE;
3529 sp->fileformat = EOL_UNIX;
3530 }
3531 }
3532#endif
3533 /* The '\n' is escaped if there is an odd number of ^V's just
3534 * before it, first set "c" just before the 'V's and then check
3535 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3536 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3537 ;
3538 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3539 {
3540 sourcing_lnum++;
3541 continue;
3542 }
3543
3544 buf[len - 1] = NUL; /* remove the NL */
3545 }
3546
3547 /*
3548 * Check for ^C here now and then, so recursive :so can be broken.
3549 */
3550 line_breakcheck();
3551 break;
3552 }
3553
3554 if (have_read)
3555 return (char_u *)ga.ga_data;
3556
3557 vim_free(ga.ga_data);
3558 return NULL;
3559}
3560
Bram Moolenaar05159a02005-02-26 23:04:13 +00003561#if defined(FEAT_PROFILE) || defined(PROTO)
3562/*
3563 * Called when starting to read a script line.
3564 * "sourcing_lnum" must be correct!
3565 * When skipping lines it may not actually be executed, but we won't find out
3566 * until later and we need to store the time now.
3567 */
3568 void
3569script_line_start()
3570{
3571 scriptitem_T *si;
3572 sn_prl_T *pp;
3573
3574 if (current_SID <= 0 || current_SID > script_items.ga_len)
3575 return;
3576 si = &SCRIPT_ITEM(current_SID);
3577 if (si->sn_prof_on && sourcing_lnum >= 1)
3578 {
3579 /* Grow the array before starting the timer, so that the time spend
3580 * here isn't counted. */
3581 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3582 si->sn_prl_idx = sourcing_lnum - 1;
3583 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3584 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3585 {
3586 /* Zero counters for a line that was not used before. */
3587 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3588 pp->snp_count = 0;
3589 profile_zero(&pp->sn_prl_total);
3590 profile_zero(&pp->sn_prl_self);
3591 ++si->sn_prl_ga.ga_len;
3592 }
3593 si->sn_prl_execed = FALSE;
3594 profile_start(&si->sn_prl_start);
3595 profile_zero(&si->sn_prl_children);
3596 profile_get_wait(&si->sn_prl_wait);
3597 }
3598}
3599
3600/*
3601 * Called when actually executing a function line.
3602 */
3603 void
3604script_line_exec()
3605{
3606 scriptitem_T *si;
3607
3608 if (current_SID <= 0 || current_SID > script_items.ga_len)
3609 return;
3610 si = &SCRIPT_ITEM(current_SID);
3611 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3612 si->sn_prl_execed = TRUE;
3613}
3614
3615/*
3616 * Called when done with a function line.
3617 */
3618 void
3619script_line_end()
3620{
3621 scriptitem_T *si;
3622 sn_prl_T *pp;
3623
3624 if (current_SID <= 0 || current_SID > script_items.ga_len)
3625 return;
3626 si = &SCRIPT_ITEM(current_SID);
3627 if (si->sn_prof_on && si->sn_prl_idx >= 0
3628 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3629 {
3630 if (si->sn_prl_execed)
3631 {
3632 pp = &PRL_ITEM(si, si->sn_prl_idx);
3633 ++pp->snp_count;
3634 profile_end(&si->sn_prl_start);
3635 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003636 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003637 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3638 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003639 }
3640 si->sn_prl_idx = -1;
3641 }
3642}
3643#endif
3644
Bram Moolenaar071d4272004-06-13 20:20:40 +00003645/*
3646 * ":scriptencoding": Set encoding conversion for a sourced script.
3647 * Without the multi-byte feature it's simply ignored.
3648 */
3649/*ARGSUSED*/
3650 void
3651ex_scriptencoding(eap)
3652 exarg_T *eap;
3653{
3654#ifdef FEAT_MBYTE
3655 struct source_cookie *sp;
3656 char_u *name;
3657
3658 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3659 {
3660 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3661 return;
3662 }
3663
3664 if (*eap->arg != NUL)
3665 {
3666 name = enc_canonize(eap->arg);
3667 if (name == NULL) /* out of memory */
3668 return;
3669 }
3670 else
3671 name = eap->arg;
3672
3673 /* Setup for conversion from the specified encoding to 'encoding'. */
3674 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3675 convert_setup(&sp->conv, name, p_enc);
3676
3677 if (name != eap->arg)
3678 vim_free(name);
3679#endif
3680}
3681
3682#if defined(FEAT_EVAL) || defined(PROTO)
3683/*
3684 * ":finish": Mark a sourced file as finished.
3685 */
3686 void
3687ex_finish(eap)
3688 exarg_T *eap;
3689{
3690 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3691 do_finish(eap, FALSE);
3692 else
3693 EMSG(_("E168: :finish used outside of a sourced file"));
3694}
3695
3696/*
3697 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3698 * Also called for a pending finish at the ":endtry" or after returning from
3699 * an extra do_cmdline(). "reanimate" is used in the latter case.
3700 */
3701 void
3702do_finish(eap, reanimate)
3703 exarg_T *eap;
3704 int reanimate;
3705{
3706 int idx;
3707
3708 if (reanimate)
3709 ((struct source_cookie *)getline_cookie(eap->getline,
3710 eap->cookie))->finished = FALSE;
3711
3712 /*
3713 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3714 * not in its finally clause (which then is to be executed next) is found.
3715 * In this case, make the ":finish" pending for execution at the ":endtry".
3716 * Otherwise, finish normally.
3717 */
3718 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3719 if (idx >= 0)
3720 {
3721 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3722 report_make_pending(CSTP_FINISH, NULL);
3723 }
3724 else
3725 ((struct source_cookie *)getline_cookie(eap->getline,
3726 eap->cookie))->finished = TRUE;
3727}
3728
3729
3730/*
3731 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3732 * message for missing ":endif".
3733 * Return FALSE when not sourcing a file.
3734 */
3735 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003736source_finished(fgetline, cookie)
3737 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003738 void *cookie;
3739{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003740 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003742 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743}
3744#endif
3745
3746#if defined(FEAT_LISTCMDS) || defined(PROTO)
3747/*
3748 * ":checktime [buffer]"
3749 */
3750 void
3751ex_checktime(eap)
3752 exarg_T *eap;
3753{
3754 buf_T *buf;
3755 int save_no_check_timestamps = no_check_timestamps;
3756
3757 no_check_timestamps = 0;
3758 if (eap->addr_count == 0) /* default is all buffers */
3759 check_timestamps(FALSE);
3760 else
3761 {
3762 buf = buflist_findnr((int)eap->line2);
3763 if (buf != NULL) /* cannot happen? */
3764 (void)buf_check_timestamp(buf, FALSE);
3765 }
3766 no_check_timestamps = save_no_check_timestamps;
3767}
3768#endif
3769
Bram Moolenaar071d4272004-06-13 20:20:40 +00003770#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3771 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3772static char *get_locale_val __ARGS((int what));
3773
3774 static char *
3775get_locale_val(what)
3776 int what;
3777{
3778 char *loc;
3779
3780 /* Obtain the locale value from the libraries. For DJGPP this is
3781 * redefined and it doesn't use the arguments. */
3782 loc = setlocale(what, NULL);
3783
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003784# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003785 if (loc != NULL)
3786 {
3787 char_u *p;
3788
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003789 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3790 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003791 p = vim_strchr(loc, '=');
3792 if (p != NULL)
3793 {
3794 loc = ++p;
3795 while (*p != NUL) /* remove trailing newline */
3796 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003797 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798 {
3799 *p = NUL;
3800 break;
3801 }
3802 ++p;
3803 }
3804 }
3805 }
3806# endif
3807
3808 return loc;
3809}
3810#endif
3811
3812
3813#ifdef WIN32
3814/*
3815 * On MS-Windows locale names are strings like "German_Germany.1252", but
3816 * gettext expects "de". Try to translate one into another here for a few
3817 * supported languages.
3818 */
3819 static char_u *
3820gettext_lang(char_u *name)
3821{
3822 int i;
3823 static char *(mtable[]) = {
3824 "afrikaans", "af",
3825 "czech", "cs",
3826 "dutch", "nl",
3827 "german", "de",
3828 "english_united kingdom", "en_GB",
3829 "spanish", "es",
3830 "french", "fr",
3831 "italian", "it",
3832 "japanese", "ja",
3833 "korean", "ko",
3834 "norwegian", "no",
3835 "polish", "pl",
3836 "russian", "ru",
3837 "slovak", "sk",
3838 "swedish", "sv",
3839 "ukrainian", "uk",
3840 "chinese_china", "zh_CN",
3841 "chinese_taiwan", "zh_TW",
3842 NULL};
3843
3844 for (i = 0; mtable[i] != NULL; i += 2)
3845 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3846 return mtable[i + 1];
3847 return name;
3848}
3849#endif
3850
3851#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3852/*
3853 * Obtain the current messages language. Used to set the default for
3854 * 'helplang'. May return NULL or an empty string.
3855 */
3856 char_u *
3857get_mess_lang()
3858{
3859 char_u *p;
3860
3861# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3862# if defined(LC_MESSAGES)
3863 p = (char_u *)get_locale_val(LC_MESSAGES);
3864# else
3865 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003866 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3867 * and LC_MONETARY may be set differently for a Japanese working in the
3868 * US. */
3869 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003870# endif
3871# else
3872 p = mch_getenv((char_u *)"LC_ALL");
3873 if (p == NULL || *p == NUL)
3874 {
3875 p = mch_getenv((char_u *)"LC_MESSAGES");
3876 if (p == NULL || *p == NUL)
3877 p = mch_getenv((char_u *)"LANG");
3878 }
3879# endif
3880# ifdef WIN32
3881 p = gettext_lang(p);
3882# endif
3883 return p;
3884}
3885#endif
3886
Bram Moolenaardef9e822004-12-31 20:58:58 +00003887/* Complicated #if; matches with where get_mess_env() is used below. */
3888#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3889 && defined(LC_MESSAGES))) \
3890 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3891 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3892 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893static char_u *get_mess_env __ARGS((void));
3894
3895/*
3896 * Get the language used for messages from the environment.
3897 */
3898 static char_u *
3899get_mess_env()
3900{
3901 char_u *p;
3902
3903 p = mch_getenv((char_u *)"LC_ALL");
3904 if (p == NULL || *p == NUL)
3905 {
3906 p = mch_getenv((char_u *)"LC_MESSAGES");
3907 if (p == NULL || *p == NUL)
3908 {
3909 p = mch_getenv((char_u *)"LANG");
3910 if (p != NULL && VIM_ISDIGIT(*p))
3911 p = NULL; /* ignore something like "1043" */
3912# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3913 if (p == NULL || *p == NUL)
3914 p = (char_u *)get_locale_val(LC_CTYPE);
3915# endif
3916 }
3917 }
3918 return p;
3919}
3920#endif
3921
3922#if defined(FEAT_EVAL) || defined(PROTO)
3923
3924/*
3925 * Set the "v:lang" variable according to the current locale setting.
3926 * Also do "v:lc_time"and "v:ctype".
3927 */
3928 void
3929set_lang_var()
3930{
3931 char_u *loc;
3932
3933# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3934 loc = (char_u *)get_locale_val(LC_CTYPE);
3935# else
3936 /* setlocale() not supported: use the default value */
3937 loc = (char_u *)"C";
3938# endif
3939 set_vim_var_string(VV_CTYPE, loc, -1);
3940
3941 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3942 * back to LC_CTYPE if it's empty. */
3943# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
3944 loc = (char_u *)get_locale_val(LC_MESSAGES);
3945# else
3946 loc = get_mess_env();
3947# endif
3948 set_vim_var_string(VV_LANG, loc, -1);
3949
3950# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3951 loc = (char_u *)get_locale_val(LC_TIME);
3952# endif
3953 set_vim_var_string(VV_LC_TIME, loc, -1);
3954}
3955#endif
3956
3957#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3958 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
3959/*
3960 * ":language": Set the language (locale).
3961 */
3962 void
3963ex_language(eap)
3964 exarg_T *eap;
3965{
3966 char *loc;
3967 char_u *p;
3968 char_u *name;
3969 int what = LC_ALL;
3970 char *whatstr = "";
3971#ifdef LC_MESSAGES
3972# define VIM_LC_MESSAGES LC_MESSAGES
3973#else
3974# define VIM_LC_MESSAGES 6789
3975#endif
3976
3977 name = eap->arg;
3978
3979 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3980 * Allow abbreviation, but require at least 3 characters to avoid
3981 * confusion with a two letter language name "me" or "ct". */
3982 p = skiptowhite(eap->arg);
3983 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
3984 {
3985 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3986 {
3987 what = VIM_LC_MESSAGES;
3988 name = skipwhite(p);
3989 whatstr = "messages ";
3990 }
3991 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3992 {
3993 what = LC_CTYPE;
3994 name = skipwhite(p);
3995 whatstr = "ctype ";
3996 }
3997 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
3998 {
3999 what = LC_TIME;
4000 name = skipwhite(p);
4001 whatstr = "time ";
4002 }
4003 }
4004
4005 if (*name == NUL)
4006 {
4007#ifndef LC_MESSAGES
4008 if (what == VIM_LC_MESSAGES)
4009 p = get_mess_env();
4010 else
4011#endif
4012 p = (char_u *)setlocale(what, NULL);
4013 if (p == NULL || *p == NUL)
4014 p = (char_u *)"Unknown";
4015 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4016 }
4017 else
4018 {
4019#ifndef LC_MESSAGES
4020 if (what == VIM_LC_MESSAGES)
4021 loc = "";
4022 else
4023#endif
4024 loc = setlocale(what, (char *)name);
4025 if (loc == NULL)
4026 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4027 else
4028 {
4029#ifdef HAVE_NL_MSG_CAT_CNTR
4030 /* Need to do this for GNU gettext, otherwise cached translations
4031 * will be used again. */
4032 extern int _nl_msg_cat_cntr;
4033
4034 ++_nl_msg_cat_cntr;
4035#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004036 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004037 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4038
4039 if (what != LC_TIME)
4040 {
4041 /* Tell gettext() what to translate to. It apparently doesn't
4042 * use the currently effective locale. Also do this when
4043 * FEAT_GETTEXT isn't defined, so that shell commands use this
4044 * value. */
4045 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004046 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004047 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004048# ifdef WIN32
4049 /* Apparently MS-Windows printf() may cause a crash when
4050 * we give it 8-bit text while it's expecting text in the
4051 * current locale. This call avoids that. */
4052 setlocale(LC_CTYPE, "C");
4053# endif
4054 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004055 if (what != LC_CTYPE)
4056 {
4057 char_u *mname;
4058#ifdef WIN32
4059 mname = gettext_lang(name);
4060#else
4061 mname = name;
4062#endif
4063 vim_setenv((char_u *)"LC_MESSAGES", mname);
4064#ifdef FEAT_MULTI_LANG
4065 set_helplang_default(mname);
4066#endif
4067 }
4068
4069 /* Set $LC_CTYPE, because it overrules $LANG, and
4070 * gtk_set_locale() calls setlocale() again. gnome_init()
4071 * sets $LC_CTYPE to "en_US" (that's a bug!). */
4072 if (what != VIM_LC_MESSAGES)
4073 vim_setenv((char_u *)"LC_CTYPE", name);
4074# ifdef FEAT_GUI_GTK
4075 /* Let GTK know what locale we're using. Not sure this is
4076 * really needed... */
4077 if (gui.in_use)
4078 (void)gtk_set_locale();
4079# endif
4080 }
4081
4082# ifdef FEAT_EVAL
4083 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4084 set_lang_var();
4085# endif
4086 }
4087 }
4088}
4089
4090# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4091/*
4092 * Function given to ExpandGeneric() to obtain the possible arguments of the
4093 * ":language" command.
4094 */
4095/*ARGSUSED*/
4096 char_u *
4097get_lang_arg(xp, idx)
4098 expand_T *xp;
4099 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