blob: 884220ef35e0736e2f682936ad51b825a7821c0b [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;
97 int save_ignore_script;
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);
898#endif
899 return buf;
900}
901
902# endif /* FEAT_PROFILE || FEAT_RELTIME */
903
904# if defined(FEAT_PROFILE) || defined(PROTO)
905/*
906 * Functions for profiling.
907 */
908static void script_do_profile __ARGS((scriptitem_T *si));
909static void script_dump_profile __ARGS((FILE *fd));
910static proftime_T prof_wait_time;
911
912/*
913 * Set the time in "tm" to zero.
914 */
915 void
916profile_zero(tm)
917 proftime_T *tm;
918{
919# ifdef WIN3264
920 tm->QuadPart = 0;
921# else
922 tm->tv_usec = 0;
923 tm->tv_sec = 0;
924# endif
925}
926
927/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000928 * Add the time "tm2" to "tm".
929 */
930 void
931profile_add(tm, tm2)
932 proftime_T *tm, *tm2;
933{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000934# ifdef WIN3264
935 tm->QuadPart += tm2->QuadPart;
936# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000937 tm->tv_usec += tm2->tv_usec;
938 tm->tv_sec += tm2->tv_sec;
939 if (tm->tv_usec >= 1000000)
940 {
941 tm->tv_usec -= 1000000;
942 ++tm->tv_sec;
943 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000944# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000945}
946
947/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000948 * Add the "self" time from the total time and the children's time.
949 */
950 void
951profile_self(self, total, children)
952 proftime_T *self, *total, *children;
953{
954 /* Check that the result won't be negative. Can happen with recursive
955 * calls. */
956#ifdef WIN3264
957 if (total->QuadPart <= children->QuadPart)
958 return;
959#else
960 if (total->tv_sec < children->tv_sec
961 || (total->tv_sec == children->tv_sec
962 && total->tv_usec <= children->tv_usec))
963 return;
964#endif
965 profile_add(self, total);
966 profile_sub(self, children);
967}
968
969/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000970 * Get the current waittime.
971 */
972 void
973profile_get_wait(tm)
974 proftime_T *tm;
975{
976 *tm = prof_wait_time;
977}
978
979/*
980 * Subtract the passed waittime since "tm" from "tma".
981 */
982 void
983profile_sub_wait(tm, tma)
984 proftime_T *tm, *tma;
985{
986 proftime_T tm3 = prof_wait_time;
987
988 profile_sub(&tm3, tm);
989 profile_sub(tma, &tm3);
990}
991
992/*
993 * Return TRUE if "tm1" and "tm2" are equal.
994 */
995 int
996profile_equal(tm1, tm2)
997 proftime_T *tm1, *tm2;
998{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000999# ifdef WIN3264
1000 return (tm1->QuadPart == tm2->QuadPart);
1001# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001002 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001003# endif
1004}
1005
1006/*
1007 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1008 */
1009 int
1010profile_cmp(tm1, tm2)
1011 proftime_T *tm1, *tm2;
1012{
1013# ifdef WIN3264
1014 return (int)(tm2->QuadPart - tm1->QuadPart);
1015# else
1016 if (tm1->tv_sec == tm2->tv_sec)
1017 return tm2->tv_usec - tm1->tv_usec;
1018 return tm2->tv_sec - tm1->tv_sec;
1019# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001020}
1021
Bram Moolenaar05159a02005-02-26 23:04:13 +00001022static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001023static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001024
1025/*
1026 * ":profile cmd args"
1027 */
1028 void
1029ex_profile(eap)
1030 exarg_T *eap;
1031{
1032 char_u *e;
1033 int len;
1034
1035 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001036 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001037 e = skipwhite(e);
1038
1039 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1040 {
1041 vim_free(profile_fname);
1042 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001043 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001044 profile_zero(&prof_wait_time);
1045 set_vim_var_nr(VV_PROFILING, 1L);
1046 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001047 else if (do_profiling == PROF_NONE)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001048 EMSG(_("E750: First use :profile start <fname>"));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001049 else if (STRCMP(eap->arg, "pause") == 0)
1050 {
1051 if (do_profiling == PROF_YES)
1052 profile_start(&pause_time);
1053 do_profiling = PROF_PAUSED;
1054 }
1055 else if (STRCMP(eap->arg, "continue") == 0)
1056 {
1057 if (do_profiling == PROF_PAUSED)
1058 {
1059 profile_end(&pause_time);
1060 profile_add(&prof_wait_time, &pause_time);
1061 }
1062 do_profiling = PROF_YES;
1063 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001064 else
1065 {
1066 /* The rest is similar to ":breakadd". */
1067 ex_breakadd(eap);
1068 }
1069}
1070
1071/*
1072 * Dump the profiling info.
1073 */
1074 void
1075profile_dump()
1076{
1077 FILE *fd;
1078
1079 if (profile_fname != NULL)
1080 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001081 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001082 if (fd == NULL)
1083 EMSG2(_(e_notopen), profile_fname);
1084 else
1085 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001086 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001087 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001088 fclose(fd);
1089 }
1090 }
1091}
1092
1093/*
1094 * Start profiling script "fp".
1095 */
1096 static void
1097script_do_profile(si)
1098 scriptitem_T *si;
1099{
1100 si->sn_pr_count = 0;
1101 profile_zero(&si->sn_pr_total);
1102 profile_zero(&si->sn_pr_self);
1103
1104 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1105 si->sn_prl_idx = -1;
1106 si->sn_prof_on = TRUE;
1107 si->sn_pr_nest = 0;
1108}
1109
1110/*
1111 * save time when starting to invoke another script or function.
1112 */
1113 void
1114script_prof_save(tm)
1115 proftime_T *tm; /* place to store wait time */
1116{
1117 scriptitem_T *si;
1118
1119 if (current_SID > 0 && current_SID <= script_items.ga_len)
1120 {
1121 si = &SCRIPT_ITEM(current_SID);
1122 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1123 profile_start(&si->sn_pr_child);
1124 }
1125 profile_get_wait(tm);
1126}
1127
1128/*
1129 * Count time spent in children after invoking another script or function.
1130 */
1131 void
1132script_prof_restore(tm)
1133 proftime_T *tm;
1134{
1135 scriptitem_T *si;
1136
1137 if (current_SID > 0 && current_SID <= script_items.ga_len)
1138 {
1139 si = &SCRIPT_ITEM(current_SID);
1140 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1141 {
1142 profile_end(&si->sn_pr_child);
1143 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1144 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1145 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1146 }
1147 }
1148}
1149
1150static proftime_T inchar_time;
1151
1152/*
1153 * Called when starting to wait for the user to type a character.
1154 */
1155 void
1156prof_inchar_enter()
1157{
1158 profile_start(&inchar_time);
1159}
1160
1161/*
1162 * Called when finished waiting for the user to type a character.
1163 */
1164 void
1165prof_inchar_exit()
1166{
1167 profile_end(&inchar_time);
1168 profile_add(&prof_wait_time, &inchar_time);
1169}
1170
1171/*
1172 * Dump the profiling results for all scripts in file "fd".
1173 */
1174 static void
1175script_dump_profile(fd)
1176 FILE *fd;
1177{
1178 int id;
1179 scriptitem_T *si;
1180 int i;
1181 FILE *sfd;
1182 sn_prl_T *pp;
1183
1184 for (id = 1; id <= script_items.ga_len; ++id)
1185 {
1186 si = &SCRIPT_ITEM(id);
1187 if (si->sn_prof_on)
1188 {
1189 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1190 if (si->sn_pr_count == 1)
1191 fprintf(fd, "Sourced 1 time\n");
1192 else
1193 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1194 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1195 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1196 fprintf(fd, "\n");
1197 fprintf(fd, "count total (s) self (s)\n");
1198
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001199 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001200 if (sfd == NULL)
1201 fprintf(fd, "Cannot open file!\n");
1202 else
1203 {
1204 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1205 {
1206 if (vim_fgets(IObuff, IOSIZE, sfd))
1207 break;
1208 pp = &PRL_ITEM(si, i);
1209 if (pp->snp_count > 0)
1210 {
1211 fprintf(fd, "%5d ", pp->snp_count);
1212 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1213 fprintf(fd, " ");
1214 else
1215 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1216 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1217 }
1218 else
1219 fprintf(fd, " ");
1220 fprintf(fd, "%s", IObuff);
1221 }
1222 fclose(sfd);
1223 }
1224 fprintf(fd, "\n");
1225 }
1226 }
1227}
1228
1229/*
1230 * Return TRUE when a function defined in the current script should be
1231 * profiled.
1232 */
1233 int
1234prof_def_func()
1235{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001236 if (current_SID > 0)
1237 return SCRIPT_ITEM(current_SID).sn_pr_force;
1238 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001239}
1240
1241# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242#endif
1243
1244/*
1245 * If 'autowrite' option set, try to write the file.
1246 * Careful: autocommands may make "buf" invalid!
1247 *
1248 * return FAIL for failure, OK otherwise
1249 */
1250 int
1251autowrite(buf, forceit)
1252 buf_T *buf;
1253 int forceit;
1254{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001255 int r;
1256
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257 if (!(p_aw || p_awa) || !p_write
1258#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001259 /* never autowrite a "nofile" or "nowrite" buffer */
1260 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001261#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001262 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001263 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001264 r = buf_write_all(buf, forceit);
1265
1266 /* Writing may succeed but the buffer still changed, e.g., when there is a
1267 * conversion error. We do want to return FAIL then. */
1268 if (buf_valid(buf) && bufIsChanged(buf))
1269 r = FAIL;
1270 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271}
1272
1273/*
1274 * flush all buffers, except the ones that are readonly
1275 */
1276 void
1277autowrite_all()
1278{
1279 buf_T *buf;
1280
1281 if (!(p_aw || p_awa) || !p_write)
1282 return;
1283 for (buf = firstbuf; buf; buf = buf->b_next)
1284 if (bufIsChanged(buf) && !buf->b_p_ro)
1285 {
1286 (void)buf_write_all(buf, FALSE);
1287#ifdef FEAT_AUTOCMD
1288 /* an autocommand may have deleted the buffer */
1289 if (!buf_valid(buf))
1290 buf = firstbuf;
1291#endif
1292 }
1293}
1294
1295/*
1296 * return TRUE if buffer was changed and cannot be abandoned.
1297 */
1298/*ARGSUSED*/
1299 int
1300check_changed(buf, checkaw, mult_win, forceit, allbuf)
1301 buf_T *buf;
1302 int checkaw; /* do autowrite if buffer was changed */
1303 int mult_win; /* check also when several wins for the buf */
1304 int forceit;
1305 int allbuf; /* may write all buffers */
1306{
1307 if ( !forceit
1308 && bufIsChanged(buf)
1309 && (mult_win || buf->b_nwindows <= 1)
1310 && (!checkaw || autowrite(buf, forceit) == FAIL))
1311 {
1312#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1313 if ((p_confirm || cmdmod.confirm) && p_write)
1314 {
1315 buf_T *buf2;
1316 int count = 0;
1317
1318 if (allbuf)
1319 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1320 if (bufIsChanged(buf2)
1321 && (buf2->b_ffname != NULL
1322# ifdef FEAT_BROWSE
1323 || cmdmod.browse
1324# endif
1325 ))
1326 ++count;
1327# ifdef FEAT_AUTOCMD
1328 if (!buf_valid(buf))
1329 /* Autocommand deleted buffer, oops! It's not changed now. */
1330 return FALSE;
1331# endif
1332 dialog_changed(buf, count > 1);
1333# ifdef FEAT_AUTOCMD
1334 if (!buf_valid(buf))
1335 /* Autocommand deleted buffer, oops! It's not changed now. */
1336 return FALSE;
1337# endif
1338 return bufIsChanged(buf);
1339 }
1340#endif
1341 EMSG(_(e_nowrtmsg));
1342 return TRUE;
1343 }
1344 return FALSE;
1345}
1346
1347#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1348
1349#if defined(FEAT_BROWSE) || defined(PROTO)
1350/*
1351 * When wanting to write a file without a file name, ask the user for a name.
1352 */
1353 void
1354browse_save_fname(buf)
1355 buf_T *buf;
1356{
1357 if (buf->b_fname == NULL)
1358 {
1359 char_u *fname;
1360
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001361 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1362 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001363 if (fname != NULL)
1364 {
1365 if (setfname(buf, fname, NULL, TRUE) == OK)
1366 buf->b_flags |= BF_NOTEDITED;
1367 vim_free(fname);
1368 }
1369 }
1370}
1371#endif
1372
1373/*
1374 * Ask the user what to do when abondoning a changed buffer.
1375 * Must check 'write' option first!
1376 */
1377 void
1378dialog_changed(buf, checkall)
1379 buf_T *buf;
1380 int checkall; /* may abandon all changed buffers */
1381{
1382 char_u buff[IOSIZE];
1383 int ret;
1384 buf_T *buf2;
1385
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001386 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001387 (buf->b_fname != NULL) ?
1388 buf->b_fname : (char_u *)_("Untitled"));
1389 if (checkall)
1390 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1391 else
1392 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1393
1394 if (ret == VIM_YES)
1395 {
1396#ifdef FEAT_BROWSE
1397 /* May get file name, when there is none */
1398 browse_save_fname(buf);
1399#endif
1400 if (buf->b_fname != NULL) /* didn't hit Cancel */
1401 (void)buf_write_all(buf, FALSE);
1402 }
1403 else if (ret == VIM_NO)
1404 {
1405 unchanged(buf, TRUE);
1406 }
1407 else if (ret == VIM_ALL)
1408 {
1409 /*
1410 * Write all modified files that can be written.
1411 * Skip readonly buffers, these need to be confirmed
1412 * individually.
1413 */
1414 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1415 {
1416 if (bufIsChanged(buf2)
1417 && (buf2->b_ffname != NULL
1418#ifdef FEAT_BROWSE
1419 || cmdmod.browse
1420#endif
1421 )
1422 && !buf2->b_p_ro)
1423 {
1424#ifdef FEAT_BROWSE
1425 /* May get file name, when there is none */
1426 browse_save_fname(buf2);
1427#endif
1428 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1429 (void)buf_write_all(buf2, FALSE);
1430#ifdef FEAT_AUTOCMD
1431 /* an autocommand may have deleted the buffer */
1432 if (!buf_valid(buf2))
1433 buf2 = firstbuf;
1434#endif
1435 }
1436 }
1437 }
1438 else if (ret == VIM_DISCARDALL)
1439 {
1440 /*
1441 * mark all buffers as unchanged
1442 */
1443 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1444 unchanged(buf2, TRUE);
1445 }
1446}
1447#endif
1448
1449/*
1450 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1451 * hidden, autowriting it or unloading it.
1452 */
1453 int
1454can_abandon(buf, forceit)
1455 buf_T *buf;
1456 int forceit;
1457{
1458 return ( P_HID(buf)
1459 || !bufIsChanged(buf)
1460 || buf->b_nwindows > 1
1461 || autowrite(buf, forceit) == OK
1462 || forceit);
1463}
1464
1465/*
1466 * Return TRUE if any buffer was changed and cannot be abandoned.
1467 * That changed buffer becomes the current buffer.
1468 */
1469 int
1470check_changed_any(hidden)
1471 int hidden; /* Only check hidden buffers */
1472{
1473 buf_T *buf;
1474 int save;
1475#ifdef FEAT_WINDOWS
1476 win_T *wp;
1477#endif
1478
1479 for (;;)
1480 {
1481 /* check curbuf first: if it was changed we can't abandon it */
1482 if (!hidden && curbufIsChanged())
1483 buf = curbuf;
1484 else
1485 {
1486 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1487 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1488 break;
1489 }
1490 if (buf == NULL) /* No buffers changed */
1491 return FALSE;
1492
Bram Moolenaar373154b2007-02-13 05:19:30 +00001493 /* Try auto-writing the buffer. If this fails but the buffer no
1494 * longer exists it's not changed, that's OK. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001495 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1496 break; /* didn't save - still changes */
1497 }
1498
1499 exiting = FALSE;
1500#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1501 /*
1502 * When ":confirm" used, don't give an error message.
1503 */
1504 if (!(p_confirm || cmdmod.confirm))
1505#endif
1506 {
1507 /* There must be a wait_return for this message, do_buffer()
1508 * may cause a redraw. But wait_return() is a no-op when vgetc()
1509 * is busy (Quit used from window menu), then make sure we don't
1510 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001511 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001512 {
1513 msg_row = cmdline_row;
1514 msg_col = 0;
1515 msg_didout = FALSE;
1516 }
1517 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1518 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1519 buf->b_fname))
1520 {
1521 save = no_wait_return;
1522 no_wait_return = FALSE;
1523 wait_return(FALSE);
1524 no_wait_return = save;
1525 }
1526 }
1527
1528#ifdef FEAT_WINDOWS
1529 /* Try to find a window that contains the buffer. */
1530 if (buf != curbuf)
1531 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1532 if (wp->w_buffer == buf)
1533 {
1534 win_goto(wp);
1535# ifdef FEAT_AUTOCMD
1536 /* Paranoia: did autocms wipe out the buffer with changes? */
1537 if (!buf_valid(buf))
1538 return TRUE;
1539# endif
1540 break;
1541 }
1542#endif
1543
1544 /* Open the changed buffer in the current window. */
1545 if (buf != curbuf)
1546 set_curbuf(buf, DOBUF_GOTO);
1547
1548 return TRUE;
1549}
1550
1551/*
1552 * return FAIL if there is no file name, OK if there is one
1553 * give error message for FAIL
1554 */
1555 int
1556check_fname()
1557{
1558 if (curbuf->b_ffname == NULL)
1559 {
1560 EMSG(_(e_noname));
1561 return FAIL;
1562 }
1563 return OK;
1564}
1565
1566/*
1567 * flush the contents of a buffer, unless it has no file name
1568 *
1569 * return FAIL for failure, OK otherwise
1570 */
1571 int
1572buf_write_all(buf, forceit)
1573 buf_T *buf;
1574 int forceit;
1575{
1576 int retval;
1577#ifdef FEAT_AUTOCMD
1578 buf_T *old_curbuf = curbuf;
1579#endif
1580
1581 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1582 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1583 FALSE, forceit, TRUE, FALSE));
1584#ifdef FEAT_AUTOCMD
1585 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001586 {
1587 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001590#endif
1591 return retval;
1592}
1593
1594/*
1595 * Code to handle the argument list.
1596 */
1597
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001598static char_u *do_one_arg __ARGS((char_u *str));
1599static int do_arglist __ARGS((char_u *str, int what, int after));
1600static void alist_check_arg_idx __ARGS((void));
1601static int editing_arg_idx __ARGS((win_T *win));
1602#ifdef FEAT_LISTCMDS
1603static int alist_add_list __ARGS((int count, char_u **files, int after));
1604#endif
1605#define AL_SET 1
1606#define AL_ADD 2
1607#define AL_DEL 3
1608
Bram Moolenaar071d4272004-06-13 20:20:40 +00001609/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001610 * Isolate one argument, taking backticks.
1611 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001612 * Return a pointer to the start of the next argument.
1613 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001614 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615do_one_arg(str)
1616 char_u *str;
1617{
1618 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001619 int inbacktick;
1620
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621 inbacktick = FALSE;
1622 for (p = str; *str; ++str)
1623 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001624 /* When the backslash is used for escaping the special meaning of a
1625 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001626 if (rem_backslash(str))
1627 {
1628 *p++ = *str++;
1629 *p++ = *str;
1630 }
1631 else
1632 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001633 /* An item ends at a space not in backticks */
1634 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001635 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001636 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001637 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001638 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639 }
1640 }
1641 str = skipwhite(str);
1642 *p = NUL;
1643
1644 return str;
1645}
1646
Bram Moolenaar86b68352004-12-27 21:59:20 +00001647/*
1648 * Separate the arguments in "str" and return a list of pointers in the
1649 * growarray "gap".
1650 */
1651 int
1652get_arglist(gap, str)
1653 garray_T *gap;
1654 char_u *str;
1655{
1656 ga_init2(gap, (int)sizeof(char_u *), 20);
1657 while (*str != NUL)
1658 {
1659 if (ga_grow(gap, 1) == FAIL)
1660 {
1661 ga_clear(gap);
1662 return FAIL;
1663 }
1664 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1665
1666 /* Isolate one argument, change it in-place, put a NUL after it. */
1667 str = do_one_arg(str);
1668 }
1669 return OK;
1670}
1671
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001672#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001673/*
1674 * Parse a list of arguments (file names), expand them and return in
1675 * "fnames[fcountp]".
1676 * Return FAIL or OK.
1677 */
1678 int
1679get_arglist_exp(str, fcountp, fnamesp)
1680 char_u *str;
1681 int *fcountp;
1682 char_u ***fnamesp;
1683{
1684 garray_T ga;
1685 int i;
1686
1687 if (get_arglist(&ga, str) == FAIL)
1688 return FAIL;
1689 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1690 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1691 ga_clear(&ga);
1692 return i;
1693}
1694#endif
1695
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1697/*
1698 * Redefine the argument list.
1699 */
1700 void
1701set_arglist(str)
1702 char_u *str;
1703{
1704 do_arglist(str, AL_SET, 0);
1705}
1706#endif
1707
1708/*
1709 * "what" == AL_SET: Redefine the argument list to 'str'.
1710 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1711 * "what" == AL_DEL: remove files in 'str' from the argument list.
1712 *
1713 * Return FAIL for failure, OK otherwise.
1714 */
1715/*ARGSUSED*/
1716 static int
1717do_arglist(str, what, after)
1718 char_u *str;
1719 int what;
1720 int after; /* 0 means before first one */
1721{
1722 garray_T new_ga;
1723 int exp_count;
1724 char_u **exp_files;
1725 int i;
1726#ifdef FEAT_LISTCMDS
1727 char_u *p;
1728 int match;
1729#endif
1730
1731 /*
1732 * Collect all file name arguments in "new_ga".
1733 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001734 if (get_arglist(&new_ga, str) == FAIL)
1735 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001736
1737#ifdef FEAT_LISTCMDS
1738 if (what == AL_DEL)
1739 {
1740 regmatch_T regmatch;
1741 int didone;
1742
1743 /*
1744 * Delete the items: use each item as a regexp and find a match in the
1745 * argument list.
1746 */
1747#ifdef CASE_INSENSITIVE_FILENAME
1748 regmatch.rm_ic = TRUE; /* Always ignore case */
1749#else
1750 regmatch.rm_ic = FALSE; /* Never ignore case */
1751#endif
1752 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1753 {
1754 p = ((char_u **)new_ga.ga_data)[i];
1755 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1756 if (p == NULL)
1757 break;
1758 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1759 if (regmatch.regprog == NULL)
1760 {
1761 vim_free(p);
1762 break;
1763 }
1764
1765 didone = FALSE;
1766 for (match = 0; match < ARGCOUNT; ++match)
1767 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1768 (colnr_T)0))
1769 {
1770 didone = TRUE;
1771 vim_free(ARGLIST[match].ae_fname);
1772 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1773 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1774 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775 if (curwin->w_arg_idx > match)
1776 --curwin->w_arg_idx;
1777 --match;
1778 }
1779
1780 vim_free(regmatch.regprog);
1781 vim_free(p);
1782 if (!didone)
1783 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1784 }
1785 ga_clear(&new_ga);
1786 }
1787 else
1788#endif
1789 {
1790 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1791 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1792 ga_clear(&new_ga);
1793 if (i == FAIL)
1794 return FAIL;
1795 if (exp_count == 0)
1796 {
1797 EMSG(_(e_nomatch));
1798 return FAIL;
1799 }
1800
1801#ifdef FEAT_LISTCMDS
1802 if (what == AL_ADD)
1803 {
1804 (void)alist_add_list(exp_count, exp_files, after);
1805 vim_free(exp_files);
1806 }
1807 else /* what == AL_SET */
1808#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001809 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810 }
1811
1812 alist_check_arg_idx();
1813
1814 return OK;
1815}
1816
1817/*
1818 * Check the validity of the arg_idx for each other window.
1819 */
1820 static void
1821alist_check_arg_idx()
1822{
1823#ifdef FEAT_WINDOWS
1824 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001825 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826
Bram Moolenaarf740b292006-02-16 22:11:02 +00001827 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828 if (win->w_alist == curwin->w_alist)
1829 check_arg_idx(win);
1830#else
1831 check_arg_idx(curwin);
1832#endif
1833}
1834
1835/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001836 * Return TRUE if window "win" is editing then file at the current argument
1837 * index.
1838 */
1839 static int
1840editing_arg_idx(win)
1841 win_T *win;
1842{
1843 return !(win->w_arg_idx >= WARGCOUNT(win)
1844 || (win->w_buffer->b_fnum
1845 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1846 && (win->w_buffer->b_ffname == NULL
1847 || !(fullpathcmp(
1848 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1849 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1850}
1851
1852/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853 * Check if window "win" is editing the w_arg_idx file in its argument list.
1854 */
1855 void
1856check_arg_idx(win)
1857 win_T *win;
1858{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001859 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860 {
1861 /* We are not editing the current entry in the argument list.
1862 * Set "arg_had_last" if we are editing the last one. */
1863 win->w_arg_idx_invalid = TRUE;
1864 if (win->w_arg_idx != WARGCOUNT(win) - 1
1865 && arg_had_last == FALSE
1866#ifdef FEAT_WINDOWS
1867 && ALIST(win) == &global_alist
1868#endif
1869 && GARGCOUNT > 0
1870 && win->w_arg_idx < GARGCOUNT
1871 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1872 || (win->w_buffer->b_ffname != NULL
1873 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1874 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1875 arg_had_last = TRUE;
1876 }
1877 else
1878 {
1879 /* We are editing the current entry in the argument list.
1880 * Set "arg_had_last" if it's also the last one */
1881 win->w_arg_idx_invalid = FALSE;
1882 if (win->w_arg_idx == WARGCOUNT(win) - 1
1883#ifdef FEAT_WINDOWS
1884 && win->w_alist == &global_alist
1885#endif
1886 )
1887 arg_had_last = TRUE;
1888 }
1889}
1890
1891/*
1892 * ":args", ":argslocal" and ":argsglobal".
1893 */
1894 void
1895ex_args(eap)
1896 exarg_T *eap;
1897{
1898 int i;
1899
1900 if (eap->cmdidx != CMD_args)
1901 {
1902#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1903 alist_unlink(ALIST(curwin));
1904 if (eap->cmdidx == CMD_argglobal)
1905 ALIST(curwin) = &global_alist;
1906 else /* eap->cmdidx == CMD_arglocal */
1907 alist_new();
1908#else
1909 ex_ni(eap);
1910 return;
1911#endif
1912 }
1913
1914 if (!ends_excmd(*eap->arg))
1915 {
1916 /*
1917 * ":args file ..": define new argument list, handle like ":next"
1918 * Also for ":argslocal file .." and ":argsglobal file ..".
1919 */
1920 ex_next(eap);
1921 }
1922 else
1923#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1924 if (eap->cmdidx == CMD_args)
1925#endif
1926 {
1927 /*
1928 * ":args": list arguments.
1929 */
1930 if (ARGCOUNT > 0)
1931 {
1932 /* Overwrite the command, for a short list there is no scrolling
1933 * required and no wait_return(). */
1934 gotocmdline(TRUE);
1935 for (i = 0; i < ARGCOUNT; ++i)
1936 {
1937 if (i == curwin->w_arg_idx)
1938 msg_putchar('[');
1939 msg_outtrans(alist_name(&ARGLIST[i]));
1940 if (i == curwin->w_arg_idx)
1941 msg_putchar(']');
1942 msg_putchar(' ');
1943 }
1944 }
1945 }
1946#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1947 else if (eap->cmdidx == CMD_arglocal)
1948 {
1949 garray_T *gap = &curwin->w_alist->al_ga;
1950
1951 /*
1952 * ":argslocal": make a local copy of the global argument list.
1953 */
1954 if (ga_grow(gap, GARGCOUNT) == OK)
1955 for (i = 0; i < GARGCOUNT; ++i)
1956 if (GARGLIST[i].ae_fname != NULL)
1957 {
1958 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1959 vim_strsave(GARGLIST[i].ae_fname);
1960 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1961 GARGLIST[i].ae_fnum;
1962 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963 }
1964 }
1965#endif
1966}
1967
1968/*
1969 * ":previous", ":sprevious", ":Next" and ":sNext".
1970 */
1971 void
1972ex_previous(eap)
1973 exarg_T *eap;
1974{
1975 /* If past the last one already, go to the last one. */
1976 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1977 do_argfile(eap, ARGCOUNT - 1);
1978 else
1979 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1980}
1981
1982/*
1983 * ":rewind", ":first", ":sfirst" and ":srewind".
1984 */
1985 void
1986ex_rewind(eap)
1987 exarg_T *eap;
1988{
1989 do_argfile(eap, 0);
1990}
1991
1992/*
1993 * ":last" and ":slast".
1994 */
1995 void
1996ex_last(eap)
1997 exarg_T *eap;
1998{
1999 do_argfile(eap, ARGCOUNT - 1);
2000}
2001
2002/*
2003 * ":argument" and ":sargument".
2004 */
2005 void
2006ex_argument(eap)
2007 exarg_T *eap;
2008{
2009 int i;
2010
2011 if (eap->addr_count > 0)
2012 i = eap->line2 - 1;
2013 else
2014 i = curwin->w_arg_idx;
2015 do_argfile(eap, i);
2016}
2017
2018/*
2019 * Edit file "argn" of the argument lists.
2020 */
2021 void
2022do_argfile(eap, argn)
2023 exarg_T *eap;
2024 int argn;
2025{
2026 int other;
2027 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002028 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002029
2030 if (argn < 0 || argn >= ARGCOUNT)
2031 {
2032 if (ARGCOUNT <= 1)
2033 EMSG(_("E163: There is only one file to edit"));
2034 else if (argn < 0)
2035 EMSG(_("E164: Cannot go before first file"));
2036 else
2037 EMSG(_("E165: Cannot go beyond last file"));
2038 }
2039 else
2040 {
2041 setpcmark();
2042#ifdef FEAT_GUI
2043 need_mouse_correct = TRUE;
2044#endif
2045
2046#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002047 /* split window or create new tab page first */
2048 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002049 {
2050 if (win_split(0, 0) == FAIL)
2051 return;
2052# ifdef FEAT_SCROLLBIND
2053 curwin->w_p_scb = FALSE;
2054# endif
2055 }
2056 else
2057#endif
2058 {
2059 /*
2060 * if 'hidden' set, only check for changed file when re-editing
2061 * the same buffer
2062 */
2063 other = TRUE;
2064 if (P_HID(curbuf))
2065 {
2066 p = fix_fname(alist_name(&ARGLIST[argn]));
2067 other = otherfile(p);
2068 vim_free(p);
2069 }
2070 if ((!P_HID(curbuf) || !other)
2071 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2072 return;
2073 }
2074
2075 curwin->w_arg_idx = argn;
2076 if (argn == ARGCOUNT - 1
2077#ifdef FEAT_WINDOWS
2078 && curwin->w_alist == &global_alist
2079#endif
2080 )
2081 arg_had_last = TRUE;
2082
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002083 /* Edit the file; always use the last known line number.
2084 * When it fails (e.g. Abort for already edited file) restore the
2085 * argument index. */
2086 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002087 eap, ECMD_LAST,
2088 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) +
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002089 (eap->forceit ? ECMD_FORCEIT : 0)) == FAIL)
2090 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002092 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093 setmark('\'');
2094 }
2095}
2096
2097/*
2098 * ":next", and commands that behave like it.
2099 */
2100 void
2101ex_next(eap)
2102 exarg_T *eap;
2103{
2104 int i;
2105
2106 /*
2107 * check for changed buffer now, if this fails the argument list is not
2108 * redefined.
2109 */
2110 if ( P_HID(curbuf)
2111 || eap->cmdidx == CMD_snext
2112 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2113 {
2114 if (*eap->arg != NUL) /* redefine file list */
2115 {
2116 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2117 return;
2118 i = 0;
2119 }
2120 else
2121 i = curwin->w_arg_idx + (int)eap->line2;
2122 do_argfile(eap, i);
2123 }
2124}
2125
2126#ifdef FEAT_LISTCMDS
2127/*
2128 * ":argedit"
2129 */
2130 void
2131ex_argedit(eap)
2132 exarg_T *eap;
2133{
2134 int fnum;
2135 int i;
2136 char_u *s;
2137
2138 /* Add the argument to the buffer list and get the buffer number. */
2139 fnum = buflist_add(eap->arg, BLN_LISTED);
2140
2141 /* Check if this argument is already in the argument list. */
2142 for (i = 0; i < ARGCOUNT; ++i)
2143 if (ARGLIST[i].ae_fnum == fnum)
2144 break;
2145 if (i == ARGCOUNT)
2146 {
2147 /* Can't find it, add it to the argument list. */
2148 s = vim_strsave(eap->arg);
2149 if (s == NULL)
2150 return;
2151 i = alist_add_list(1, &s,
2152 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2153 if (i < 0)
2154 return;
2155 curwin->w_arg_idx = i;
2156 }
2157
2158 alist_check_arg_idx();
2159
2160 /* Edit the argument. */
2161 do_argfile(eap, i);
2162}
2163
2164/*
2165 * ":argadd"
2166 */
2167 void
2168ex_argadd(eap)
2169 exarg_T *eap;
2170{
2171 do_arglist(eap->arg, AL_ADD,
2172 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2173#ifdef FEAT_TITLE
2174 maketitle();
2175#endif
2176}
2177
2178/*
2179 * ":argdelete"
2180 */
2181 void
2182ex_argdelete(eap)
2183 exarg_T *eap;
2184{
2185 int i;
2186 int n;
2187
2188 if (eap->addr_count > 0)
2189 {
2190 /* ":1,4argdel": Delete all arguments in the range. */
2191 if (eap->line2 > ARGCOUNT)
2192 eap->line2 = ARGCOUNT;
2193 n = eap->line2 - eap->line1 + 1;
2194 if (*eap->arg != NUL || n <= 0)
2195 EMSG(_(e_invarg));
2196 else
2197 {
2198 for (i = eap->line1; i <= eap->line2; ++i)
2199 vim_free(ARGLIST[i - 1].ae_fname);
2200 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2201 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2202 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002203 if (curwin->w_arg_idx >= eap->line2)
2204 curwin->w_arg_idx -= n;
2205 else if (curwin->w_arg_idx > eap->line1)
2206 curwin->w_arg_idx = eap->line1;
2207 }
2208 }
2209 else if (*eap->arg == NUL)
2210 EMSG(_(e_argreq));
2211 else
2212 do_arglist(eap->arg, AL_DEL, 0);
2213#ifdef FEAT_TITLE
2214 maketitle();
2215#endif
2216}
2217
2218/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002219 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220 */
2221 void
2222ex_listdo(eap)
2223 exarg_T *eap;
2224{
2225 int i;
2226#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002227 win_T *wp;
2228 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002229#endif
2230 buf_T *buf;
2231 int next_fnum = 0;
2232#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2233 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002234#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002235 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002236
2237#ifndef FEAT_WINDOWS
2238 if (eap->cmdidx == CMD_windo)
2239 {
2240 ex_ni(eap);
2241 return;
2242 }
2243#endif
2244
2245#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002246 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002247 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2248 * great speed improvement. */
2249 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002250#endif
2251
2252 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002253 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254 || P_HID(curbuf)
2255 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2256 {
2257 /* start at the first argument/window/buffer */
2258 i = 0;
2259#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002260 wp = firstwin;
2261 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262#endif
2263 /* set pcmark now */
2264 if (eap->cmdidx == CMD_bufdo)
2265 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2266 else
2267 setpcmark();
2268 listcmd_busy = TRUE; /* avoids setting pcmark below */
2269
2270 while (!got_int)
2271 {
2272 if (eap->cmdidx == CMD_argdo)
2273 {
2274 /* go to argument "i" */
2275 if (i == ARGCOUNT)
2276 break;
2277 /* Don't call do_argfile() when already there, it will try
2278 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002279 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002280 {
2281 /* Clear 'shm' to avoid that the file message overwrites
2282 * any output from the command. */
2283 p_shm_save = vim_strsave(p_shm);
2284 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002286 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2287 vim_free(p_shm_save);
2288 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289 if (curwin->w_arg_idx != i)
2290 break;
2291 ++i;
2292 }
2293#ifdef FEAT_WINDOWS
2294 else if (eap->cmdidx == CMD_windo)
2295 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002296 /* go to window "wp" */
2297 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002298 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002299 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002300 if (curwin != wp)
2301 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002302 wp = curwin->w_next;
2303 }
2304 else if (eap->cmdidx == CMD_tabdo)
2305 {
2306 /* go to window "tp" */
2307 if (!valid_tabpage(tp))
2308 break;
2309 goto_tabpage_tp(tp);
2310 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002311 }
2312#endif
2313 else if (eap->cmdidx == CMD_bufdo)
2314 {
2315 /* Remember the number of the next listed buffer, in case
2316 * ":bwipe" is used or autocommands do something strange. */
2317 next_fnum = -1;
2318 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2319 if (buf->b_p_bl)
2320 {
2321 next_fnum = buf->b_fnum;
2322 break;
2323 }
2324 }
2325
2326 /* execute the command */
2327 do_cmdline(eap->arg, eap->getline, eap->cookie,
2328 DOCMD_VERBOSE + DOCMD_NOWAIT);
2329
2330 if (eap->cmdidx == CMD_bufdo)
2331 {
2332 /* Done? */
2333 if (next_fnum < 0)
2334 break;
2335 /* Check if the buffer still exists. */
2336 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2337 if (buf->b_fnum == next_fnum)
2338 break;
2339 if (buf == NULL)
2340 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002341
2342 /* Go to the next buffer. Clear 'shm' to avoid that the file
2343 * message overwrites any output from the command. */
2344 p_shm_save = vim_strsave(p_shm);
2345 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002347 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2348 vim_free(p_shm_save);
2349
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350 /* If autocommands took us elsewhere, quit here */
2351 if (curbuf->b_fnum != next_fnum)
2352 break;
2353 }
2354
2355 if (eap->cmdidx == CMD_windo)
2356 {
2357 validate_cursor(); /* cursor may have moved */
2358#ifdef FEAT_SCROLLBIND
2359 /* required when 'scrollbind' has been set */
2360 if (curwin->w_p_scb)
2361 do_check_scrollbind(TRUE);
2362#endif
2363 }
2364 }
2365 listcmd_busy = FALSE;
2366 }
2367
2368#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002369 if (save_ei != NULL)
2370 {
2371 au_event_restore(save_ei);
2372 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2373 curbuf->b_fname, TRUE, curbuf);
2374 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375#endif
2376}
2377
2378/*
2379 * Add files[count] to the arglist of the current window after arg "after".
2380 * The file names in files[count] must have been allocated and are taken over.
2381 * Files[] itself is not taken over.
2382 * Returns index of first added argument. Returns -1 when failed (out of mem).
2383 */
2384 static int
2385alist_add_list(count, files, after)
2386 int count;
2387 char_u **files;
2388 int after; /* where to add: 0 = before first one */
2389{
2390 int i;
2391
2392 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2393 {
2394 if (after < 0)
2395 after = 0;
2396 if (after > ARGCOUNT)
2397 after = ARGCOUNT;
2398 if (after < ARGCOUNT)
2399 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2400 (ARGCOUNT - after) * sizeof(aentry_T));
2401 for (i = 0; i < count; ++i)
2402 {
2403 ARGLIST[after + i].ae_fname = files[i];
2404 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2405 }
2406 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002407 if (curwin->w_arg_idx >= after)
2408 ++curwin->w_arg_idx;
2409 return after;
2410 }
2411
2412 for (i = 0; i < count; ++i)
2413 vim_free(files[i]);
2414 return -1;
2415}
2416
2417#endif /* FEAT_LISTCMDS */
2418
2419#ifdef FEAT_EVAL
2420/*
2421 * ":compiler[!] {name}"
2422 */
2423 void
2424ex_compiler(eap)
2425 exarg_T *eap;
2426{
2427 char_u *buf;
2428 char_u *old_cur_comp = NULL;
2429 char_u *p;
2430
2431 if (*eap->arg == NUL)
2432 {
2433 /* List all compiler scripts. */
2434 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2435 /* ) keep the indenter happy... */
2436 }
2437 else
2438 {
2439 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2440 if (buf != NULL)
2441 {
2442 if (eap->forceit)
2443 {
2444 /* ":compiler! {name}" sets global options */
2445 do_cmdline_cmd((char_u *)
2446 "command -nargs=* CompilerSet set <args>");
2447 }
2448 else
2449 {
2450 /* ":compiler! {name}" sets local options.
2451 * To remain backwards compatible "current_compiler" is always
2452 * used. A user's compiler plugin may set it, the distributed
2453 * plugin will then skip the settings. Afterwards set
2454 * "b:current_compiler" and restore "current_compiler". */
2455 old_cur_comp = get_var_value((char_u *)"current_compiler");
2456 if (old_cur_comp != NULL)
2457 old_cur_comp = vim_strsave(old_cur_comp);
2458 do_cmdline_cmd((char_u *)
2459 "command -nargs=* CompilerSet setlocal <args>");
2460 }
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002461 do_unlet((char_u *)"current_compiler", TRUE);
2462 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463
2464 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002465 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2467 vim_free(buf);
2468
2469 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2470
2471 /* Set "b:current_compiler" from "current_compiler". */
2472 p = get_var_value((char_u *)"current_compiler");
2473 if (p != NULL)
2474 set_internal_string_var((char_u *)"b:current_compiler", p);
2475
2476 /* Restore "current_compiler" for ":compiler {name}". */
2477 if (!eap->forceit)
2478 {
2479 if (old_cur_comp != NULL)
2480 {
2481 set_internal_string_var((char_u *)"current_compiler",
2482 old_cur_comp);
2483 vim_free(old_cur_comp);
2484 }
2485 else
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002486 do_unlet((char_u *)"current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487 }
2488 }
2489 }
2490}
2491#endif
2492
2493/*
2494 * ":runtime {name}"
2495 */
2496 void
2497ex_runtime(eap)
2498 exarg_T *eap;
2499{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002500 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002501}
2502
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002503static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002505/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00002506 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002507source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002508 char_u *fname;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002509 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002511 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512}
2513
2514/*
2515 * Source the file "name" from all directories in 'runtimepath'.
2516 * "name" can contain wildcards.
2517 * When "all" is TRUE, source all files, otherwise only the first one.
2518 * return FAIL when no file could be sourced, OK otherwise.
2519 */
2520 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002521source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002522 char_u *name;
2523 int all;
2524{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002525 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002526}
2527
2528/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002529 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2530 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2532 * used.
2533 * Returns OK when at least one match found, FAIL otherwise.
2534 */
2535 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002536do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002537 char_u *name;
2538 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002539 void (*callback)__ARGS((char_u *fname, void *ck));
2540 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541{
2542 char_u *rtp;
2543 char_u *np;
2544 char_u *buf;
2545 char_u *rtp_copy;
2546 char_u *tail;
2547 int num_files;
2548 char_u **files;
2549 int i;
2550 int did_one = FALSE;
2551#ifdef AMIGA
2552 struct Process *proc = (struct Process *)FindTask(0L);
2553 APTR save_winptr = proc->pr_WindowPtr;
2554
2555 /* Avoid a requester here for a volume that doesn't exist. */
2556 proc->pr_WindowPtr = (APTR)-1L;
2557#endif
2558
2559 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2560 * value. */
2561 rtp_copy = vim_strsave(p_rtp);
2562 buf = alloc(MAXPATHL);
2563 if (buf != NULL && rtp_copy != NULL)
2564 {
2565 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002566 {
2567 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002568 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002569 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002570 verbose_leave();
2571 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002572
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573 /* Loop over all entries in 'runtimepath'. */
2574 rtp = rtp_copy;
2575 while (*rtp != NUL && (all || !did_one))
2576 {
2577 /* Copy the path from 'runtimepath' to buf[]. */
2578 copy_option_part(&rtp, buf, MAXPATHL, ",");
2579 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2580 {
2581 add_pathsep(buf);
2582 tail = buf + STRLEN(buf);
2583
2584 /* Loop over all patterns in "name" */
2585 np = name;
2586 while (*np != NUL && (all || !did_one))
2587 {
2588 /* Append the pattern from "name" to buf[]. */
2589 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2590 "\t ");
2591
2592 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002593 {
2594 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002595 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002596 verbose_leave();
2597 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598
2599 /* Expand wildcards, invoke the callback for each match. */
2600 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2601 EW_FILE) == OK)
2602 {
2603 for (i = 0; i < num_files; ++i)
2604 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002605 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606 did_one = TRUE;
2607 if (!all)
2608 break;
2609 }
2610 FreeWild(num_files, files);
2611 }
2612 }
2613 }
2614 }
2615 }
2616 vim_free(buf);
2617 vim_free(rtp_copy);
2618 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002619 {
2620 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002621 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002622 verbose_leave();
2623 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624
2625#ifdef AMIGA
2626 proc->pr_WindowPtr = save_winptr;
2627#endif
2628
2629 return did_one ? OK : FAIL;
2630}
2631
2632#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2633/*
2634 * ":options"
2635 */
2636/*ARGSUSED*/
2637 void
2638ex_options(eap)
2639 exarg_T *eap;
2640{
2641 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2642}
2643#endif
2644
2645/*
2646 * ":source {fname}"
2647 */
2648 void
2649ex_source(eap)
2650 exarg_T *eap;
2651{
2652#ifdef FEAT_BROWSE
2653 if (cmdmod.browse)
2654 {
2655 char_u *fname = NULL;
2656
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002657 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2659 if (fname != NULL)
2660 {
2661 cmd_source(fname, eap);
2662 vim_free(fname);
2663 }
2664 }
2665 else
2666#endif
2667 cmd_source(eap->arg, eap);
2668}
2669
2670 static void
2671cmd_source(fname, eap)
2672 char_u *fname;
2673 exarg_T *eap;
2674{
2675 if (*fname == NUL)
2676 EMSG(_(e_argreq));
2677
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002679 /* ":source!": read Normal mdoe commands
2680 * Need to execute the commands directly. This is required at least
2681 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682 * - ":g" command busy
2683 * - after ":argdo", ":windo" or ":bufdo"
2684 * - another command follows
2685 * - inside a loop
2686 */
2687 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2688#ifdef FEAT_EVAL
2689 || eap->cstack->cs_idx >= 0
2690#endif
2691 );
2692
2693 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002694 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002695 EMSG2(_(e_notopen), fname);
2696}
2697
2698/*
2699 * ":source" and associated commands.
2700 */
2701/*
2702 * Structure used to store info for each sourced file.
2703 * It is shared between do_source() and getsourceline().
2704 * This is required, because it needs to be handed to do_cmdline() and
2705 * sourcing can be done recursively.
2706 */
2707struct source_cookie
2708{
2709 FILE *fp; /* opened file for sourcing */
2710 char_u *nextline; /* if not NULL: line that was read ahead */
2711 int finished; /* ":finish" used */
2712#if defined (USE_CRNL) || defined (USE_CR)
2713 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2714 int error; /* TRUE if LF found after CR-LF */
2715#endif
2716#ifdef FEAT_EVAL
2717 linenr_T breakpoint; /* next line with breakpoint or zero */
2718 char_u *fname; /* name of sourced file */
2719 int dbg_tick; /* debug_tick when breakpoint was set */
2720 int level; /* top nesting level of sourced file */
2721#endif
2722#ifdef FEAT_MBYTE
2723 vimconv_T conv; /* type of conversion */
2724#endif
2725};
2726
2727#ifdef FEAT_EVAL
2728/*
2729 * Return the address holding the next breakpoint line for a source cookie.
2730 */
2731 linenr_T *
2732source_breakpoint(cookie)
2733 void *cookie;
2734{
2735 return &((struct source_cookie *)cookie)->breakpoint;
2736}
2737
2738/*
2739 * Return the address holding the debug tick for a source cookie.
2740 */
2741 int *
2742source_dbg_tick(cookie)
2743 void *cookie;
2744{
2745 return &((struct source_cookie *)cookie)->dbg_tick;
2746}
2747
2748/*
2749 * Return the nesting level for a source cookie.
2750 */
2751 int
2752source_level(cookie)
2753 void *cookie;
2754{
2755 return ((struct source_cookie *)cookie)->level;
2756}
2757#endif
2758
2759static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2760
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761#if defined(WIN32) && defined(FEAT_CSCOPE)
2762static FILE *fopen_noinh_readbin __ARGS((char *filename));
2763
2764/*
2765 * Special function to open a file without handle inheritance.
2766 */
2767 static FILE *
2768fopen_noinh_readbin(filename)
2769 char *filename;
2770{
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00002771 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002772
2773 if (fd_tmp == -1)
2774 return NULL;
2775 return fdopen(fd_tmp, READBIN);
2776}
2777#endif
2778
2779
2780/*
2781 * do_source: Read the file "fname" and execute its lines as EX commands.
2782 *
2783 * This function may be called recursively!
2784 *
2785 * return FAIL if file could not be opened, OK otherwise
2786 */
2787 int
2788do_source(fname, check_other, is_vimrc)
2789 char_u *fname;
2790 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002791 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792{
2793 struct source_cookie cookie;
2794 char_u *save_sourcing_name;
2795 linenr_T save_sourcing_lnum;
2796 char_u *p;
2797 char_u *fname_exp;
2798 int retval = FAIL;
2799#ifdef FEAT_EVAL
2800 scid_T save_current_SID;
2801 static scid_T last_current_SID = 0;
2802 void *save_funccalp;
2803 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002804 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002805# ifdef UNIX
2806 struct stat st;
2807 int stat_ok;
2808# endif
2809#endif
2810#ifdef STARTUPTIME
2811 struct timeval tv_rel;
2812 struct timeval tv_start;
2813#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002814#ifdef FEAT_PROFILE
2815 proftime_T wait_start;
2816#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817
2818#ifdef RISCOS
2819 p = mch_munge_fname(fname);
2820#else
2821 p = expand_env_save(fname);
2822#endif
2823 if (p == NULL)
2824 return retval;
2825 fname_exp = fix_fname(p);
2826 vim_free(p);
2827 if (fname_exp == NULL)
2828 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002829 if (mch_isdir(fname_exp))
2830 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002831 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832 goto theend;
2833 }
2834
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002835#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002836 /* Apply SourceCmd autocommands, they should get the file and source it. */
2837 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2838 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2839 FALSE, curbuf))
2840# ifdef FEAT_EVAL
2841 return aborting() ? FAIL : OK;
2842# else
2843 return OK;
2844# endif
2845
2846 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002847 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2848#endif
2849
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850#if defined(WIN32) && defined(FEAT_CSCOPE)
2851 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2852#else
2853 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2854#endif
2855 if (cookie.fp == NULL && check_other)
2856 {
2857 /*
2858 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2859 * and ".exrc" by "_exrc" or vice versa.
2860 */
2861 p = gettail(fname_exp);
2862 if ((*p == '.' || *p == '_')
2863 && (STRICMP(p + 1, "vimrc") == 0
2864 || STRICMP(p + 1, "gvimrc") == 0
2865 || STRICMP(p + 1, "exrc") == 0))
2866 {
2867 if (*p == '_')
2868 *p = '.';
2869 else
2870 *p = '_';
2871#if defined(WIN32) && defined(FEAT_CSCOPE)
2872 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2873#else
2874 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2875#endif
2876 }
2877 }
2878
2879 if (cookie.fp == NULL)
2880 {
2881 if (p_verbose > 0)
2882 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002883 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002885 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002886 else
2887 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002888 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002889 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002890 }
2891 goto theend;
2892 }
2893
2894 /*
2895 * The file exists.
2896 * - In verbose mode, give a message.
2897 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2898 */
2899 if (p_verbose > 1)
2900 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002901 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002903 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904 else
2905 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002906 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002907 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002909 if (is_vimrc == DOSO_VIMRC)
2910 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
2911 else if (is_vimrc == DOSO_GVIMRC)
2912 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913
2914#ifdef USE_CRNL
2915 /* If no automatic file format: Set default to CR-NL. */
2916 if (*p_ffs == NUL)
2917 cookie.fileformat = EOL_DOS;
2918 else
2919 cookie.fileformat = EOL_UNKNOWN;
2920 cookie.error = FALSE;
2921#endif
2922
2923#ifdef USE_CR
2924 /* If no automatic file format: Set default to CR. */
2925 if (*p_ffs == NUL)
2926 cookie.fileformat = EOL_MAC;
2927 else
2928 cookie.fileformat = EOL_UNKNOWN;
2929 cookie.error = FALSE;
2930#endif
2931
2932 cookie.nextline = NULL;
2933 cookie.finished = FALSE;
2934
2935#ifdef FEAT_EVAL
2936 /*
2937 * Check if this script has a breakpoint.
2938 */
2939 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2940 cookie.fname = fname_exp;
2941 cookie.dbg_tick = debug_tick;
2942
2943 cookie.level = ex_nesting_level;
2944#endif
2945#ifdef FEAT_MBYTE
2946 cookie.conv.vc_type = CONV_NONE; /* no conversion */
2947
2948 /* Try reading the first few bytes to check for a UTF-8 BOM. */
2949 {
2950 char_u buf[3];
2951
2952 if (fread((char *)buf, sizeof(char_u), (size_t)3, cookie.fp)
2953 == (size_t)3
2954 && buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf)
2955 /* Found BOM, setup conversion and skip over it. */
2956 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
2957 else
2958 /* No BOM found, rewind. */
2959 fseek(cookie.fp, 0L, SEEK_SET);
2960 }
2961#endif
2962
2963 /*
2964 * Keep the sourcing name/lnum, for recursive calls.
2965 */
2966 save_sourcing_name = sourcing_name;
2967 sourcing_name = fname_exp;
2968 save_sourcing_lnum = sourcing_lnum;
2969 sourcing_lnum = 0;
2970
2971#ifdef STARTUPTIME
2972 time_push(&tv_rel, &tv_start);
2973#endif
2974
2975#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00002976# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002977 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002978 prof_child_enter(&wait_start); /* entering a child now */
2979# endif
2980
2981 /* Don't use local function variables, if called from a function.
2982 * Also starts profiling timer for nested script. */
2983 save_funccalp = save_funccal();
2984
Bram Moolenaar071d4272004-06-13 20:20:40 +00002985 /*
2986 * Check if this script was sourced before to finds its SID.
2987 * If it's new, generate a new SID.
2988 */
2989 save_current_SID = current_SID;
2990# ifdef UNIX
2991 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
2992# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002993 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
2994 {
2995 si = &SCRIPT_ITEM(current_SID);
2996 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002997 && (
2998# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00002999 /* Compare dev/ino when possible, it catches symbolic
3000 * links. Also compare file names, the inode may change
3001 * when the file was edited. */
Bram Moolenaar05159a02005-02-26 23:04:13 +00003002 ((stat_ok && si->sn_dev != -1)
3003 && (si->sn_dev == st.st_dev
3004 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003005# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003006 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003007 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003008 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003009 if (current_SID == 0)
3010 {
3011 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003012 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3013 == FAIL)
3014 goto almosttheend;
3015 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003017 ++script_items.ga_len;
3018 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3019# ifdef FEAT_PROFILE
3020 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003023 si = &SCRIPT_ITEM(current_SID);
3024 si->sn_name = fname_exp;
3025 fname_exp = NULL;
3026# ifdef UNIX
3027 if (stat_ok)
3028 {
3029 si->sn_dev = st.st_dev;
3030 si->sn_ino = st.st_ino;
3031 }
3032 else
3033 si->sn_dev = -1;
3034# endif
3035
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036 /* Allocate the local script variables to use for this script. */
3037 new_script_vars(current_SID);
3038 }
3039
Bram Moolenaar05159a02005-02-26 23:04:13 +00003040# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003041 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003042 {
3043 int forceit;
3044
3045 /* Check if we do profiling for this script. */
3046 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3047 {
3048 script_do_profile(si);
3049 si->sn_pr_force = forceit;
3050 }
3051 if (si->sn_prof_on)
3052 {
3053 ++si->sn_pr_count;
3054 profile_start(&si->sn_pr_start);
3055 profile_zero(&si->sn_pr_children);
3056 }
3057 }
3058# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059#endif
3060
3061 /*
3062 * Call do_cmdline, which will call getsourceline() to get the lines.
3063 */
3064 do_cmdline(NULL, getsourceline, (void *)&cookie,
3065 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
3066
3067 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003068
3069#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003070 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003071 {
3072 /* Get "si" again, "script_items" may have been reallocated. */
3073 si = &SCRIPT_ITEM(current_SID);
3074 if (si->sn_prof_on)
3075 {
3076 profile_end(&si->sn_pr_start);
3077 profile_sub_wait(&wait_start, &si->sn_pr_start);
3078 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003079 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3080 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003081 }
3082 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083#endif
3084
3085 if (got_int)
3086 EMSG(_(e_interr));
3087 sourcing_name = save_sourcing_name;
3088 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089 if (p_verbose > 1)
3090 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003091 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003092 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003094 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003095 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003096 }
3097#ifdef STARTUPTIME
Bram Moolenaar555b2802005-05-19 21:08:39 +00003098 vim_snprintf(IObuff, IOSIZE, "sourcing %s", fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003099 time_msg(IObuff, &tv_start);
3100 time_pop(&tv_rel);
3101#endif
3102
3103#ifdef FEAT_EVAL
3104 /*
3105 * After a "finish" in debug mode, need to break at first command of next
3106 * sourced file.
3107 */
3108 if (save_debug_break_level > ex_nesting_level
3109 && debug_break_level == ex_nesting_level)
3110 ++debug_break_level;
3111#endif
3112
Bram Moolenaar05159a02005-02-26 23:04:13 +00003113#ifdef FEAT_EVAL
3114almosttheend:
3115 current_SID = save_current_SID;
3116 restore_funccal(save_funccalp);
3117# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003118 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003119 prof_child_exit(&wait_start); /* leaving a child now */
3120# endif
3121#endif
3122 fclose(cookie.fp);
3123 vim_free(cookie.nextline);
3124#ifdef FEAT_MBYTE
3125 convert_setup(&cookie.conv, NULL, NULL);
3126#endif
3127
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128theend:
3129 vim_free(fname_exp);
3130 return retval;
3131}
3132
3133#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003134
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135/*
3136 * ":scriptnames"
3137 */
3138/*ARGSUSED*/
3139 void
3140ex_scriptnames(eap)
3141 exarg_T *eap;
3142{
3143 int i;
3144
Bram Moolenaar05159a02005-02-26 23:04:13 +00003145 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3146 if (SCRIPT_ITEM(i).sn_name != NULL)
3147 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148}
3149
3150# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3151/*
3152 * Fix slashes in the list of script names for 'shellslash'.
3153 */
3154 void
3155scriptnames_slash_adjust()
3156{
3157 int i;
3158
Bram Moolenaar05159a02005-02-26 23:04:13 +00003159 for (i = 1; i <= script_items.ga_len; ++i)
3160 if (SCRIPT_ITEM(i).sn_name != NULL)
3161 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162}
3163# endif
3164
3165/*
3166 * Get a pointer to a script name. Used for ":verbose set".
3167 */
3168 char_u *
3169get_scriptname(id)
3170 scid_T id;
3171{
3172 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003173 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003175 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003177 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003178 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003179 return (char_u *)_("environment variable");
3180 if (id == SID_ERROR)
3181 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003182 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003183}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003184
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003185# if defined(EXITFREE) || defined(PROTO)
3186 void
3187free_scriptnames()
3188{
3189 int i;
3190
3191 for (i = script_items.ga_len; i > 0; --i)
3192 vim_free(SCRIPT_ITEM(i).sn_name);
3193 ga_clear(&script_items);
3194}
3195# endif
3196
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197#endif
3198
3199#if defined(USE_CR) || defined(PROTO)
3200
3201# if defined(__MSL__) && (__MSL__ >= 22)
3202/*
3203 * Newer version of the Metrowerks library handle DOS and UNIX files
3204 * without help.
3205 * Test with earlier versions, MSL 2.2 is the library supplied with
3206 * Codewarrior Pro 2.
3207 */
3208 char *
3209fgets_cr(s, n, stream)
3210 char *s;
3211 int n;
3212 FILE *stream;
3213{
3214 return fgets(s, n, stream);
3215}
3216# else
3217/*
3218 * Version of fgets() which also works for lines ending in a <CR> only
3219 * (Macintosh format).
3220 * For older versions of the Metrowerks library.
3221 * At least CodeWarrior 9 needed this code.
3222 */
3223 char *
3224fgets_cr(s, n, stream)
3225 char *s;
3226 int n;
3227 FILE *stream;
3228{
3229 int c = 0;
3230 int char_read = 0;
3231
3232 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3233 {
3234 c = fgetc(stream);
3235 s[char_read++] = c;
3236 /* If the file is in DOS format, we need to skip a NL after a CR. I
3237 * thought it was the other way around, but this appears to work... */
3238 if (c == '\n')
3239 {
3240 c = fgetc(stream);
3241 if (c != '\r')
3242 ungetc(c, stream);
3243 }
3244 }
3245
3246 s[char_read] = 0;
3247 if (char_read == 0)
3248 return NULL;
3249
3250 if (feof(stream) && char_read == 1)
3251 return NULL;
3252
3253 return s;
3254}
3255# endif
3256#endif
3257
3258/*
3259 * Get one full line from a sourced file.
3260 * Called by do_cmdline() when it's called from do_source().
3261 *
3262 * Return a pointer to the line in allocated memory.
3263 * Return NULL for end-of-file or some error.
3264 */
3265/* ARGSUSED */
3266 char_u *
3267getsourceline(c, cookie, indent)
3268 int c; /* not used */
3269 void *cookie;
3270 int indent; /* not used */
3271{
3272 struct source_cookie *sp = (struct source_cookie *)cookie;
3273 char_u *line;
3274 char_u *p, *s;
3275
3276#ifdef FEAT_EVAL
3277 /* If breakpoints have been added/deleted need to check for it. */
3278 if (sp->dbg_tick < debug_tick)
3279 {
3280 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3281 sp->dbg_tick = debug_tick;
3282 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003283# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003284 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003285 script_line_end();
3286# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287#endif
3288 /*
3289 * Get current line. If there is a read-ahead line, use it, otherwise get
3290 * one now.
3291 */
3292 if (sp->finished)
3293 line = NULL;
3294 else if (sp->nextline == NULL)
3295 line = get_one_sourceline(sp);
3296 else
3297 {
3298 line = sp->nextline;
3299 sp->nextline = NULL;
3300 ++sourcing_lnum;
3301 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003302#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003303 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003304 script_line_start();
3305#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306
3307 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3308 * contain the 'C' flag. */
3309 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3310 {
3311 /* compensate for the one line read-ahead */
3312 --sourcing_lnum;
3313 for (;;)
3314 {
3315 sp->nextline = get_one_sourceline(sp);
3316 if (sp->nextline == NULL)
3317 break;
3318 p = skipwhite(sp->nextline);
3319 if (*p != '\\')
3320 break;
3321 s = alloc((int)(STRLEN(line) + STRLEN(p)));
3322 if (s == NULL) /* out of memory */
3323 break;
3324 STRCPY(s, line);
3325 STRCAT(s, p + 1);
3326 vim_free(line);
3327 line = s;
3328 vim_free(sp->nextline);
3329 }
3330 }
3331
3332#ifdef FEAT_MBYTE
3333 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3334 {
3335 /* Convert the encoding of the script line. */
3336 s = string_convert(&sp->conv, line, NULL);
3337 if (s != NULL)
3338 {
3339 vim_free(line);
3340 line = s;
3341 }
3342 }
3343#endif
3344
3345#ifdef FEAT_EVAL
3346 /* Did we encounter a breakpoint? */
3347 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3348 {
3349 dbg_breakpoint(sp->fname, sourcing_lnum);
3350 /* Find next breakpoint. */
3351 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3352 sp->dbg_tick = debug_tick;
3353 }
3354#endif
3355
3356 return line;
3357}
3358
3359 static char_u *
3360get_one_sourceline(sp)
3361 struct source_cookie *sp;
3362{
3363 garray_T ga;
3364 int len;
3365 int c;
3366 char_u *buf;
3367#ifdef USE_CRNL
3368 int has_cr; /* CR-LF found */
3369#endif
3370#ifdef USE_CR
3371 char_u *scan;
3372#endif
3373 int have_read = FALSE;
3374
3375 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003376 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377
3378 /*
3379 * Loop until there is a finished line (or end-of-file).
3380 */
3381 sourcing_lnum++;
3382 for (;;)
3383 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003384 /* make room to read at least 120 (more) characters */
3385 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003386 break;
3387 buf = (char_u *)ga.ga_data;
3388
3389#ifdef USE_CR
3390 if (sp->fileformat == EOL_MAC)
3391 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003392 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3393 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394 break;
3395 }
3396 else
3397#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003398 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3399 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003400 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003401 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402#ifdef USE_CRNL
3403 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3404 * CTRL-Z by its own, or after a NL. */
3405 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3406 && sp->fileformat == EOL_DOS
3407 && buf[len - 1] == Ctrl_Z)
3408 {
3409 buf[len - 1] = NUL;
3410 break;
3411 }
3412#endif
3413
3414#ifdef USE_CR
3415 /* If the read doesn't stop on a new line, and there's
3416 * some CR then we assume a Mac format */
3417 if (sp->fileformat == EOL_UNKNOWN)
3418 {
3419 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3420 sp->fileformat = EOL_MAC;
3421 else
3422 sp->fileformat = EOL_UNIX;
3423 }
3424
3425 if (sp->fileformat == EOL_MAC)
3426 {
3427 scan = vim_strchr(buf, '\r');
3428
3429 if (scan != NULL)
3430 {
3431 *scan = '\n';
3432 if (*(scan + 1) != 0)
3433 {
3434 *(scan + 1) = 0;
3435 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3436 }
3437 }
3438 len = STRLEN(buf);
3439 }
3440#endif
3441
3442 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003443 ga.ga_len = len;
3444
3445 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003446 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447 continue;
3448
3449 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3450 {
3451#ifdef USE_CRNL
3452 has_cr = (len >= 2 && buf[len - 2] == '\r');
3453 if (sp->fileformat == EOL_UNKNOWN)
3454 {
3455 if (has_cr)
3456 sp->fileformat = EOL_DOS;
3457 else
3458 sp->fileformat = EOL_UNIX;
3459 }
3460
3461 if (sp->fileformat == EOL_DOS)
3462 {
3463 if (has_cr) /* replace trailing CR */
3464 {
3465 buf[len - 2] = '\n';
3466 --len;
3467 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468 }
3469 else /* lines like ":map xx yy^M" will have failed */
3470 {
3471 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003472 {
3473 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003474 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003475 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476 sp->error = TRUE;
3477 sp->fileformat = EOL_UNIX;
3478 }
3479 }
3480#endif
3481 /* The '\n' is escaped if there is an odd number of ^V's just
3482 * before it, first set "c" just before the 'V's and then check
3483 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3484 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3485 ;
3486 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3487 {
3488 sourcing_lnum++;
3489 continue;
3490 }
3491
3492 buf[len - 1] = NUL; /* remove the NL */
3493 }
3494
3495 /*
3496 * Check for ^C here now and then, so recursive :so can be broken.
3497 */
3498 line_breakcheck();
3499 break;
3500 }
3501
3502 if (have_read)
3503 return (char_u *)ga.ga_data;
3504
3505 vim_free(ga.ga_data);
3506 return NULL;
3507}
3508
Bram Moolenaar05159a02005-02-26 23:04:13 +00003509#if defined(FEAT_PROFILE) || defined(PROTO)
3510/*
3511 * Called when starting to read a script line.
3512 * "sourcing_lnum" must be correct!
3513 * When skipping lines it may not actually be executed, but we won't find out
3514 * until later and we need to store the time now.
3515 */
3516 void
3517script_line_start()
3518{
3519 scriptitem_T *si;
3520 sn_prl_T *pp;
3521
3522 if (current_SID <= 0 || current_SID > script_items.ga_len)
3523 return;
3524 si = &SCRIPT_ITEM(current_SID);
3525 if (si->sn_prof_on && sourcing_lnum >= 1)
3526 {
3527 /* Grow the array before starting the timer, so that the time spend
3528 * here isn't counted. */
3529 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3530 si->sn_prl_idx = sourcing_lnum - 1;
3531 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3532 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3533 {
3534 /* Zero counters for a line that was not used before. */
3535 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3536 pp->snp_count = 0;
3537 profile_zero(&pp->sn_prl_total);
3538 profile_zero(&pp->sn_prl_self);
3539 ++si->sn_prl_ga.ga_len;
3540 }
3541 si->sn_prl_execed = FALSE;
3542 profile_start(&si->sn_prl_start);
3543 profile_zero(&si->sn_prl_children);
3544 profile_get_wait(&si->sn_prl_wait);
3545 }
3546}
3547
3548/*
3549 * Called when actually executing a function line.
3550 */
3551 void
3552script_line_exec()
3553{
3554 scriptitem_T *si;
3555
3556 if (current_SID <= 0 || current_SID > script_items.ga_len)
3557 return;
3558 si = &SCRIPT_ITEM(current_SID);
3559 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3560 si->sn_prl_execed = TRUE;
3561}
3562
3563/*
3564 * Called when done with a function line.
3565 */
3566 void
3567script_line_end()
3568{
3569 scriptitem_T *si;
3570 sn_prl_T *pp;
3571
3572 if (current_SID <= 0 || current_SID > script_items.ga_len)
3573 return;
3574 si = &SCRIPT_ITEM(current_SID);
3575 if (si->sn_prof_on && si->sn_prl_idx >= 0
3576 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3577 {
3578 if (si->sn_prl_execed)
3579 {
3580 pp = &PRL_ITEM(si, si->sn_prl_idx);
3581 ++pp->snp_count;
3582 profile_end(&si->sn_prl_start);
3583 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003584 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003585 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3586 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003587 }
3588 si->sn_prl_idx = -1;
3589 }
3590}
3591#endif
3592
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593/*
3594 * ":scriptencoding": Set encoding conversion for a sourced script.
3595 * Without the multi-byte feature it's simply ignored.
3596 */
3597/*ARGSUSED*/
3598 void
3599ex_scriptencoding(eap)
3600 exarg_T *eap;
3601{
3602#ifdef FEAT_MBYTE
3603 struct source_cookie *sp;
3604 char_u *name;
3605
3606 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3607 {
3608 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3609 return;
3610 }
3611
3612 if (*eap->arg != NUL)
3613 {
3614 name = enc_canonize(eap->arg);
3615 if (name == NULL) /* out of memory */
3616 return;
3617 }
3618 else
3619 name = eap->arg;
3620
3621 /* Setup for conversion from the specified encoding to 'encoding'. */
3622 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3623 convert_setup(&sp->conv, name, p_enc);
3624
3625 if (name != eap->arg)
3626 vim_free(name);
3627#endif
3628}
3629
3630#if defined(FEAT_EVAL) || defined(PROTO)
3631/*
3632 * ":finish": Mark a sourced file as finished.
3633 */
3634 void
3635ex_finish(eap)
3636 exarg_T *eap;
3637{
3638 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3639 do_finish(eap, FALSE);
3640 else
3641 EMSG(_("E168: :finish used outside of a sourced file"));
3642}
3643
3644/*
3645 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3646 * Also called for a pending finish at the ":endtry" or after returning from
3647 * an extra do_cmdline(). "reanimate" is used in the latter case.
3648 */
3649 void
3650do_finish(eap, reanimate)
3651 exarg_T *eap;
3652 int reanimate;
3653{
3654 int idx;
3655
3656 if (reanimate)
3657 ((struct source_cookie *)getline_cookie(eap->getline,
3658 eap->cookie))->finished = FALSE;
3659
3660 /*
3661 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3662 * not in its finally clause (which then is to be executed next) is found.
3663 * In this case, make the ":finish" pending for execution at the ":endtry".
3664 * Otherwise, finish normally.
3665 */
3666 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3667 if (idx >= 0)
3668 {
3669 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3670 report_make_pending(CSTP_FINISH, NULL);
3671 }
3672 else
3673 ((struct source_cookie *)getline_cookie(eap->getline,
3674 eap->cookie))->finished = TRUE;
3675}
3676
3677
3678/*
3679 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3680 * message for missing ":endif".
3681 * Return FALSE when not sourcing a file.
3682 */
3683 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003684source_finished(fgetline, cookie)
3685 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003686 void *cookie;
3687{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003688 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003690 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003691}
3692#endif
3693
3694#if defined(FEAT_LISTCMDS) || defined(PROTO)
3695/*
3696 * ":checktime [buffer]"
3697 */
3698 void
3699ex_checktime(eap)
3700 exarg_T *eap;
3701{
3702 buf_T *buf;
3703 int save_no_check_timestamps = no_check_timestamps;
3704
3705 no_check_timestamps = 0;
3706 if (eap->addr_count == 0) /* default is all buffers */
3707 check_timestamps(FALSE);
3708 else
3709 {
3710 buf = buflist_findnr((int)eap->line2);
3711 if (buf != NULL) /* cannot happen? */
3712 (void)buf_check_timestamp(buf, FALSE);
3713 }
3714 no_check_timestamps = save_no_check_timestamps;
3715}
3716#endif
3717
Bram Moolenaar071d4272004-06-13 20:20:40 +00003718#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3719 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3720static char *get_locale_val __ARGS((int what));
3721
3722 static char *
3723get_locale_val(what)
3724 int what;
3725{
3726 char *loc;
3727
3728 /* Obtain the locale value from the libraries. For DJGPP this is
3729 * redefined and it doesn't use the arguments. */
3730 loc = setlocale(what, NULL);
3731
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003732# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733 if (loc != NULL)
3734 {
3735 char_u *p;
3736
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003737 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3738 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739 p = vim_strchr(loc, '=');
3740 if (p != NULL)
3741 {
3742 loc = ++p;
3743 while (*p != NUL) /* remove trailing newline */
3744 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003745 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746 {
3747 *p = NUL;
3748 break;
3749 }
3750 ++p;
3751 }
3752 }
3753 }
3754# endif
3755
3756 return loc;
3757}
3758#endif
3759
3760
3761#ifdef WIN32
3762/*
3763 * On MS-Windows locale names are strings like "German_Germany.1252", but
3764 * gettext expects "de". Try to translate one into another here for a few
3765 * supported languages.
3766 */
3767 static char_u *
3768gettext_lang(char_u *name)
3769{
3770 int i;
3771 static char *(mtable[]) = {
3772 "afrikaans", "af",
3773 "czech", "cs",
3774 "dutch", "nl",
3775 "german", "de",
3776 "english_united kingdom", "en_GB",
3777 "spanish", "es",
3778 "french", "fr",
3779 "italian", "it",
3780 "japanese", "ja",
3781 "korean", "ko",
3782 "norwegian", "no",
3783 "polish", "pl",
3784 "russian", "ru",
3785 "slovak", "sk",
3786 "swedish", "sv",
3787 "ukrainian", "uk",
3788 "chinese_china", "zh_CN",
3789 "chinese_taiwan", "zh_TW",
3790 NULL};
3791
3792 for (i = 0; mtable[i] != NULL; i += 2)
3793 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3794 return mtable[i + 1];
3795 return name;
3796}
3797#endif
3798
3799#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3800/*
3801 * Obtain the current messages language. Used to set the default for
3802 * 'helplang'. May return NULL or an empty string.
3803 */
3804 char_u *
3805get_mess_lang()
3806{
3807 char_u *p;
3808
3809# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3810# if defined(LC_MESSAGES)
3811 p = (char_u *)get_locale_val(LC_MESSAGES);
3812# else
3813 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003814 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3815 * and LC_MONETARY may be set differently for a Japanese working in the
3816 * US. */
3817 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003818# endif
3819# else
3820 p = mch_getenv((char_u *)"LC_ALL");
3821 if (p == NULL || *p == NUL)
3822 {
3823 p = mch_getenv((char_u *)"LC_MESSAGES");
3824 if (p == NULL || *p == NUL)
3825 p = mch_getenv((char_u *)"LANG");
3826 }
3827# endif
3828# ifdef WIN32
3829 p = gettext_lang(p);
3830# endif
3831 return p;
3832}
3833#endif
3834
Bram Moolenaardef9e822004-12-31 20:58:58 +00003835/* Complicated #if; matches with where get_mess_env() is used below. */
3836#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3837 && defined(LC_MESSAGES))) \
3838 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3839 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3840 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841static char_u *get_mess_env __ARGS((void));
3842
3843/*
3844 * Get the language used for messages from the environment.
3845 */
3846 static char_u *
3847get_mess_env()
3848{
3849 char_u *p;
3850
3851 p = mch_getenv((char_u *)"LC_ALL");
3852 if (p == NULL || *p == NUL)
3853 {
3854 p = mch_getenv((char_u *)"LC_MESSAGES");
3855 if (p == NULL || *p == NUL)
3856 {
3857 p = mch_getenv((char_u *)"LANG");
3858 if (p != NULL && VIM_ISDIGIT(*p))
3859 p = NULL; /* ignore something like "1043" */
3860# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3861 if (p == NULL || *p == NUL)
3862 p = (char_u *)get_locale_val(LC_CTYPE);
3863# endif
3864 }
3865 }
3866 return p;
3867}
3868#endif
3869
3870#if defined(FEAT_EVAL) || defined(PROTO)
3871
3872/*
3873 * Set the "v:lang" variable according to the current locale setting.
3874 * Also do "v:lc_time"and "v:ctype".
3875 */
3876 void
3877set_lang_var()
3878{
3879 char_u *loc;
3880
3881# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3882 loc = (char_u *)get_locale_val(LC_CTYPE);
3883# else
3884 /* setlocale() not supported: use the default value */
3885 loc = (char_u *)"C";
3886# endif
3887 set_vim_var_string(VV_CTYPE, loc, -1);
3888
3889 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3890 * back to LC_CTYPE if it's empty. */
3891# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
3892 loc = (char_u *)get_locale_val(LC_MESSAGES);
3893# else
3894 loc = get_mess_env();
3895# endif
3896 set_vim_var_string(VV_LANG, loc, -1);
3897
3898# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3899 loc = (char_u *)get_locale_val(LC_TIME);
3900# endif
3901 set_vim_var_string(VV_LC_TIME, loc, -1);
3902}
3903#endif
3904
3905#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3906 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
3907/*
3908 * ":language": Set the language (locale).
3909 */
3910 void
3911ex_language(eap)
3912 exarg_T *eap;
3913{
3914 char *loc;
3915 char_u *p;
3916 char_u *name;
3917 int what = LC_ALL;
3918 char *whatstr = "";
3919#ifdef LC_MESSAGES
3920# define VIM_LC_MESSAGES LC_MESSAGES
3921#else
3922# define VIM_LC_MESSAGES 6789
3923#endif
3924
3925 name = eap->arg;
3926
3927 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3928 * Allow abbreviation, but require at least 3 characters to avoid
3929 * confusion with a two letter language name "me" or "ct". */
3930 p = skiptowhite(eap->arg);
3931 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
3932 {
3933 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3934 {
3935 what = VIM_LC_MESSAGES;
3936 name = skipwhite(p);
3937 whatstr = "messages ";
3938 }
3939 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3940 {
3941 what = LC_CTYPE;
3942 name = skipwhite(p);
3943 whatstr = "ctype ";
3944 }
3945 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
3946 {
3947 what = LC_TIME;
3948 name = skipwhite(p);
3949 whatstr = "time ";
3950 }
3951 }
3952
3953 if (*name == NUL)
3954 {
3955#ifndef LC_MESSAGES
3956 if (what == VIM_LC_MESSAGES)
3957 p = get_mess_env();
3958 else
3959#endif
3960 p = (char_u *)setlocale(what, NULL);
3961 if (p == NULL || *p == NUL)
3962 p = (char_u *)"Unknown";
3963 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
3964 }
3965 else
3966 {
3967#ifndef LC_MESSAGES
3968 if (what == VIM_LC_MESSAGES)
3969 loc = "";
3970 else
3971#endif
3972 loc = setlocale(what, (char *)name);
3973 if (loc == NULL)
3974 EMSG2(_("E197: Cannot set language to \"%s\""), name);
3975 else
3976 {
3977#ifdef HAVE_NL_MSG_CAT_CNTR
3978 /* Need to do this for GNU gettext, otherwise cached translations
3979 * will be used again. */
3980 extern int _nl_msg_cat_cntr;
3981
3982 ++_nl_msg_cat_cntr;
3983#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00003984 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003985 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
3986
3987 if (what != LC_TIME)
3988 {
3989 /* Tell gettext() what to translate to. It apparently doesn't
3990 * use the currently effective locale. Also do this when
3991 * FEAT_GETTEXT isn't defined, so that shell commands use this
3992 * value. */
3993 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003994 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003996# ifdef WIN32
3997 /* Apparently MS-Windows printf() may cause a crash when
3998 * we give it 8-bit text while it's expecting text in the
3999 * current locale. This call avoids that. */
4000 setlocale(LC_CTYPE, "C");
4001# endif
4002 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003 if (what != LC_CTYPE)
4004 {
4005 char_u *mname;
4006#ifdef WIN32
4007 mname = gettext_lang(name);
4008#else
4009 mname = name;
4010#endif
4011 vim_setenv((char_u *)"LC_MESSAGES", mname);
4012#ifdef FEAT_MULTI_LANG
4013 set_helplang_default(mname);
4014#endif
4015 }
4016
4017 /* Set $LC_CTYPE, because it overrules $LANG, and
4018 * gtk_set_locale() calls setlocale() again. gnome_init()
4019 * sets $LC_CTYPE to "en_US" (that's a bug!). */
4020 if (what != VIM_LC_MESSAGES)
4021 vim_setenv((char_u *)"LC_CTYPE", name);
4022# ifdef FEAT_GUI_GTK
4023 /* Let GTK know what locale we're using. Not sure this is
4024 * really needed... */
4025 if (gui.in_use)
4026 (void)gtk_set_locale();
4027# endif
4028 }
4029
4030# ifdef FEAT_EVAL
4031 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4032 set_lang_var();
4033# endif
4034 }
4035 }
4036}
4037
4038# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4039/*
4040 * Function given to ExpandGeneric() to obtain the possible arguments of the
4041 * ":language" command.
4042 */
4043/*ARGSUSED*/
4044 char_u *
4045get_lang_arg(xp, idx)
4046 expand_T *xp;
4047 int idx;
4048{
4049 if (idx == 0)
4050 return (char_u *)"messages";
4051 if (idx == 1)
4052 return (char_u *)"ctype";
4053 if (idx == 2)
4054 return (char_u *)"time";
4055 return NULL;
4056}
4057# endif
4058
4059#endif