blob: 39ed496fc7a491a7033bfa9670e3fe66b0b2551f [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaarc236c162008-07-13 17:41:49 +000014#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
Bram Moolenaar8c8de832008-06-24 22:58:06 +000015# include "vimio.h" /* for mch_open(), must be before vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +000016#endif
17
18#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000019#include "version.h"
20
21static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
22
Bram Moolenaar05159a02005-02-26 23:04:13 +000023#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000024/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000025 * For Unix also store the dev/ino, so that we don't have to stat() each
26 * script when going through the list. */
27typedef struct scriptitem_S
28{
29 char_u *sn_name;
30# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000031 int sn_dev_valid;
32 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000033 ino_t sn_ino;
34# endif
35# ifdef FEAT_PROFILE
36 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000037 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000038 proftime_T sn_pr_child; /* time set when going into first child */
39 int sn_pr_nest; /* nesting for sn_pr_child */
40 /* profiling the script as a whole */
41 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000042 proftime_T sn_pr_total; /* time spent in script + children */
43 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000044 proftime_T sn_pr_start; /* time at script start */
45 proftime_T sn_pr_children; /* time in children after script start */
46 /* profiling the script per line */
47 garray_T sn_prl_ga; /* things stored for every line */
48 proftime_T sn_prl_start; /* start time for current line */
49 proftime_T sn_prl_children; /* time spent in children for this line */
50 proftime_T sn_prl_wait; /* wait start time for current line */
51 int sn_prl_idx; /* index of line being timed; -1 if none */
52 int sn_prl_execed; /* line being timed was executed */
53# endif
54} scriptitem_T;
55
56static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
57#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
58
59# ifdef FEAT_PROFILE
60/* Struct used in sn_prl_ga for every line of a script. */
61typedef struct sn_prl_S
62{
63 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000064 proftime_T sn_prl_total; /* time spent in a line + children */
65 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000066} sn_prl_T;
67
68# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
69# endif
70#endif
71
Bram Moolenaar071d4272004-06-13 20:20:40 +000072#if defined(FEAT_EVAL) || defined(PROTO)
73static int debug_greedy = FALSE; /* batch mode debugging: don't save
74 and restore typeahead. */
75
76/*
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
79 */
80 void
81do_debug(cmd)
82 char_u *cmd;
83{
84 int save_msg_scroll = msg_scroll;
85 int save_State = State;
86 int save_did_emsg = did_emsg;
87 int save_cmd_silent = cmd_silent;
88 int save_msg_silent = msg_silent;
89 int save_emsg_silent = emsg_silent;
90 int save_redir_off = redir_off;
91 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000092 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000093 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094# ifdef FEAT_EX_EXTRA
95 int save_ex_normal_busy;
96# endif
97 int n;
98 char_u *cmdline = NULL;
99 char_u *p;
100 char *tail = NULL;
101 static int last_cmd = 0;
102#define CMD_CONT 1
103#define CMD_NEXT 2
104#define CMD_STEP 3
105#define CMD_FINISH 4
106#define CMD_QUIT 5
107#define CMD_INTERRUPT 6
108
109#ifdef ALWAYS_USE_GUI
110 /* Can't do this when there is no terminal for input/output. */
111 if (!gui.in_use)
112 {
113 /* Break as soon as possible. */
114 debug_break_level = 9999;
115 return;
116 }
117#endif
118
119 /* Make sure we are in raw mode and start termcap mode. Might have side
120 * effects... */
121 settmode(TMODE_RAW);
122 starttermcap();
123
124 ++RedrawingDisabled; /* don't redisplay the window */
125 ++no_wait_return; /* don't wait for return */
126 did_emsg = FALSE; /* don't use error from debugged stuff */
127 cmd_silent = FALSE; /* display commands */
128 msg_silent = FALSE; /* display messages */
129 emsg_silent = FALSE; /* display error messages */
130 redir_off = TRUE; /* don't redirect debug commands */
131
132 State = NORMAL;
133#ifdef FEAT_SNIFF
134 want_sniff_request = 0; /* No K_SNIFF wanted */
135#endif
136
137 if (!debug_did_msg)
138 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
139 if (sourcing_name != NULL)
140 msg(sourcing_name);
141 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000142 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000144 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145
146 /*
147 * Repeat getting a command and executing it.
148 */
149 for (;;)
150 {
151 msg_scroll = TRUE;
152 need_wait_return = FALSE;
153#ifdef FEAT_SNIFF
154 ProcessSniffRequests();
155#endif
156 /* Save the current typeahead buffer and replace it with an empty one.
157 * This makes sure we get input from the user here and don't interfere
158 * with the commands being executed. Reset "ex_normal_busy" to avoid
159 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000160 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161# ifdef FEAT_EX_EXTRA
162 save_ex_normal_busy = ex_normal_busy;
163 ex_normal_busy = 0;
164# endif
165 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000166 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000168 typeahead_saved = TRUE;
169 save_ignore_script = ignore_script;
170 ignore_script = TRUE;
171 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000173 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000175 if (typeahead_saved)
176 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000178 ignore_script = save_ignore_script;
179 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180# ifdef FEAT_EX_EXTRA
181 ex_normal_busy = save_ex_normal_busy;
182# endif
183
184 cmdline_row = msg_row;
185 if (cmdline != NULL)
186 {
187 /* If this is a debug command, set "last_cmd".
188 * If not, reset "last_cmd".
189 * For a blank line use previous command. */
190 p = skipwhite(cmdline);
191 if (*p != NUL)
192 {
193 switch (*p)
194 {
195 case 'c': last_cmd = CMD_CONT;
196 tail = "ont";
197 break;
198 case 'n': last_cmd = CMD_NEXT;
199 tail = "ext";
200 break;
201 case 's': last_cmd = CMD_STEP;
202 tail = "tep";
203 break;
204 case 'f': last_cmd = CMD_FINISH;
205 tail = "inish";
206 break;
207 case 'q': last_cmd = CMD_QUIT;
208 tail = "uit";
209 break;
210 case 'i': last_cmd = CMD_INTERRUPT;
211 tail = "nterrupt";
212 break;
213 default: last_cmd = 0;
214 }
215 if (last_cmd != 0)
216 {
217 /* Check that the tail matches. */
218 ++p;
219 while (*p != NUL && *p == *tail)
220 {
221 ++p;
222 ++tail;
223 }
224 if (ASCII_ISALPHA(*p))
225 last_cmd = 0;
226 }
227 }
228
229 if (last_cmd != 0)
230 {
231 /* Execute debug command: decided where to break next and
232 * return. */
233 switch (last_cmd)
234 {
235 case CMD_CONT:
236 debug_break_level = -1;
237 break;
238 case CMD_NEXT:
239 debug_break_level = ex_nesting_level;
240 break;
241 case CMD_STEP:
242 debug_break_level = 9999;
243 break;
244 case CMD_FINISH:
245 debug_break_level = ex_nesting_level - 1;
246 break;
247 case CMD_QUIT:
248 got_int = TRUE;
249 debug_break_level = -1;
250 break;
251 case CMD_INTERRUPT:
252 got_int = TRUE;
253 debug_break_level = 9999;
254 /* Do not repeat ">interrupt" cmd, continue stepping. */
255 last_cmd = CMD_STEP;
256 break;
257 }
258 break;
259 }
260
261 /* don't debug this command */
262 n = debug_break_level;
263 debug_break_level = -1;
264 (void)do_cmdline(cmdline, getexline, NULL,
265 DOCMD_VERBOSE|DOCMD_EXCRESET);
266 debug_break_level = n;
267
268 vim_free(cmdline);
269 }
270 lines_left = Rows - 1;
271 }
272 vim_free(cmdline);
273
274 --RedrawingDisabled;
275 --no_wait_return;
276 redraw_all_later(NOT_VALID);
277 need_wait_return = FALSE;
278 msg_scroll = save_msg_scroll;
279 lines_left = Rows - 1;
280 State = save_State;
281 did_emsg = save_did_emsg;
282 cmd_silent = save_cmd_silent;
283 msg_silent = save_msg_silent;
284 emsg_silent = save_emsg_silent;
285 redir_off = save_redir_off;
286
287 /* Only print the message again when typing a command before coming back
288 * here. */
289 debug_did_msg = TRUE;
290}
291
292/*
293 * ":debug".
294 */
295 void
296ex_debug(eap)
297 exarg_T *eap;
298{
299 int debug_break_level_save = debug_break_level;
300
301 debug_break_level = 9999;
302 do_cmdline_cmd(eap->arg);
303 debug_break_level = debug_break_level_save;
304}
305
306static char_u *debug_breakpoint_name = NULL;
307static linenr_T debug_breakpoint_lnum;
308
309/*
310 * When debugging or a breakpoint is set on a skipped command, no debug prompt
311 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
312 * debug_skipped_name is then set to the source name in the breakpoint case. If
313 * a skipped command decides itself that a debug prompt should be displayed, it
314 * can do so by calling dbg_check_skipped().
315 */
316static int debug_skipped;
317static char_u *debug_skipped_name;
318
319/*
320 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
321 * at or below the break level. But only when the line is actually
322 * executed. Return TRUE and set breakpoint_name for skipped commands that
323 * decide to execute something themselves.
324 * Called from do_one_cmd() before executing a command.
325 */
326 void
327dbg_check_breakpoint(eap)
328 exarg_T *eap;
329{
330 char_u *p;
331
332 debug_skipped = FALSE;
333 if (debug_breakpoint_name != NULL)
334 {
335 if (!eap->skip)
336 {
337 /* replace K_SNR with "<SNR>" */
338 if (debug_breakpoint_name[0] == K_SPECIAL
339 && debug_breakpoint_name[1] == KS_EXTRA
340 && debug_breakpoint_name[2] == (int)KE_SNR)
341 p = (char_u *)"<SNR>";
342 else
343 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000344 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
345 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000346 debug_breakpoint_name + (*p == NUL ? 0 : 3),
347 (long)debug_breakpoint_lnum);
348 debug_breakpoint_name = NULL;
349 do_debug(eap->cmd);
350 }
351 else
352 {
353 debug_skipped = TRUE;
354 debug_skipped_name = debug_breakpoint_name;
355 debug_breakpoint_name = NULL;
356 }
357 }
358 else if (ex_nesting_level <= debug_break_level)
359 {
360 if (!eap->skip)
361 do_debug(eap->cmd);
362 else
363 {
364 debug_skipped = TRUE;
365 debug_skipped_name = NULL;
366 }
367 }
368}
369
370/*
371 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
372 * set. Return TRUE when the debug mode is entered this time.
373 */
374 int
375dbg_check_skipped(eap)
376 exarg_T *eap;
377{
378 int prev_got_int;
379
380 if (debug_skipped)
381 {
382 /*
383 * Save the value of got_int and reset it. We don't want a previous
384 * interruption cause flushing the input buffer.
385 */
386 prev_got_int = got_int;
387 got_int = FALSE;
388 debug_breakpoint_name = debug_skipped_name;
389 /* eap->skip is TRUE */
390 eap->skip = FALSE;
391 (void)dbg_check_breakpoint(eap);
392 eap->skip = TRUE;
393 got_int |= prev_got_int;
394 return TRUE;
395 }
396 return FALSE;
397}
398
399/*
400 * The list of breakpoints: dbg_breakp.
401 * This is a grow-array of structs.
402 */
403struct debuggy
404{
405 int dbg_nr; /* breakpoint number */
406 int dbg_type; /* DBG_FUNC or DBG_FILE */
407 char_u *dbg_name; /* function or file name */
408 regprog_T *dbg_prog; /* regexp program */
409 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000410 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000411};
412
413static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000414#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
415#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416static int last_breakp = 0; /* nr of last defined breakpoint */
417
Bram Moolenaar05159a02005-02-26 23:04:13 +0000418#ifdef FEAT_PROFILE
419/* Profiling uses file and func names similar to breakpoints. */
420static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
421#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422#define DBG_FUNC 1
423#define DBG_FILE 2
424
Bram Moolenaar05159a02005-02-26 23:04:13 +0000425static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
426static 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 +0000427
428/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000429 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
430 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
431 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 * Returns FAIL for failure.
433 */
434 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000435dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000436 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000437 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438{
439 char_u *p = arg;
440 char_u *q;
441 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000442 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443
Bram Moolenaar05159a02005-02-26 23:04:13 +0000444 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000445 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000446 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000447
448 /* Find "func" or "file". */
449 if (STRNCMP(p, "func", 4) == 0)
450 bp->dbg_type = DBG_FUNC;
451 else if (STRNCMP(p, "file", 4) == 0)
452 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000453 else if (
454#ifdef FEAT_PROFILE
455 gap != &prof_ga &&
456#endif
457 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000458 {
459 if (curbuf->b_ffname == NULL)
460 {
461 EMSG(_(e_noname));
462 return FAIL;
463 }
464 bp->dbg_type = DBG_FILE;
465 here = TRUE;
466 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000467 else
468 {
469 EMSG2(_(e_invarg2), p);
470 return FAIL;
471 }
472 p = skipwhite(p + 4);
473
474 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000475 if (here)
476 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000477 else if (
478#ifdef FEAT_PROFILE
479 gap != &prof_ga &&
480#endif
481 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000482 {
483 bp->dbg_lnum = getdigits(&p);
484 p = skipwhite(p);
485 }
486 else
487 bp->dbg_lnum = 0;
488
489 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000490 if ((!here && *p == NUL)
491 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000492 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
493 {
494 EMSG2(_(e_invarg2), arg);
495 return FAIL;
496 }
497
498 if (bp->dbg_type == DBG_FUNC)
499 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000500 else if (here)
501 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000502 else
503 {
504 /* Expand the file name in the same way as do_source(). This means
505 * doing it twice, so that $DIR/file gets expanded when $DIR is
506 * "~/dir". */
507#ifdef RISCOS
508 q = mch_munge_fname(p);
509#else
510 q = expand_env_save(p);
511#endif
512 if (q == NULL)
513 return FAIL;
514#ifdef RISCOS
515 p = mch_munge_fname(q);
516#else
517 p = expand_env_save(q);
518#endif
519 vim_free(q);
520 if (p == NULL)
521 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000522 if (*p != '*')
523 {
524 bp->dbg_name = fix_fname(p);
525 vim_free(p);
526 }
527 else
528 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529 }
530
531 if (bp->dbg_name == NULL)
532 return FAIL;
533 return OK;
534}
535
536/*
537 * ":breakadd".
538 */
539 void
540ex_breakadd(eap)
541 exarg_T *eap;
542{
543 struct debuggy *bp;
544 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000545 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546
Bram Moolenaar05159a02005-02-26 23:04:13 +0000547 gap = &dbg_breakp;
548#ifdef FEAT_PROFILE
549 if (eap->cmdidx == CMD_profile)
550 gap = &prof_ga;
551#endif
552
553 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000555 bp = &DEBUGGY(gap, gap->ga_len);
556 bp->dbg_forceit = eap->forceit;
557
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
559 if (pat != NULL)
560 {
561 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
562 vim_free(pat);
563 }
564 if (pat == NULL || bp->dbg_prog == NULL)
565 vim_free(bp->dbg_name);
566 else
567 {
568 if (bp->dbg_lnum == 0) /* default line number is 1 */
569 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000570#ifdef FEAT_PROFILE
571 if (eap->cmdidx != CMD_profile)
572#endif
573 {
574 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
575 ++debug_tick;
576 }
577 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578 }
579 }
580}
581
582/*
583 * ":debuggreedy".
584 */
585 void
586ex_debuggreedy(eap)
587 exarg_T *eap;
588{
589 if (eap->addr_count == 0 || eap->line2 != 0)
590 debug_greedy = TRUE;
591 else
592 debug_greedy = FALSE;
593}
594
595/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000596 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 */
598 void
599ex_breakdel(eap)
600 exarg_T *eap;
601{
602 struct debuggy *bp, *bpi;
603 int nr;
604 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000605 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606 int i;
607 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000608 garray_T *gap;
609
610 gap = &dbg_breakp;
611#ifdef FEAT_PROFILE
612 if (eap->cmdidx == CMD_profdel)
613 gap = &prof_ga;
614#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615
616 if (vim_isdigit(*eap->arg))
617 {
618 /* ":breakdel {nr}" */
619 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000620 for (i = 0; i < gap->ga_len; ++i)
621 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 {
623 todel = i;
624 break;
625 }
626 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000627 else if (*eap->arg == '*')
628 {
629 todel = 0;
630 del_all = TRUE;
631 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 else
633 {
634 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000635 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000636 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000637 bp = &DEBUGGY(gap, gap->ga_len);
638 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000639 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000640 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641 if (bp->dbg_type == bpi->dbg_type
642 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
643 && (bp->dbg_lnum == bpi->dbg_lnum
644 || (bp->dbg_lnum == 0
645 && (best_lnum == 0
646 || bpi->dbg_lnum < best_lnum))))
647 {
648 todel = i;
649 best_lnum = bpi->dbg_lnum;
650 }
651 }
652 vim_free(bp->dbg_name);
653 }
654
655 if (todel < 0)
656 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
657 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000658 {
659 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000660 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000661 vim_free(DEBUGGY(gap, todel).dbg_name);
662 vim_free(DEBUGGY(gap, todel).dbg_prog);
663 --gap->ga_len;
664 if (todel < gap->ga_len)
665 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
666 (gap->ga_len - todel) * sizeof(struct debuggy));
667#ifdef FEAT_PROFILE
668 if (eap->cmdidx == CMD_breakdel)
669#endif
670 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000671 if (!del_all)
672 break;
673 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000674
675 /* If all breakpoints were removed clear the array. */
676 if (gap->ga_len == 0)
677 ga_clear(gap);
678 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679}
680
681/*
682 * ":breaklist".
683 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000684 void
685ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000686 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687{
688 struct debuggy *bp;
689 int i;
690
691 if (dbg_breakp.ga_len == 0)
692 MSG(_("No breakpoints defined"));
693 else
694 for (i = 0; i < dbg_breakp.ga_len; ++i)
695 {
696 bp = &BREAKP(i);
697 smsg((char_u *)_("%3d %s %s line %ld"),
698 bp->dbg_nr,
699 bp->dbg_type == DBG_FUNC ? "func" : "file",
700 bp->dbg_name,
701 (long)bp->dbg_lnum);
702 }
703}
704
705/*
706 * Find a breakpoint for a function or sourced file.
707 * Returns line number at which to break; zero when no matching breakpoint.
708 */
709 linenr_T
710dbg_find_breakpoint(file, fname, after)
711 int file; /* TRUE for a file, FALSE for a function */
712 char_u *fname; /* file or function name */
713 linenr_T after; /* after this line number */
714{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000715 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
716}
717
718#if defined(FEAT_PROFILE) || defined(PROTO)
719/*
720 * Return TRUE if profiling is on for a function or sourced file.
721 */
722 int
723has_profiling(file, fname, fp)
724 int file; /* TRUE for a file, FALSE for a function */
725 char_u *fname; /* file or function name */
726 int *fp; /* return: forceit */
727{
728 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
729 != (linenr_T)0);
730}
731#endif
732
733/*
734 * Common code for dbg_find_breakpoint() and has_profiling().
735 */
736 static linenr_T
737debuggy_find(file, fname, after, gap, fp)
738 int file; /* TRUE for a file, FALSE for a function */
739 char_u *fname; /* file or function name */
740 linenr_T after; /* after this line number */
741 garray_T *gap; /* either &dbg_breakp or &prof_ga */
742 int *fp; /* if not NULL: return forceit */
743{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000744 struct debuggy *bp;
745 int i;
746 linenr_T lnum = 0;
747 regmatch_T regmatch;
748 char_u *name = fname;
749 int prev_got_int;
750
Bram Moolenaar05159a02005-02-26 23:04:13 +0000751 /* Return quickly when there are no breakpoints. */
752 if (gap->ga_len == 0)
753 return (linenr_T)0;
754
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755 /* Replace K_SNR in function name with "<SNR>". */
756 if (!file && fname[0] == K_SPECIAL)
757 {
758 name = alloc((unsigned)STRLEN(fname) + 3);
759 if (name == NULL)
760 name = fname;
761 else
762 {
763 STRCPY(name, "<SNR>");
764 STRCPY(name + 5, fname + 3);
765 }
766 }
767
Bram Moolenaar05159a02005-02-26 23:04:13 +0000768 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000770 /* Skip entries that are not useful or are for a line that is beyond
771 * an already found breakpoint. */
772 bp = &DEBUGGY(gap, i);
773 if (((bp->dbg_type == DBG_FILE) == file && (
774#ifdef FEAT_PROFILE
775 gap == &prof_ga ||
776#endif
777 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778 {
779 regmatch.regprog = bp->dbg_prog;
780 regmatch.rm_ic = FALSE;
781 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000782 * Save the value of got_int and reset it. We don't want a
783 * previous interruption cancel matching, only hitting CTRL-C
784 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 */
786 prev_got_int = got_int;
787 got_int = FALSE;
788 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000789 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000791 if (fp != NULL)
792 *fp = bp->dbg_forceit;
793 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794 got_int |= prev_got_int;
795 }
796 }
797 if (name != fname)
798 vim_free(name);
799
800 return lnum;
801}
802
803/*
804 * Called when a breakpoint was encountered.
805 */
806 void
807dbg_breakpoint(name, lnum)
808 char_u *name;
809 linenr_T lnum;
810{
811 /* We need to check if this line is actually executed in do_one_cmd() */
812 debug_breakpoint_name = name;
813 debug_breakpoint_lnum = lnum;
814}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000815
816
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000817# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000818/*
819 * Store the current time in "tm".
820 */
821 void
822profile_start(tm)
823 proftime_T *tm;
824{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000825# ifdef WIN3264
826 QueryPerformanceCounter(tm);
827# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000828 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000829# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000830}
831
832/*
833 * Compute the elapsed time from "tm" till now and store in "tm".
834 */
835 void
836profile_end(tm)
837 proftime_T *tm;
838{
839 proftime_T now;
840
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000841# ifdef WIN3264
842 QueryPerformanceCounter(&now);
843 tm->QuadPart = now.QuadPart - tm->QuadPart;
844# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845 gettimeofday(&now, NULL);
846 tm->tv_usec = now.tv_usec - tm->tv_usec;
847 tm->tv_sec = now.tv_sec - tm->tv_sec;
848 if (tm->tv_usec < 0)
849 {
850 tm->tv_usec += 1000000;
851 --tm->tv_sec;
852 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000853# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000854}
855
856/*
857 * Subtract the time "tm2" from "tm".
858 */
859 void
860profile_sub(tm, tm2)
861 proftime_T *tm, *tm2;
862{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000863# ifdef WIN3264
864 tm->QuadPart -= tm2->QuadPart;
865# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000866 tm->tv_usec -= tm2->tv_usec;
867 tm->tv_sec -= tm2->tv_sec;
868 if (tm->tv_usec < 0)
869 {
870 tm->tv_usec += 1000000;
871 --tm->tv_sec;
872 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000873# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000874}
875
876/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000877 * Return a string that represents the time in "tm".
878 * Uses a static buffer!
879 */
880 char *
881profile_msg(tm)
882 proftime_T *tm;
883{
884 static char buf[50];
885
886# ifdef WIN3264
887 LARGE_INTEGER fr;
888
889 QueryPerformanceFrequency(&fr);
890 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
891# else
892 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000893# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000894 return buf;
895}
896
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000897/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000898 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000899 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000900 void
901profile_setlimit(msec, tm)
902 long msec;
903 proftime_T *tm;
904{
905 if (msec <= 0) /* no limit */
906 profile_zero(tm);
907 else
908 {
909# ifdef WIN3264
910 LARGE_INTEGER fr;
911
912 QueryPerformanceCounter(tm);
913 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000914 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000915# else
916 long usec;
917
918 gettimeofday(tm, NULL);
919 usec = (long)tm->tv_usec + (long)msec * 1000;
920 tm->tv_usec = usec % 1000000L;
921 tm->tv_sec += usec / 1000000L;
922# endif
923 }
924}
925
926/*
927 * Return TRUE if the current time is past "tm".
928 */
929 int
930profile_passed_limit(tm)
931 proftime_T *tm;
932{
933 proftime_T now;
934
935# ifdef WIN3264
936 if (tm->QuadPart == 0) /* timer was not set */
937 return FALSE;
938 QueryPerformanceCounter(&now);
939 return (now.QuadPart > tm->QuadPart);
940# else
941 if (tm->tv_sec == 0) /* timer was not set */
942 return FALSE;
943 gettimeofday(&now, NULL);
944 return (now.tv_sec > tm->tv_sec
945 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
946# endif
947}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000948
949/*
950 * Set the time in "tm" to zero.
951 */
952 void
953profile_zero(tm)
954 proftime_T *tm;
955{
956# ifdef WIN3264
957 tm->QuadPart = 0;
958# else
959 tm->tv_usec = 0;
960 tm->tv_sec = 0;
961# endif
962}
963
Bram Moolenaar76929292008-01-06 19:07:36 +0000964# endif /* FEAT_PROFILE || FEAT_RELTIME */
965
966# if defined(FEAT_PROFILE) || defined(PROTO)
967/*
968 * Functions for profiling.
969 */
970static void script_do_profile __ARGS((scriptitem_T *si));
971static void script_dump_profile __ARGS((FILE *fd));
972static proftime_T prof_wait_time;
973
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000974/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000975 * Add the time "tm2" to "tm".
976 */
977 void
978profile_add(tm, tm2)
979 proftime_T *tm, *tm2;
980{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000981# ifdef WIN3264
982 tm->QuadPart += tm2->QuadPart;
983# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000984 tm->tv_usec += tm2->tv_usec;
985 tm->tv_sec += tm2->tv_sec;
986 if (tm->tv_usec >= 1000000)
987 {
988 tm->tv_usec -= 1000000;
989 ++tm->tv_sec;
990 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000991# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000992}
993
994/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000995 * Add the "self" time from the total time and the children's time.
996 */
997 void
998profile_self(self, total, children)
999 proftime_T *self, *total, *children;
1000{
1001 /* Check that the result won't be negative. Can happen with recursive
1002 * calls. */
1003#ifdef WIN3264
1004 if (total->QuadPart <= children->QuadPart)
1005 return;
1006#else
1007 if (total->tv_sec < children->tv_sec
1008 || (total->tv_sec == children->tv_sec
1009 && total->tv_usec <= children->tv_usec))
1010 return;
1011#endif
1012 profile_add(self, total);
1013 profile_sub(self, children);
1014}
1015
1016/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001017 * Get the current waittime.
1018 */
1019 void
1020profile_get_wait(tm)
1021 proftime_T *tm;
1022{
1023 *tm = prof_wait_time;
1024}
1025
1026/*
1027 * Subtract the passed waittime since "tm" from "tma".
1028 */
1029 void
1030profile_sub_wait(tm, tma)
1031 proftime_T *tm, *tma;
1032{
1033 proftime_T tm3 = prof_wait_time;
1034
1035 profile_sub(&tm3, tm);
1036 profile_sub(tma, &tm3);
1037}
1038
1039/*
1040 * Return TRUE if "tm1" and "tm2" are equal.
1041 */
1042 int
1043profile_equal(tm1, tm2)
1044 proftime_T *tm1, *tm2;
1045{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001046# ifdef WIN3264
1047 return (tm1->QuadPart == tm2->QuadPart);
1048# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001049 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001050# endif
1051}
1052
1053/*
1054 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1055 */
1056 int
1057profile_cmp(tm1, tm2)
1058 proftime_T *tm1, *tm2;
1059{
1060# ifdef WIN3264
1061 return (int)(tm2->QuadPart - tm1->QuadPart);
1062# else
1063 if (tm1->tv_sec == tm2->tv_sec)
1064 return tm2->tv_usec - tm1->tv_usec;
1065 return tm2->tv_sec - tm1->tv_sec;
1066# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001067}
1068
Bram Moolenaar05159a02005-02-26 23:04:13 +00001069static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001070static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001071
1072/*
1073 * ":profile cmd args"
1074 */
1075 void
1076ex_profile(eap)
1077 exarg_T *eap;
1078{
1079 char_u *e;
1080 int len;
1081
1082 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001083 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001084 e = skipwhite(e);
1085
1086 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1087 {
1088 vim_free(profile_fname);
1089 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001090 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001091 profile_zero(&prof_wait_time);
1092 set_vim_var_nr(VV_PROFILING, 1L);
1093 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001094 else if (do_profiling == PROF_NONE)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001095 EMSG(_("E750: First use :profile start <fname>"));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001096 else if (STRCMP(eap->arg, "pause") == 0)
1097 {
1098 if (do_profiling == PROF_YES)
1099 profile_start(&pause_time);
1100 do_profiling = PROF_PAUSED;
1101 }
1102 else if (STRCMP(eap->arg, "continue") == 0)
1103 {
1104 if (do_profiling == PROF_PAUSED)
1105 {
1106 profile_end(&pause_time);
1107 profile_add(&prof_wait_time, &pause_time);
1108 }
1109 do_profiling = PROF_YES;
1110 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001111 else
1112 {
1113 /* The rest is similar to ":breakadd". */
1114 ex_breakadd(eap);
1115 }
1116}
1117
1118/*
1119 * Dump the profiling info.
1120 */
1121 void
1122profile_dump()
1123{
1124 FILE *fd;
1125
1126 if (profile_fname != NULL)
1127 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001128 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001129 if (fd == NULL)
1130 EMSG2(_(e_notopen), profile_fname);
1131 else
1132 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001133 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001134 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001135 fclose(fd);
1136 }
1137 }
1138}
1139
1140/*
1141 * Start profiling script "fp".
1142 */
1143 static void
1144script_do_profile(si)
1145 scriptitem_T *si;
1146{
1147 si->sn_pr_count = 0;
1148 profile_zero(&si->sn_pr_total);
1149 profile_zero(&si->sn_pr_self);
1150
1151 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1152 si->sn_prl_idx = -1;
1153 si->sn_prof_on = TRUE;
1154 si->sn_pr_nest = 0;
1155}
1156
1157/*
1158 * save time when starting to invoke another script or function.
1159 */
1160 void
1161script_prof_save(tm)
1162 proftime_T *tm; /* place to store wait time */
1163{
1164 scriptitem_T *si;
1165
1166 if (current_SID > 0 && current_SID <= script_items.ga_len)
1167 {
1168 si = &SCRIPT_ITEM(current_SID);
1169 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1170 profile_start(&si->sn_pr_child);
1171 }
1172 profile_get_wait(tm);
1173}
1174
1175/*
1176 * Count time spent in children after invoking another script or function.
1177 */
1178 void
1179script_prof_restore(tm)
1180 proftime_T *tm;
1181{
1182 scriptitem_T *si;
1183
1184 if (current_SID > 0 && current_SID <= script_items.ga_len)
1185 {
1186 si = &SCRIPT_ITEM(current_SID);
1187 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1188 {
1189 profile_end(&si->sn_pr_child);
1190 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1191 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1192 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1193 }
1194 }
1195}
1196
1197static proftime_T inchar_time;
1198
1199/*
1200 * Called when starting to wait for the user to type a character.
1201 */
1202 void
1203prof_inchar_enter()
1204{
1205 profile_start(&inchar_time);
1206}
1207
1208/*
1209 * Called when finished waiting for the user to type a character.
1210 */
1211 void
1212prof_inchar_exit()
1213{
1214 profile_end(&inchar_time);
1215 profile_add(&prof_wait_time, &inchar_time);
1216}
1217
1218/*
1219 * Dump the profiling results for all scripts in file "fd".
1220 */
1221 static void
1222script_dump_profile(fd)
1223 FILE *fd;
1224{
1225 int id;
1226 scriptitem_T *si;
1227 int i;
1228 FILE *sfd;
1229 sn_prl_T *pp;
1230
1231 for (id = 1; id <= script_items.ga_len; ++id)
1232 {
1233 si = &SCRIPT_ITEM(id);
1234 if (si->sn_prof_on)
1235 {
1236 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1237 if (si->sn_pr_count == 1)
1238 fprintf(fd, "Sourced 1 time\n");
1239 else
1240 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1241 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1242 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1243 fprintf(fd, "\n");
1244 fprintf(fd, "count total (s) self (s)\n");
1245
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001246 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001247 if (sfd == NULL)
1248 fprintf(fd, "Cannot open file!\n");
1249 else
1250 {
1251 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1252 {
1253 if (vim_fgets(IObuff, IOSIZE, sfd))
1254 break;
1255 pp = &PRL_ITEM(si, i);
1256 if (pp->snp_count > 0)
1257 {
1258 fprintf(fd, "%5d ", pp->snp_count);
1259 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1260 fprintf(fd, " ");
1261 else
1262 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1263 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1264 }
1265 else
1266 fprintf(fd, " ");
1267 fprintf(fd, "%s", IObuff);
1268 }
1269 fclose(sfd);
1270 }
1271 fprintf(fd, "\n");
1272 }
1273 }
1274}
1275
1276/*
1277 * Return TRUE when a function defined in the current script should be
1278 * profiled.
1279 */
1280 int
1281prof_def_func()
1282{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001283 if (current_SID > 0)
1284 return SCRIPT_ITEM(current_SID).sn_pr_force;
1285 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001286}
1287
1288# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289#endif
1290
1291/*
1292 * If 'autowrite' option set, try to write the file.
1293 * Careful: autocommands may make "buf" invalid!
1294 *
1295 * return FAIL for failure, OK otherwise
1296 */
1297 int
1298autowrite(buf, forceit)
1299 buf_T *buf;
1300 int forceit;
1301{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001302 int r;
1303
Bram Moolenaar071d4272004-06-13 20:20:40 +00001304 if (!(p_aw || p_awa) || !p_write
1305#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001306 /* never autowrite a "nofile" or "nowrite" buffer */
1307 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001309 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001311 r = buf_write_all(buf, forceit);
1312
1313 /* Writing may succeed but the buffer still changed, e.g., when there is a
1314 * conversion error. We do want to return FAIL then. */
1315 if (buf_valid(buf) && bufIsChanged(buf))
1316 r = FAIL;
1317 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001318}
1319
1320/*
1321 * flush all buffers, except the ones that are readonly
1322 */
1323 void
1324autowrite_all()
1325{
1326 buf_T *buf;
1327
1328 if (!(p_aw || p_awa) || !p_write)
1329 return;
1330 for (buf = firstbuf; buf; buf = buf->b_next)
1331 if (bufIsChanged(buf) && !buf->b_p_ro)
1332 {
1333 (void)buf_write_all(buf, FALSE);
1334#ifdef FEAT_AUTOCMD
1335 /* an autocommand may have deleted the buffer */
1336 if (!buf_valid(buf))
1337 buf = firstbuf;
1338#endif
1339 }
1340}
1341
1342/*
1343 * return TRUE if buffer was changed and cannot be abandoned.
1344 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001345 int
1346check_changed(buf, checkaw, mult_win, forceit, allbuf)
1347 buf_T *buf;
1348 int checkaw; /* do autowrite if buffer was changed */
1349 int mult_win; /* check also when several wins for the buf */
1350 int forceit;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001351 int allbuf UNUSED; /* may write all buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001352{
1353 if ( !forceit
1354 && bufIsChanged(buf)
1355 && (mult_win || buf->b_nwindows <= 1)
1356 && (!checkaw || autowrite(buf, forceit) == FAIL))
1357 {
1358#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1359 if ((p_confirm || cmdmod.confirm) && p_write)
1360 {
1361 buf_T *buf2;
1362 int count = 0;
1363
1364 if (allbuf)
1365 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1366 if (bufIsChanged(buf2)
1367 && (buf2->b_ffname != NULL
1368# ifdef FEAT_BROWSE
1369 || cmdmod.browse
1370# endif
1371 ))
1372 ++count;
1373# ifdef FEAT_AUTOCMD
1374 if (!buf_valid(buf))
1375 /* Autocommand deleted buffer, oops! It's not changed now. */
1376 return FALSE;
1377# endif
1378 dialog_changed(buf, count > 1);
1379# ifdef FEAT_AUTOCMD
1380 if (!buf_valid(buf))
1381 /* Autocommand deleted buffer, oops! It's not changed now. */
1382 return FALSE;
1383# endif
1384 return bufIsChanged(buf);
1385 }
1386#endif
1387 EMSG(_(e_nowrtmsg));
1388 return TRUE;
1389 }
1390 return FALSE;
1391}
1392
1393#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1394
1395#if defined(FEAT_BROWSE) || defined(PROTO)
1396/*
1397 * When wanting to write a file without a file name, ask the user for a name.
1398 */
1399 void
1400browse_save_fname(buf)
1401 buf_T *buf;
1402{
1403 if (buf->b_fname == NULL)
1404 {
1405 char_u *fname;
1406
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001407 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1408 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001409 if (fname != NULL)
1410 {
1411 if (setfname(buf, fname, NULL, TRUE) == OK)
1412 buf->b_flags |= BF_NOTEDITED;
1413 vim_free(fname);
1414 }
1415 }
1416}
1417#endif
1418
1419/*
1420 * Ask the user what to do when abondoning a changed buffer.
1421 * Must check 'write' option first!
1422 */
1423 void
1424dialog_changed(buf, checkall)
1425 buf_T *buf;
1426 int checkall; /* may abandon all changed buffers */
1427{
1428 char_u buff[IOSIZE];
1429 int ret;
1430 buf_T *buf2;
1431
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001432 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001433 (buf->b_fname != NULL) ?
1434 buf->b_fname : (char_u *)_("Untitled"));
1435 if (checkall)
1436 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1437 else
1438 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1439
1440 if (ret == VIM_YES)
1441 {
1442#ifdef FEAT_BROWSE
1443 /* May get file name, when there is none */
1444 browse_save_fname(buf);
1445#endif
1446 if (buf->b_fname != NULL) /* didn't hit Cancel */
1447 (void)buf_write_all(buf, FALSE);
1448 }
1449 else if (ret == VIM_NO)
1450 {
1451 unchanged(buf, TRUE);
1452 }
1453 else if (ret == VIM_ALL)
1454 {
1455 /*
1456 * Write all modified files that can be written.
1457 * Skip readonly buffers, these need to be confirmed
1458 * individually.
1459 */
1460 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1461 {
1462 if (bufIsChanged(buf2)
1463 && (buf2->b_ffname != NULL
1464#ifdef FEAT_BROWSE
1465 || cmdmod.browse
1466#endif
1467 )
1468 && !buf2->b_p_ro)
1469 {
1470#ifdef FEAT_BROWSE
1471 /* May get file name, when there is none */
1472 browse_save_fname(buf2);
1473#endif
1474 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1475 (void)buf_write_all(buf2, FALSE);
1476#ifdef FEAT_AUTOCMD
1477 /* an autocommand may have deleted the buffer */
1478 if (!buf_valid(buf2))
1479 buf2 = firstbuf;
1480#endif
1481 }
1482 }
1483 }
1484 else if (ret == VIM_DISCARDALL)
1485 {
1486 /*
1487 * mark all buffers as unchanged
1488 */
1489 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1490 unchanged(buf2, TRUE);
1491 }
1492}
1493#endif
1494
1495/*
1496 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1497 * hidden, autowriting it or unloading it.
1498 */
1499 int
1500can_abandon(buf, forceit)
1501 buf_T *buf;
1502 int forceit;
1503{
1504 return ( P_HID(buf)
1505 || !bufIsChanged(buf)
1506 || buf->b_nwindows > 1
1507 || autowrite(buf, forceit) == OK
1508 || forceit);
1509}
1510
1511/*
1512 * Return TRUE if any buffer was changed and cannot be abandoned.
1513 * That changed buffer becomes the current buffer.
1514 */
1515 int
1516check_changed_any(hidden)
1517 int hidden; /* Only check hidden buffers */
1518{
1519 buf_T *buf;
1520 int save;
1521#ifdef FEAT_WINDOWS
1522 win_T *wp;
1523#endif
1524
1525 for (;;)
1526 {
1527 /* check curbuf first: if it was changed we can't abandon it */
1528 if (!hidden && curbufIsChanged())
1529 buf = curbuf;
1530 else
1531 {
1532 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1533 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1534 break;
1535 }
1536 if (buf == NULL) /* No buffers changed */
1537 return FALSE;
1538
Bram Moolenaar373154b2007-02-13 05:19:30 +00001539 /* Try auto-writing the buffer. If this fails but the buffer no
1540 * longer exists it's not changed, that's OK. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1542 break; /* didn't save - still changes */
1543 }
1544
1545 exiting = FALSE;
1546#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1547 /*
1548 * When ":confirm" used, don't give an error message.
1549 */
1550 if (!(p_confirm || cmdmod.confirm))
1551#endif
1552 {
1553 /* There must be a wait_return for this message, do_buffer()
1554 * may cause a redraw. But wait_return() is a no-op when vgetc()
1555 * is busy (Quit used from window menu), then make sure we don't
1556 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001557 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558 {
1559 msg_row = cmdline_row;
1560 msg_col = 0;
1561 msg_didout = FALSE;
1562 }
1563 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1564 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1565 buf->b_fname))
1566 {
1567 save = no_wait_return;
1568 no_wait_return = FALSE;
1569 wait_return(FALSE);
1570 no_wait_return = save;
1571 }
1572 }
1573
1574#ifdef FEAT_WINDOWS
1575 /* Try to find a window that contains the buffer. */
1576 if (buf != curbuf)
1577 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1578 if (wp->w_buffer == buf)
1579 {
1580 win_goto(wp);
1581# ifdef FEAT_AUTOCMD
1582 /* Paranoia: did autocms wipe out the buffer with changes? */
1583 if (!buf_valid(buf))
1584 return TRUE;
1585# endif
1586 break;
1587 }
1588#endif
1589
1590 /* Open the changed buffer in the current window. */
1591 if (buf != curbuf)
1592 set_curbuf(buf, DOBUF_GOTO);
1593
1594 return TRUE;
1595}
1596
1597/*
1598 * return FAIL if there is no file name, OK if there is one
1599 * give error message for FAIL
1600 */
1601 int
1602check_fname()
1603{
1604 if (curbuf->b_ffname == NULL)
1605 {
1606 EMSG(_(e_noname));
1607 return FAIL;
1608 }
1609 return OK;
1610}
1611
1612/*
1613 * flush the contents of a buffer, unless it has no file name
1614 *
1615 * return FAIL for failure, OK otherwise
1616 */
1617 int
1618buf_write_all(buf, forceit)
1619 buf_T *buf;
1620 int forceit;
1621{
1622 int retval;
1623#ifdef FEAT_AUTOCMD
1624 buf_T *old_curbuf = curbuf;
1625#endif
1626
1627 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1628 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1629 FALSE, forceit, TRUE, FALSE));
1630#ifdef FEAT_AUTOCMD
1631 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001632 {
1633 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001634 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001635 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636#endif
1637 return retval;
1638}
1639
1640/*
1641 * Code to handle the argument list.
1642 */
1643
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001644static char_u *do_one_arg __ARGS((char_u *str));
1645static int do_arglist __ARGS((char_u *str, int what, int after));
1646static void alist_check_arg_idx __ARGS((void));
1647static int editing_arg_idx __ARGS((win_T *win));
1648#ifdef FEAT_LISTCMDS
1649static int alist_add_list __ARGS((int count, char_u **files, int after));
1650#endif
1651#define AL_SET 1
1652#define AL_ADD 2
1653#define AL_DEL 3
1654
Bram Moolenaar071d4272004-06-13 20:20:40 +00001655/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001656 * Isolate one argument, taking backticks.
1657 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001658 * Return a pointer to the start of the next argument.
1659 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001660 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661do_one_arg(str)
1662 char_u *str;
1663{
1664 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001665 int inbacktick;
1666
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667 inbacktick = FALSE;
1668 for (p = str; *str; ++str)
1669 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001670 /* When the backslash is used for escaping the special meaning of a
1671 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001672 if (rem_backslash(str))
1673 {
1674 *p++ = *str++;
1675 *p++ = *str;
1676 }
1677 else
1678 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001679 /* An item ends at a space not in backticks */
1680 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001681 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001682 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001683 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001684 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685 }
1686 }
1687 str = skipwhite(str);
1688 *p = NUL;
1689
1690 return str;
1691}
1692
Bram Moolenaar86b68352004-12-27 21:59:20 +00001693/*
1694 * Separate the arguments in "str" and return a list of pointers in the
1695 * growarray "gap".
1696 */
1697 int
1698get_arglist(gap, str)
1699 garray_T *gap;
1700 char_u *str;
1701{
1702 ga_init2(gap, (int)sizeof(char_u *), 20);
1703 while (*str != NUL)
1704 {
1705 if (ga_grow(gap, 1) == FAIL)
1706 {
1707 ga_clear(gap);
1708 return FAIL;
1709 }
1710 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1711
1712 /* Isolate one argument, change it in-place, put a NUL after it. */
1713 str = do_one_arg(str);
1714 }
1715 return OK;
1716}
1717
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001718#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001719/*
1720 * Parse a list of arguments (file names), expand them and return in
1721 * "fnames[fcountp]".
1722 * Return FAIL or OK.
1723 */
1724 int
1725get_arglist_exp(str, fcountp, fnamesp)
1726 char_u *str;
1727 int *fcountp;
1728 char_u ***fnamesp;
1729{
1730 garray_T ga;
1731 int i;
1732
1733 if (get_arglist(&ga, str) == FAIL)
1734 return FAIL;
1735 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1736 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1737 ga_clear(&ga);
1738 return i;
1739}
1740#endif
1741
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1743/*
1744 * Redefine the argument list.
1745 */
1746 void
1747set_arglist(str)
1748 char_u *str;
1749{
1750 do_arglist(str, AL_SET, 0);
1751}
1752#endif
1753
1754/*
1755 * "what" == AL_SET: Redefine the argument list to 'str'.
1756 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1757 * "what" == AL_DEL: remove files in 'str' from the argument list.
1758 *
1759 * Return FAIL for failure, OK otherwise.
1760 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 static int
1762do_arglist(str, what, after)
1763 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001764 int what UNUSED;
1765 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001766{
1767 garray_T new_ga;
1768 int exp_count;
1769 char_u **exp_files;
1770 int i;
1771#ifdef FEAT_LISTCMDS
1772 char_u *p;
1773 int match;
1774#endif
1775
1776 /*
1777 * Collect all file name arguments in "new_ga".
1778 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001779 if (get_arglist(&new_ga, str) == FAIL)
1780 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781
1782#ifdef FEAT_LISTCMDS
1783 if (what == AL_DEL)
1784 {
1785 regmatch_T regmatch;
1786 int didone;
1787
1788 /*
1789 * Delete the items: use each item as a regexp and find a match in the
1790 * argument list.
1791 */
1792#ifdef CASE_INSENSITIVE_FILENAME
1793 regmatch.rm_ic = TRUE; /* Always ignore case */
1794#else
1795 regmatch.rm_ic = FALSE; /* Never ignore case */
1796#endif
1797 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1798 {
1799 p = ((char_u **)new_ga.ga_data)[i];
1800 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1801 if (p == NULL)
1802 break;
1803 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1804 if (regmatch.regprog == NULL)
1805 {
1806 vim_free(p);
1807 break;
1808 }
1809
1810 didone = FALSE;
1811 for (match = 0; match < ARGCOUNT; ++match)
1812 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1813 (colnr_T)0))
1814 {
1815 didone = TRUE;
1816 vim_free(ARGLIST[match].ae_fname);
1817 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1818 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1819 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820 if (curwin->w_arg_idx > match)
1821 --curwin->w_arg_idx;
1822 --match;
1823 }
1824
1825 vim_free(regmatch.regprog);
1826 vim_free(p);
1827 if (!didone)
1828 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1829 }
1830 ga_clear(&new_ga);
1831 }
1832 else
1833#endif
1834 {
1835 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1836 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1837 ga_clear(&new_ga);
1838 if (i == FAIL)
1839 return FAIL;
1840 if (exp_count == 0)
1841 {
1842 EMSG(_(e_nomatch));
1843 return FAIL;
1844 }
1845
1846#ifdef FEAT_LISTCMDS
1847 if (what == AL_ADD)
1848 {
1849 (void)alist_add_list(exp_count, exp_files, after);
1850 vim_free(exp_files);
1851 }
1852 else /* what == AL_SET */
1853#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001854 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001855 }
1856
1857 alist_check_arg_idx();
1858
1859 return OK;
1860}
1861
1862/*
1863 * Check the validity of the arg_idx for each other window.
1864 */
1865 static void
1866alist_check_arg_idx()
1867{
1868#ifdef FEAT_WINDOWS
1869 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001870 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871
Bram Moolenaarf740b292006-02-16 22:11:02 +00001872 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873 if (win->w_alist == curwin->w_alist)
1874 check_arg_idx(win);
1875#else
1876 check_arg_idx(curwin);
1877#endif
1878}
1879
1880/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001881 * Return TRUE if window "win" is editing then file at the current argument
1882 * index.
1883 */
1884 static int
1885editing_arg_idx(win)
1886 win_T *win;
1887{
1888 return !(win->w_arg_idx >= WARGCOUNT(win)
1889 || (win->w_buffer->b_fnum
1890 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1891 && (win->w_buffer->b_ffname == NULL
1892 || !(fullpathcmp(
1893 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1894 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1895}
1896
1897/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 * Check if window "win" is editing the w_arg_idx file in its argument list.
1899 */
1900 void
1901check_arg_idx(win)
1902 win_T *win;
1903{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001904 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905 {
1906 /* We are not editing the current entry in the argument list.
1907 * Set "arg_had_last" if we are editing the last one. */
1908 win->w_arg_idx_invalid = TRUE;
1909 if (win->w_arg_idx != WARGCOUNT(win) - 1
1910 && arg_had_last == FALSE
1911#ifdef FEAT_WINDOWS
1912 && ALIST(win) == &global_alist
1913#endif
1914 && GARGCOUNT > 0
1915 && win->w_arg_idx < GARGCOUNT
1916 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1917 || (win->w_buffer->b_ffname != NULL
1918 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1919 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1920 arg_had_last = TRUE;
1921 }
1922 else
1923 {
1924 /* We are editing the current entry in the argument list.
1925 * Set "arg_had_last" if it's also the last one */
1926 win->w_arg_idx_invalid = FALSE;
1927 if (win->w_arg_idx == WARGCOUNT(win) - 1
1928#ifdef FEAT_WINDOWS
1929 && win->w_alist == &global_alist
1930#endif
1931 )
1932 arg_had_last = TRUE;
1933 }
1934}
1935
1936/*
1937 * ":args", ":argslocal" and ":argsglobal".
1938 */
1939 void
1940ex_args(eap)
1941 exarg_T *eap;
1942{
1943 int i;
1944
1945 if (eap->cmdidx != CMD_args)
1946 {
1947#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1948 alist_unlink(ALIST(curwin));
1949 if (eap->cmdidx == CMD_argglobal)
1950 ALIST(curwin) = &global_alist;
1951 else /* eap->cmdidx == CMD_arglocal */
1952 alist_new();
1953#else
1954 ex_ni(eap);
1955 return;
1956#endif
1957 }
1958
1959 if (!ends_excmd(*eap->arg))
1960 {
1961 /*
1962 * ":args file ..": define new argument list, handle like ":next"
1963 * Also for ":argslocal file .." and ":argsglobal file ..".
1964 */
1965 ex_next(eap);
1966 }
1967 else
1968#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1969 if (eap->cmdidx == CMD_args)
1970#endif
1971 {
1972 /*
1973 * ":args": list arguments.
1974 */
1975 if (ARGCOUNT > 0)
1976 {
1977 /* Overwrite the command, for a short list there is no scrolling
1978 * required and no wait_return(). */
1979 gotocmdline(TRUE);
1980 for (i = 0; i < ARGCOUNT; ++i)
1981 {
1982 if (i == curwin->w_arg_idx)
1983 msg_putchar('[');
1984 msg_outtrans(alist_name(&ARGLIST[i]));
1985 if (i == curwin->w_arg_idx)
1986 msg_putchar(']');
1987 msg_putchar(' ');
1988 }
1989 }
1990 }
1991#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1992 else if (eap->cmdidx == CMD_arglocal)
1993 {
1994 garray_T *gap = &curwin->w_alist->al_ga;
1995
1996 /*
1997 * ":argslocal": make a local copy of the global argument list.
1998 */
1999 if (ga_grow(gap, GARGCOUNT) == OK)
2000 for (i = 0; i < GARGCOUNT; ++i)
2001 if (GARGLIST[i].ae_fname != NULL)
2002 {
2003 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2004 vim_strsave(GARGLIST[i].ae_fname);
2005 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2006 GARGLIST[i].ae_fnum;
2007 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002008 }
2009 }
2010#endif
2011}
2012
2013/*
2014 * ":previous", ":sprevious", ":Next" and ":sNext".
2015 */
2016 void
2017ex_previous(eap)
2018 exarg_T *eap;
2019{
2020 /* If past the last one already, go to the last one. */
2021 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2022 do_argfile(eap, ARGCOUNT - 1);
2023 else
2024 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2025}
2026
2027/*
2028 * ":rewind", ":first", ":sfirst" and ":srewind".
2029 */
2030 void
2031ex_rewind(eap)
2032 exarg_T *eap;
2033{
2034 do_argfile(eap, 0);
2035}
2036
2037/*
2038 * ":last" and ":slast".
2039 */
2040 void
2041ex_last(eap)
2042 exarg_T *eap;
2043{
2044 do_argfile(eap, ARGCOUNT - 1);
2045}
2046
2047/*
2048 * ":argument" and ":sargument".
2049 */
2050 void
2051ex_argument(eap)
2052 exarg_T *eap;
2053{
2054 int i;
2055
2056 if (eap->addr_count > 0)
2057 i = eap->line2 - 1;
2058 else
2059 i = curwin->w_arg_idx;
2060 do_argfile(eap, i);
2061}
2062
2063/*
2064 * Edit file "argn" of the argument lists.
2065 */
2066 void
2067do_argfile(eap, argn)
2068 exarg_T *eap;
2069 int argn;
2070{
2071 int other;
2072 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002073 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074
2075 if (argn < 0 || argn >= ARGCOUNT)
2076 {
2077 if (ARGCOUNT <= 1)
2078 EMSG(_("E163: There is only one file to edit"));
2079 else if (argn < 0)
2080 EMSG(_("E164: Cannot go before first file"));
2081 else
2082 EMSG(_("E165: Cannot go beyond last file"));
2083 }
2084 else
2085 {
2086 setpcmark();
2087#ifdef FEAT_GUI
2088 need_mouse_correct = TRUE;
2089#endif
2090
2091#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002092 /* split window or create new tab page first */
2093 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 {
2095 if (win_split(0, 0) == FAIL)
2096 return;
2097# ifdef FEAT_SCROLLBIND
2098 curwin->w_p_scb = FALSE;
2099# endif
2100 }
2101 else
2102#endif
2103 {
2104 /*
2105 * if 'hidden' set, only check for changed file when re-editing
2106 * the same buffer
2107 */
2108 other = TRUE;
2109 if (P_HID(curbuf))
2110 {
2111 p = fix_fname(alist_name(&ARGLIST[argn]));
2112 other = otherfile(p);
2113 vim_free(p);
2114 }
2115 if ((!P_HID(curbuf) || !other)
2116 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2117 return;
2118 }
2119
2120 curwin->w_arg_idx = argn;
2121 if (argn == ARGCOUNT - 1
2122#ifdef FEAT_WINDOWS
2123 && curwin->w_alist == &global_alist
2124#endif
2125 )
2126 arg_had_last = TRUE;
2127
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002128 /* Edit the file; always use the last known line number.
2129 * When it fails (e.g. Abort for already edited file) restore the
2130 * argument index. */
2131 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002133 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2134 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002135 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002137 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002138 setmark('\'');
2139 }
2140}
2141
2142/*
2143 * ":next", and commands that behave like it.
2144 */
2145 void
2146ex_next(eap)
2147 exarg_T *eap;
2148{
2149 int i;
2150
2151 /*
2152 * check for changed buffer now, if this fails the argument list is not
2153 * redefined.
2154 */
2155 if ( P_HID(curbuf)
2156 || eap->cmdidx == CMD_snext
2157 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2158 {
2159 if (*eap->arg != NUL) /* redefine file list */
2160 {
2161 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2162 return;
2163 i = 0;
2164 }
2165 else
2166 i = curwin->w_arg_idx + (int)eap->line2;
2167 do_argfile(eap, i);
2168 }
2169}
2170
2171#ifdef FEAT_LISTCMDS
2172/*
2173 * ":argedit"
2174 */
2175 void
2176ex_argedit(eap)
2177 exarg_T *eap;
2178{
2179 int fnum;
2180 int i;
2181 char_u *s;
2182
2183 /* Add the argument to the buffer list and get the buffer number. */
2184 fnum = buflist_add(eap->arg, BLN_LISTED);
2185
2186 /* Check if this argument is already in the argument list. */
2187 for (i = 0; i < ARGCOUNT; ++i)
2188 if (ARGLIST[i].ae_fnum == fnum)
2189 break;
2190 if (i == ARGCOUNT)
2191 {
2192 /* Can't find it, add it to the argument list. */
2193 s = vim_strsave(eap->arg);
2194 if (s == NULL)
2195 return;
2196 i = alist_add_list(1, &s,
2197 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2198 if (i < 0)
2199 return;
2200 curwin->w_arg_idx = i;
2201 }
2202
2203 alist_check_arg_idx();
2204
2205 /* Edit the argument. */
2206 do_argfile(eap, i);
2207}
2208
2209/*
2210 * ":argadd"
2211 */
2212 void
2213ex_argadd(eap)
2214 exarg_T *eap;
2215{
2216 do_arglist(eap->arg, AL_ADD,
2217 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2218#ifdef FEAT_TITLE
2219 maketitle();
2220#endif
2221}
2222
2223/*
2224 * ":argdelete"
2225 */
2226 void
2227ex_argdelete(eap)
2228 exarg_T *eap;
2229{
2230 int i;
2231 int n;
2232
2233 if (eap->addr_count > 0)
2234 {
2235 /* ":1,4argdel": Delete all arguments in the range. */
2236 if (eap->line2 > ARGCOUNT)
2237 eap->line2 = ARGCOUNT;
2238 n = eap->line2 - eap->line1 + 1;
2239 if (*eap->arg != NUL || n <= 0)
2240 EMSG(_(e_invarg));
2241 else
2242 {
2243 for (i = eap->line1; i <= eap->line2; ++i)
2244 vim_free(ARGLIST[i - 1].ae_fname);
2245 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2246 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2247 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248 if (curwin->w_arg_idx >= eap->line2)
2249 curwin->w_arg_idx -= n;
2250 else if (curwin->w_arg_idx > eap->line1)
2251 curwin->w_arg_idx = eap->line1;
2252 }
2253 }
2254 else if (*eap->arg == NUL)
2255 EMSG(_(e_argreq));
2256 else
2257 do_arglist(eap->arg, AL_DEL, 0);
2258#ifdef FEAT_TITLE
2259 maketitle();
2260#endif
2261}
2262
2263/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002264 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 */
2266 void
2267ex_listdo(eap)
2268 exarg_T *eap;
2269{
2270 int i;
2271#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002272 win_T *wp;
2273 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274#endif
2275 buf_T *buf;
2276 int next_fnum = 0;
2277#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2278 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002280 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002281
2282#ifndef FEAT_WINDOWS
2283 if (eap->cmdidx == CMD_windo)
2284 {
2285 ex_ni(eap);
2286 return;
2287 }
2288#endif
2289
2290#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002291 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002292 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2293 * great speed improvement. */
2294 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295#endif
2296
2297 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002298 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002299 || P_HID(curbuf)
2300 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2301 {
2302 /* start at the first argument/window/buffer */
2303 i = 0;
2304#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002305 wp = firstwin;
2306 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307#endif
2308 /* set pcmark now */
2309 if (eap->cmdidx == CMD_bufdo)
2310 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2311 else
2312 setpcmark();
2313 listcmd_busy = TRUE; /* avoids setting pcmark below */
2314
2315 while (!got_int)
2316 {
2317 if (eap->cmdidx == CMD_argdo)
2318 {
2319 /* go to argument "i" */
2320 if (i == ARGCOUNT)
2321 break;
2322 /* Don't call do_argfile() when already there, it will try
2323 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002324 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002325 {
2326 /* Clear 'shm' to avoid that the file message overwrites
2327 * any output from the command. */
2328 p_shm_save = vim_strsave(p_shm);
2329 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002330 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002331 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2332 vim_free(p_shm_save);
2333 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002334 if (curwin->w_arg_idx != i)
2335 break;
2336 ++i;
2337 }
2338#ifdef FEAT_WINDOWS
2339 else if (eap->cmdidx == CMD_windo)
2340 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002341 /* go to window "wp" */
2342 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002343 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002344 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002345 if (curwin != wp)
2346 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002347 wp = curwin->w_next;
2348 }
2349 else if (eap->cmdidx == CMD_tabdo)
2350 {
2351 /* go to window "tp" */
2352 if (!valid_tabpage(tp))
2353 break;
2354 goto_tabpage_tp(tp);
2355 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356 }
2357#endif
2358 else if (eap->cmdidx == CMD_bufdo)
2359 {
2360 /* Remember the number of the next listed buffer, in case
2361 * ":bwipe" is used or autocommands do something strange. */
2362 next_fnum = -1;
2363 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2364 if (buf->b_p_bl)
2365 {
2366 next_fnum = buf->b_fnum;
2367 break;
2368 }
2369 }
2370
2371 /* execute the command */
2372 do_cmdline(eap->arg, eap->getline, eap->cookie,
2373 DOCMD_VERBOSE + DOCMD_NOWAIT);
2374
2375 if (eap->cmdidx == CMD_bufdo)
2376 {
2377 /* Done? */
2378 if (next_fnum < 0)
2379 break;
2380 /* Check if the buffer still exists. */
2381 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2382 if (buf->b_fnum == next_fnum)
2383 break;
2384 if (buf == NULL)
2385 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002386
2387 /* Go to the next buffer. Clear 'shm' to avoid that the file
2388 * message overwrites any output from the command. */
2389 p_shm_save = vim_strsave(p_shm);
2390 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002391 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002392 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2393 vim_free(p_shm_save);
2394
Bram Moolenaar071d4272004-06-13 20:20:40 +00002395 /* If autocommands took us elsewhere, quit here */
2396 if (curbuf->b_fnum != next_fnum)
2397 break;
2398 }
2399
2400 if (eap->cmdidx == CMD_windo)
2401 {
2402 validate_cursor(); /* cursor may have moved */
2403#ifdef FEAT_SCROLLBIND
2404 /* required when 'scrollbind' has been set */
2405 if (curwin->w_p_scb)
2406 do_check_scrollbind(TRUE);
2407#endif
2408 }
2409 }
2410 listcmd_busy = FALSE;
2411 }
2412
2413#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002414 if (save_ei != NULL)
2415 {
2416 au_event_restore(save_ei);
2417 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2418 curbuf->b_fname, TRUE, curbuf);
2419 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420#endif
2421}
2422
2423/*
2424 * Add files[count] to the arglist of the current window after arg "after".
2425 * The file names in files[count] must have been allocated and are taken over.
2426 * Files[] itself is not taken over.
2427 * Returns index of first added argument. Returns -1 when failed (out of mem).
2428 */
2429 static int
2430alist_add_list(count, files, after)
2431 int count;
2432 char_u **files;
2433 int after; /* where to add: 0 = before first one */
2434{
2435 int i;
2436
2437 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2438 {
2439 if (after < 0)
2440 after = 0;
2441 if (after > ARGCOUNT)
2442 after = ARGCOUNT;
2443 if (after < ARGCOUNT)
2444 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2445 (ARGCOUNT - after) * sizeof(aentry_T));
2446 for (i = 0; i < count; ++i)
2447 {
2448 ARGLIST[after + i].ae_fname = files[i];
2449 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2450 }
2451 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452 if (curwin->w_arg_idx >= after)
2453 ++curwin->w_arg_idx;
2454 return after;
2455 }
2456
2457 for (i = 0; i < count; ++i)
2458 vim_free(files[i]);
2459 return -1;
2460}
2461
2462#endif /* FEAT_LISTCMDS */
2463
2464#ifdef FEAT_EVAL
2465/*
2466 * ":compiler[!] {name}"
2467 */
2468 void
2469ex_compiler(eap)
2470 exarg_T *eap;
2471{
2472 char_u *buf;
2473 char_u *old_cur_comp = NULL;
2474 char_u *p;
2475
2476 if (*eap->arg == NUL)
2477 {
2478 /* List all compiler scripts. */
2479 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2480 /* ) keep the indenter happy... */
2481 }
2482 else
2483 {
2484 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2485 if (buf != NULL)
2486 {
2487 if (eap->forceit)
2488 {
2489 /* ":compiler! {name}" sets global options */
2490 do_cmdline_cmd((char_u *)
2491 "command -nargs=* CompilerSet set <args>");
2492 }
2493 else
2494 {
2495 /* ":compiler! {name}" sets local options.
2496 * To remain backwards compatible "current_compiler" is always
2497 * used. A user's compiler plugin may set it, the distributed
2498 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002499 * "b:current_compiler" and restore "current_compiler".
2500 * Explicitly prepend "g:" to make it work in a function. */
2501 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 if (old_cur_comp != NULL)
2503 old_cur_comp = vim_strsave(old_cur_comp);
2504 do_cmdline_cmd((char_u *)
2505 "command -nargs=* CompilerSet setlocal <args>");
2506 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002507 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002508 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509
2510 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002511 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2513 vim_free(buf);
2514
2515 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2516
2517 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002518 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 if (p != NULL)
2520 set_internal_string_var((char_u *)"b:current_compiler", p);
2521
2522 /* Restore "current_compiler" for ":compiler {name}". */
2523 if (!eap->forceit)
2524 {
2525 if (old_cur_comp != NULL)
2526 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002527 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002528 old_cur_comp);
2529 vim_free(old_cur_comp);
2530 }
2531 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002532 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533 }
2534 }
2535 }
2536}
2537#endif
2538
2539/*
2540 * ":runtime {name}"
2541 */
2542 void
2543ex_runtime(eap)
2544 exarg_T *eap;
2545{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002546 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002547}
2548
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002549static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550
2551 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002552source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002553 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002554 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002556 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557}
2558
2559/*
2560 * Source the file "name" from all directories in 'runtimepath'.
2561 * "name" can contain wildcards.
2562 * When "all" is TRUE, source all files, otherwise only the first one.
2563 * return FAIL when no file could be sourced, OK otherwise.
2564 */
2565 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002566source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002567 char_u *name;
2568 int all;
2569{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002570 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571}
2572
2573/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002574 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2575 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2577 * used.
2578 * Returns OK when at least one match found, FAIL otherwise.
2579 */
2580 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002581do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582 char_u *name;
2583 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002584 void (*callback)__ARGS((char_u *fname, void *ck));
2585 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586{
2587 char_u *rtp;
2588 char_u *np;
2589 char_u *buf;
2590 char_u *rtp_copy;
2591 char_u *tail;
2592 int num_files;
2593 char_u **files;
2594 int i;
2595 int did_one = FALSE;
2596#ifdef AMIGA
2597 struct Process *proc = (struct Process *)FindTask(0L);
2598 APTR save_winptr = proc->pr_WindowPtr;
2599
2600 /* Avoid a requester here for a volume that doesn't exist. */
2601 proc->pr_WindowPtr = (APTR)-1L;
2602#endif
2603
2604 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2605 * value. */
2606 rtp_copy = vim_strsave(p_rtp);
2607 buf = alloc(MAXPATHL);
2608 if (buf != NULL && rtp_copy != NULL)
2609 {
2610 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002611 {
2612 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002613 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002615 verbose_leave();
2616 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002617
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618 /* Loop over all entries in 'runtimepath'. */
2619 rtp = rtp_copy;
2620 while (*rtp != NUL && (all || !did_one))
2621 {
2622 /* Copy the path from 'runtimepath' to buf[]. */
2623 copy_option_part(&rtp, buf, MAXPATHL, ",");
2624 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2625 {
2626 add_pathsep(buf);
2627 tail = buf + STRLEN(buf);
2628
2629 /* Loop over all patterns in "name" */
2630 np = name;
2631 while (*np != NUL && (all || !did_one))
2632 {
2633 /* Append the pattern from "name" to buf[]. */
2634 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2635 "\t ");
2636
2637 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002638 {
2639 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002640 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002641 verbose_leave();
2642 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643
2644 /* Expand wildcards, invoke the callback for each match. */
2645 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2646 EW_FILE) == OK)
2647 {
2648 for (i = 0; i < num_files; ++i)
2649 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002650 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651 did_one = TRUE;
2652 if (!all)
2653 break;
2654 }
2655 FreeWild(num_files, files);
2656 }
2657 }
2658 }
2659 }
2660 }
2661 vim_free(buf);
2662 vim_free(rtp_copy);
2663 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002664 {
2665 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002666 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002667 verbose_leave();
2668 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002669
2670#ifdef AMIGA
2671 proc->pr_WindowPtr = save_winptr;
2672#endif
2673
2674 return did_one ? OK : FAIL;
2675}
2676
2677#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2678/*
2679 * ":options"
2680 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 void
2682ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002683 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684{
2685 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2686}
2687#endif
2688
2689/*
2690 * ":source {fname}"
2691 */
2692 void
2693ex_source(eap)
2694 exarg_T *eap;
2695{
2696#ifdef FEAT_BROWSE
2697 if (cmdmod.browse)
2698 {
2699 char_u *fname = NULL;
2700
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002701 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2703 if (fname != NULL)
2704 {
2705 cmd_source(fname, eap);
2706 vim_free(fname);
2707 }
2708 }
2709 else
2710#endif
2711 cmd_source(eap->arg, eap);
2712}
2713
2714 static void
2715cmd_source(fname, eap)
2716 char_u *fname;
2717 exarg_T *eap;
2718{
2719 if (*fname == NUL)
2720 EMSG(_(e_argreq));
2721
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002723 /* ":source!": read Normal mdoe commands
2724 * Need to execute the commands directly. This is required at least
2725 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726 * - ":g" command busy
2727 * - after ":argdo", ":windo" or ":bufdo"
2728 * - another command follows
2729 * - inside a loop
2730 */
2731 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2732#ifdef FEAT_EVAL
2733 || eap->cstack->cs_idx >= 0
2734#endif
2735 );
2736
2737 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002738 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739 EMSG2(_(e_notopen), fname);
2740}
2741
2742/*
2743 * ":source" and associated commands.
2744 */
2745/*
2746 * Structure used to store info for each sourced file.
2747 * It is shared between do_source() and getsourceline().
2748 * This is required, because it needs to be handed to do_cmdline() and
2749 * sourcing can be done recursively.
2750 */
2751struct source_cookie
2752{
2753 FILE *fp; /* opened file for sourcing */
2754 char_u *nextline; /* if not NULL: line that was read ahead */
2755 int finished; /* ":finish" used */
2756#if defined (USE_CRNL) || defined (USE_CR)
2757 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2758 int error; /* TRUE if LF found after CR-LF */
2759#endif
2760#ifdef FEAT_EVAL
2761 linenr_T breakpoint; /* next line with breakpoint or zero */
2762 char_u *fname; /* name of sourced file */
2763 int dbg_tick; /* debug_tick when breakpoint was set */
2764 int level; /* top nesting level of sourced file */
2765#endif
2766#ifdef FEAT_MBYTE
2767 vimconv_T conv; /* type of conversion */
2768#endif
2769};
2770
2771#ifdef FEAT_EVAL
2772/*
2773 * Return the address holding the next breakpoint line for a source cookie.
2774 */
2775 linenr_T *
2776source_breakpoint(cookie)
2777 void *cookie;
2778{
2779 return &((struct source_cookie *)cookie)->breakpoint;
2780}
2781
2782/*
2783 * Return the address holding the debug tick for a source cookie.
2784 */
2785 int *
2786source_dbg_tick(cookie)
2787 void *cookie;
2788{
2789 return &((struct source_cookie *)cookie)->dbg_tick;
2790}
2791
2792/*
2793 * Return the nesting level for a source cookie.
2794 */
2795 int
2796source_level(cookie)
2797 void *cookie;
2798{
2799 return ((struct source_cookie *)cookie)->level;
2800}
2801#endif
2802
2803static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2804
Bram Moolenaar071d4272004-06-13 20:20:40 +00002805#if defined(WIN32) && defined(FEAT_CSCOPE)
2806static FILE *fopen_noinh_readbin __ARGS((char *filename));
2807
2808/*
2809 * Special function to open a file without handle inheritance.
2810 */
2811 static FILE *
2812fopen_noinh_readbin(filename)
2813 char *filename;
2814{
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00002815 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002816
2817 if (fd_tmp == -1)
2818 return NULL;
2819 return fdopen(fd_tmp, READBIN);
2820}
2821#endif
2822
2823
2824/*
2825 * do_source: Read the file "fname" and execute its lines as EX commands.
2826 *
2827 * This function may be called recursively!
2828 *
2829 * return FAIL if file could not be opened, OK otherwise
2830 */
2831 int
2832do_source(fname, check_other, is_vimrc)
2833 char_u *fname;
2834 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002835 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002836{
2837 struct source_cookie cookie;
2838 char_u *save_sourcing_name;
2839 linenr_T save_sourcing_lnum;
2840 char_u *p;
2841 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002842 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 int retval = FAIL;
2844#ifdef FEAT_EVAL
2845 scid_T save_current_SID;
2846 static scid_T last_current_SID = 0;
2847 void *save_funccalp;
2848 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002849 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850# ifdef UNIX
2851 struct stat st;
2852 int stat_ok;
2853# endif
2854#endif
2855#ifdef STARTUPTIME
2856 struct timeval tv_rel;
2857 struct timeval tv_start;
2858#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002859#ifdef FEAT_PROFILE
2860 proftime_T wait_start;
2861#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862
2863#ifdef RISCOS
2864 p = mch_munge_fname(fname);
2865#else
2866 p = expand_env_save(fname);
2867#endif
2868 if (p == NULL)
2869 return retval;
2870 fname_exp = fix_fname(p);
2871 vim_free(p);
2872 if (fname_exp == NULL)
2873 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002874 if (mch_isdir(fname_exp))
2875 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002876 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002877 goto theend;
2878 }
2879
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002880#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002881 /* Apply SourceCmd autocommands, they should get the file and source it. */
2882 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2883 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2884 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002885 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002886# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002887 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002888# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002889 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002890# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002891 goto theend;
2892 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002893
2894 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002895 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2896#endif
2897
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898#if defined(WIN32) && defined(FEAT_CSCOPE)
2899 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2900#else
2901 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2902#endif
2903 if (cookie.fp == NULL && check_other)
2904 {
2905 /*
2906 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2907 * and ".exrc" by "_exrc" or vice versa.
2908 */
2909 p = gettail(fname_exp);
2910 if ((*p == '.' || *p == '_')
2911 && (STRICMP(p + 1, "vimrc") == 0
2912 || STRICMP(p + 1, "gvimrc") == 0
2913 || STRICMP(p + 1, "exrc") == 0))
2914 {
2915 if (*p == '_')
2916 *p = '.';
2917 else
2918 *p = '_';
2919#if defined(WIN32) && defined(FEAT_CSCOPE)
2920 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2921#else
2922 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2923#endif
2924 }
2925 }
2926
2927 if (cookie.fp == NULL)
2928 {
2929 if (p_verbose > 0)
2930 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002931 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002933 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934 else
2935 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002936 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002937 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 }
2939 goto theend;
2940 }
2941
2942 /*
2943 * The file exists.
2944 * - In verbose mode, give a message.
2945 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2946 */
2947 if (p_verbose > 1)
2948 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002949 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002951 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952 else
2953 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002954 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002955 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002957 if (is_vimrc == DOSO_VIMRC)
2958 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
2959 else if (is_vimrc == DOSO_GVIMRC)
2960 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002961
2962#ifdef USE_CRNL
2963 /* If no automatic file format: Set default to CR-NL. */
2964 if (*p_ffs == NUL)
2965 cookie.fileformat = EOL_DOS;
2966 else
2967 cookie.fileformat = EOL_UNKNOWN;
2968 cookie.error = FALSE;
2969#endif
2970
2971#ifdef USE_CR
2972 /* If no automatic file format: Set default to CR. */
2973 if (*p_ffs == NUL)
2974 cookie.fileformat = EOL_MAC;
2975 else
2976 cookie.fileformat = EOL_UNKNOWN;
2977 cookie.error = FALSE;
2978#endif
2979
2980 cookie.nextline = NULL;
2981 cookie.finished = FALSE;
2982
2983#ifdef FEAT_EVAL
2984 /*
2985 * Check if this script has a breakpoint.
2986 */
2987 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2988 cookie.fname = fname_exp;
2989 cookie.dbg_tick = debug_tick;
2990
2991 cookie.level = ex_nesting_level;
2992#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002993
2994 /*
2995 * Keep the sourcing name/lnum, for recursive calls.
2996 */
2997 save_sourcing_name = sourcing_name;
2998 sourcing_name = fname_exp;
2999 save_sourcing_lnum = sourcing_lnum;
3000 sourcing_lnum = 0;
3001
Bram Moolenaar73881402009-02-04 16:50:47 +00003002#ifdef FEAT_MBYTE
3003 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3004
3005 /* Read the first line so we can check for a UTF-8 BOM. */
3006 firstline = getsourceline(0, (void *)&cookie, 0);
3007 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3008 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3009 {
3010 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3011 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3012 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003013 if (p == NULL)
3014 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003015 if (p != NULL)
3016 {
3017 vim_free(firstline);
3018 firstline = p;
3019 }
3020 }
3021#endif
3022
Bram Moolenaar071d4272004-06-13 20:20:40 +00003023#ifdef STARTUPTIME
3024 time_push(&tv_rel, &tv_start);
3025#endif
3026
3027#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003028# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003029 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003030 prof_child_enter(&wait_start); /* entering a child now */
3031# endif
3032
3033 /* Don't use local function variables, if called from a function.
3034 * Also starts profiling timer for nested script. */
3035 save_funccalp = save_funccal();
3036
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037 /*
3038 * Check if this script was sourced before to finds its SID.
3039 * If it's new, generate a new SID.
3040 */
3041 save_current_SID = current_SID;
3042# ifdef UNIX
3043 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3044# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003045 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3046 {
3047 si = &SCRIPT_ITEM(current_SID);
3048 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049 && (
3050# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003051 /* Compare dev/ino when possible, it catches symbolic
3052 * links. Also compare file names, the inode may change
3053 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003054 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003055 && (si->sn_dev == st.st_dev
3056 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003058 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003060 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061 if (current_SID == 0)
3062 {
3063 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003064 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3065 == FAIL)
3066 goto almosttheend;
3067 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003069 ++script_items.ga_len;
3070 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3071# ifdef FEAT_PROFILE
3072 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003075 si = &SCRIPT_ITEM(current_SID);
3076 si->sn_name = fname_exp;
3077 fname_exp = NULL;
3078# ifdef UNIX
3079 if (stat_ok)
3080 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003081 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003082 si->sn_dev = st.st_dev;
3083 si->sn_ino = st.st_ino;
3084 }
3085 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003086 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003087# endif
3088
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089 /* Allocate the local script variables to use for this script. */
3090 new_script_vars(current_SID);
3091 }
3092
Bram Moolenaar05159a02005-02-26 23:04:13 +00003093# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003094 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003095 {
3096 int forceit;
3097
3098 /* Check if we do profiling for this script. */
3099 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3100 {
3101 script_do_profile(si);
3102 si->sn_pr_force = forceit;
3103 }
3104 if (si->sn_prof_on)
3105 {
3106 ++si->sn_pr_count;
3107 profile_start(&si->sn_pr_start);
3108 profile_zero(&si->sn_pr_children);
3109 }
3110 }
3111# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003112#endif
3113
3114 /*
3115 * Call do_cmdline, which will call getsourceline() to get the lines.
3116 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003117 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003118 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003119 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003120
3121#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003122 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003123 {
3124 /* Get "si" again, "script_items" may have been reallocated. */
3125 si = &SCRIPT_ITEM(current_SID);
3126 if (si->sn_prof_on)
3127 {
3128 profile_end(&si->sn_pr_start);
3129 profile_sub_wait(&wait_start, &si->sn_pr_start);
3130 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003131 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3132 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003133 }
3134 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135#endif
3136
3137 if (got_int)
3138 EMSG(_(e_interr));
3139 sourcing_name = save_sourcing_name;
3140 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141 if (p_verbose > 1)
3142 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003143 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003144 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003146 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003147 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148 }
3149#ifdef STARTUPTIME
Bram Moolenaare511f292008-09-07 13:50:37 +00003150 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3151 time_msg((char *)IObuff, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152 time_pop(&tv_rel);
3153#endif
3154
3155#ifdef FEAT_EVAL
3156 /*
3157 * After a "finish" in debug mode, need to break at first command of next
3158 * sourced file.
3159 */
3160 if (save_debug_break_level > ex_nesting_level
3161 && debug_break_level == ex_nesting_level)
3162 ++debug_break_level;
3163#endif
3164
Bram Moolenaar05159a02005-02-26 23:04:13 +00003165#ifdef FEAT_EVAL
3166almosttheend:
3167 current_SID = save_current_SID;
3168 restore_funccal(save_funccalp);
3169# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003170 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003171 prof_child_exit(&wait_start); /* leaving a child now */
3172# endif
3173#endif
3174 fclose(cookie.fp);
3175 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003176 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003177#ifdef FEAT_MBYTE
3178 convert_setup(&cookie.conv, NULL, NULL);
3179#endif
3180
Bram Moolenaar071d4272004-06-13 20:20:40 +00003181theend:
3182 vim_free(fname_exp);
3183 return retval;
3184}
3185
3186#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003187
Bram Moolenaar071d4272004-06-13 20:20:40 +00003188/*
3189 * ":scriptnames"
3190 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003191 void
3192ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003193 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003194{
3195 int i;
3196
Bram Moolenaar05159a02005-02-26 23:04:13 +00003197 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3198 if (SCRIPT_ITEM(i).sn_name != NULL)
3199 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003200}
3201
3202# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3203/*
3204 * Fix slashes in the list of script names for 'shellslash'.
3205 */
3206 void
3207scriptnames_slash_adjust()
3208{
3209 int i;
3210
Bram Moolenaar05159a02005-02-26 23:04:13 +00003211 for (i = 1; i <= script_items.ga_len; ++i)
3212 if (SCRIPT_ITEM(i).sn_name != NULL)
3213 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214}
3215# endif
3216
3217/*
3218 * Get a pointer to a script name. Used for ":verbose set".
3219 */
3220 char_u *
3221get_scriptname(id)
3222 scid_T id;
3223{
3224 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003225 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003227 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003229 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003230 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003231 return (char_u *)_("environment variable");
3232 if (id == SID_ERROR)
3233 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003234 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003235}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003236
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003237# if defined(EXITFREE) || defined(PROTO)
3238 void
3239free_scriptnames()
3240{
3241 int i;
3242
3243 for (i = script_items.ga_len; i > 0; --i)
3244 vim_free(SCRIPT_ITEM(i).sn_name);
3245 ga_clear(&script_items);
3246}
3247# endif
3248
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249#endif
3250
3251#if defined(USE_CR) || defined(PROTO)
3252
3253# if defined(__MSL__) && (__MSL__ >= 22)
3254/*
3255 * Newer version of the Metrowerks library handle DOS and UNIX files
3256 * without help.
3257 * Test with earlier versions, MSL 2.2 is the library supplied with
3258 * Codewarrior Pro 2.
3259 */
3260 char *
3261fgets_cr(s, n, stream)
3262 char *s;
3263 int n;
3264 FILE *stream;
3265{
3266 return fgets(s, n, stream);
3267}
3268# else
3269/*
3270 * Version of fgets() which also works for lines ending in a <CR> only
3271 * (Macintosh format).
3272 * For older versions of the Metrowerks library.
3273 * At least CodeWarrior 9 needed this code.
3274 */
3275 char *
3276fgets_cr(s, n, stream)
3277 char *s;
3278 int n;
3279 FILE *stream;
3280{
3281 int c = 0;
3282 int char_read = 0;
3283
3284 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3285 {
3286 c = fgetc(stream);
3287 s[char_read++] = c;
3288 /* If the file is in DOS format, we need to skip a NL after a CR. I
3289 * thought it was the other way around, but this appears to work... */
3290 if (c == '\n')
3291 {
3292 c = fgetc(stream);
3293 if (c != '\r')
3294 ungetc(c, stream);
3295 }
3296 }
3297
3298 s[char_read] = 0;
3299 if (char_read == 0)
3300 return NULL;
3301
3302 if (feof(stream) && char_read == 1)
3303 return NULL;
3304
3305 return s;
3306}
3307# endif
3308#endif
3309
3310/*
3311 * Get one full line from a sourced file.
3312 * Called by do_cmdline() when it's called from do_source().
3313 *
3314 * Return a pointer to the line in allocated memory.
3315 * Return NULL for end-of-file or some error.
3316 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317 char_u *
3318getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003319 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003320 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003321 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322{
3323 struct source_cookie *sp = (struct source_cookie *)cookie;
3324 char_u *line;
3325 char_u *p, *s;
3326
3327#ifdef FEAT_EVAL
3328 /* If breakpoints have been added/deleted need to check for it. */
3329 if (sp->dbg_tick < debug_tick)
3330 {
3331 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3332 sp->dbg_tick = debug_tick;
3333 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003334# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003335 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003336 script_line_end();
3337# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338#endif
3339 /*
3340 * Get current line. If there is a read-ahead line, use it, otherwise get
3341 * one now.
3342 */
3343 if (sp->finished)
3344 line = NULL;
3345 else if (sp->nextline == NULL)
3346 line = get_one_sourceline(sp);
3347 else
3348 {
3349 line = sp->nextline;
3350 sp->nextline = NULL;
3351 ++sourcing_lnum;
3352 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003353#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003354 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003355 script_line_start();
3356#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003357
3358 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3359 * contain the 'C' flag. */
3360 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3361 {
3362 /* compensate for the one line read-ahead */
3363 --sourcing_lnum;
3364 for (;;)
3365 {
3366 sp->nextline = get_one_sourceline(sp);
3367 if (sp->nextline == NULL)
3368 break;
3369 p = skipwhite(sp->nextline);
3370 if (*p != '\\')
3371 break;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00003372 s = alloc((unsigned)(STRLEN(line) + STRLEN(p)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373 if (s == NULL) /* out of memory */
3374 break;
3375 STRCPY(s, line);
3376 STRCAT(s, p + 1);
3377 vim_free(line);
3378 line = s;
3379 vim_free(sp->nextline);
3380 }
3381 }
3382
3383#ifdef FEAT_MBYTE
3384 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3385 {
3386 /* Convert the encoding of the script line. */
3387 s = string_convert(&sp->conv, line, NULL);
3388 if (s != NULL)
3389 {
3390 vim_free(line);
3391 line = s;
3392 }
3393 }
3394#endif
3395
3396#ifdef FEAT_EVAL
3397 /* Did we encounter a breakpoint? */
3398 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3399 {
3400 dbg_breakpoint(sp->fname, sourcing_lnum);
3401 /* Find next breakpoint. */
3402 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3403 sp->dbg_tick = debug_tick;
3404 }
3405#endif
3406
3407 return line;
3408}
3409
3410 static char_u *
3411get_one_sourceline(sp)
3412 struct source_cookie *sp;
3413{
3414 garray_T ga;
3415 int len;
3416 int c;
3417 char_u *buf;
3418#ifdef USE_CRNL
3419 int has_cr; /* CR-LF found */
3420#endif
3421#ifdef USE_CR
3422 char_u *scan;
3423#endif
3424 int have_read = FALSE;
3425
3426 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003427 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003428
3429 /*
3430 * Loop until there is a finished line (or end-of-file).
3431 */
3432 sourcing_lnum++;
3433 for (;;)
3434 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003435 /* make room to read at least 120 (more) characters */
3436 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437 break;
3438 buf = (char_u *)ga.ga_data;
3439
3440#ifdef USE_CR
3441 if (sp->fileformat == EOL_MAC)
3442 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003443 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3444 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445 break;
3446 }
3447 else
3448#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003449 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3450 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003451 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003452 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003453#ifdef USE_CRNL
3454 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3455 * CTRL-Z by its own, or after a NL. */
3456 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3457 && sp->fileformat == EOL_DOS
3458 && buf[len - 1] == Ctrl_Z)
3459 {
3460 buf[len - 1] = NUL;
3461 break;
3462 }
3463#endif
3464
3465#ifdef USE_CR
3466 /* If the read doesn't stop on a new line, and there's
3467 * some CR then we assume a Mac format */
3468 if (sp->fileformat == EOL_UNKNOWN)
3469 {
3470 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3471 sp->fileformat = EOL_MAC;
3472 else
3473 sp->fileformat = EOL_UNIX;
3474 }
3475
3476 if (sp->fileformat == EOL_MAC)
3477 {
3478 scan = vim_strchr(buf, '\r');
3479
3480 if (scan != NULL)
3481 {
3482 *scan = '\n';
3483 if (*(scan + 1) != 0)
3484 {
3485 *(scan + 1) = 0;
3486 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3487 }
3488 }
3489 len = STRLEN(buf);
3490 }
3491#endif
3492
3493 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003494 ga.ga_len = len;
3495
3496 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003497 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498 continue;
3499
3500 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3501 {
3502#ifdef USE_CRNL
3503 has_cr = (len >= 2 && buf[len - 2] == '\r');
3504 if (sp->fileformat == EOL_UNKNOWN)
3505 {
3506 if (has_cr)
3507 sp->fileformat = EOL_DOS;
3508 else
3509 sp->fileformat = EOL_UNIX;
3510 }
3511
3512 if (sp->fileformat == EOL_DOS)
3513 {
3514 if (has_cr) /* replace trailing CR */
3515 {
3516 buf[len - 2] = '\n';
3517 --len;
3518 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 }
3520 else /* lines like ":map xx yy^M" will have failed */
3521 {
3522 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003523 {
3524 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003526 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527 sp->error = TRUE;
3528 sp->fileformat = EOL_UNIX;
3529 }
3530 }
3531#endif
3532 /* The '\n' is escaped if there is an odd number of ^V's just
3533 * before it, first set "c" just before the 'V's and then check
3534 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3535 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3536 ;
3537 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3538 {
3539 sourcing_lnum++;
3540 continue;
3541 }
3542
3543 buf[len - 1] = NUL; /* remove the NL */
3544 }
3545
3546 /*
3547 * Check for ^C here now and then, so recursive :so can be broken.
3548 */
3549 line_breakcheck();
3550 break;
3551 }
3552
3553 if (have_read)
3554 return (char_u *)ga.ga_data;
3555
3556 vim_free(ga.ga_data);
3557 return NULL;
3558}
3559
Bram Moolenaar05159a02005-02-26 23:04:13 +00003560#if defined(FEAT_PROFILE) || defined(PROTO)
3561/*
3562 * Called when starting to read a script line.
3563 * "sourcing_lnum" must be correct!
3564 * When skipping lines it may not actually be executed, but we won't find out
3565 * until later and we need to store the time now.
3566 */
3567 void
3568script_line_start()
3569{
3570 scriptitem_T *si;
3571 sn_prl_T *pp;
3572
3573 if (current_SID <= 0 || current_SID > script_items.ga_len)
3574 return;
3575 si = &SCRIPT_ITEM(current_SID);
3576 if (si->sn_prof_on && sourcing_lnum >= 1)
3577 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003578 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003579 * here isn't counted. */
3580 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3581 si->sn_prl_idx = sourcing_lnum - 1;
3582 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3583 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3584 {
3585 /* Zero counters for a line that was not used before. */
3586 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3587 pp->snp_count = 0;
3588 profile_zero(&pp->sn_prl_total);
3589 profile_zero(&pp->sn_prl_self);
3590 ++si->sn_prl_ga.ga_len;
3591 }
3592 si->sn_prl_execed = FALSE;
3593 profile_start(&si->sn_prl_start);
3594 profile_zero(&si->sn_prl_children);
3595 profile_get_wait(&si->sn_prl_wait);
3596 }
3597}
3598
3599/*
3600 * Called when actually executing a function line.
3601 */
3602 void
3603script_line_exec()
3604{
3605 scriptitem_T *si;
3606
3607 if (current_SID <= 0 || current_SID > script_items.ga_len)
3608 return;
3609 si = &SCRIPT_ITEM(current_SID);
3610 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3611 si->sn_prl_execed = TRUE;
3612}
3613
3614/*
3615 * Called when done with a function line.
3616 */
3617 void
3618script_line_end()
3619{
3620 scriptitem_T *si;
3621 sn_prl_T *pp;
3622
3623 if (current_SID <= 0 || current_SID > script_items.ga_len)
3624 return;
3625 si = &SCRIPT_ITEM(current_SID);
3626 if (si->sn_prof_on && si->sn_prl_idx >= 0
3627 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3628 {
3629 if (si->sn_prl_execed)
3630 {
3631 pp = &PRL_ITEM(si, si->sn_prl_idx);
3632 ++pp->snp_count;
3633 profile_end(&si->sn_prl_start);
3634 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003635 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003636 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3637 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003638 }
3639 si->sn_prl_idx = -1;
3640 }
3641}
3642#endif
3643
Bram Moolenaar071d4272004-06-13 20:20:40 +00003644/*
3645 * ":scriptencoding": Set encoding conversion for a sourced script.
3646 * Without the multi-byte feature it's simply ignored.
3647 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003648 void
3649ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003650 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003651{
3652#ifdef FEAT_MBYTE
3653 struct source_cookie *sp;
3654 char_u *name;
3655
3656 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3657 {
3658 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3659 return;
3660 }
3661
3662 if (*eap->arg != NUL)
3663 {
3664 name = enc_canonize(eap->arg);
3665 if (name == NULL) /* out of memory */
3666 return;
3667 }
3668 else
3669 name = eap->arg;
3670
3671 /* Setup for conversion from the specified encoding to 'encoding'. */
3672 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3673 convert_setup(&sp->conv, name, p_enc);
3674
3675 if (name != eap->arg)
3676 vim_free(name);
3677#endif
3678}
3679
3680#if defined(FEAT_EVAL) || defined(PROTO)
3681/*
3682 * ":finish": Mark a sourced file as finished.
3683 */
3684 void
3685ex_finish(eap)
3686 exarg_T *eap;
3687{
3688 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3689 do_finish(eap, FALSE);
3690 else
3691 EMSG(_("E168: :finish used outside of a sourced file"));
3692}
3693
3694/*
3695 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3696 * Also called for a pending finish at the ":endtry" or after returning from
3697 * an extra do_cmdline(). "reanimate" is used in the latter case.
3698 */
3699 void
3700do_finish(eap, reanimate)
3701 exarg_T *eap;
3702 int reanimate;
3703{
3704 int idx;
3705
3706 if (reanimate)
3707 ((struct source_cookie *)getline_cookie(eap->getline,
3708 eap->cookie))->finished = FALSE;
3709
3710 /*
3711 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3712 * not in its finally clause (which then is to be executed next) is found.
3713 * In this case, make the ":finish" pending for execution at the ":endtry".
3714 * Otherwise, finish normally.
3715 */
3716 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3717 if (idx >= 0)
3718 {
3719 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3720 report_make_pending(CSTP_FINISH, NULL);
3721 }
3722 else
3723 ((struct source_cookie *)getline_cookie(eap->getline,
3724 eap->cookie))->finished = TRUE;
3725}
3726
3727
3728/*
3729 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3730 * message for missing ":endif".
3731 * Return FALSE when not sourcing a file.
3732 */
3733 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003734source_finished(fgetline, cookie)
3735 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736 void *cookie;
3737{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003738 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003740 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741}
3742#endif
3743
3744#if defined(FEAT_LISTCMDS) || defined(PROTO)
3745/*
3746 * ":checktime [buffer]"
3747 */
3748 void
3749ex_checktime(eap)
3750 exarg_T *eap;
3751{
3752 buf_T *buf;
3753 int save_no_check_timestamps = no_check_timestamps;
3754
3755 no_check_timestamps = 0;
3756 if (eap->addr_count == 0) /* default is all buffers */
3757 check_timestamps(FALSE);
3758 else
3759 {
3760 buf = buflist_findnr((int)eap->line2);
3761 if (buf != NULL) /* cannot happen? */
3762 (void)buf_check_timestamp(buf, FALSE);
3763 }
3764 no_check_timestamps = save_no_check_timestamps;
3765}
3766#endif
3767
Bram Moolenaar071d4272004-06-13 20:20:40 +00003768#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3769 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3770static char *get_locale_val __ARGS((int what));
3771
3772 static char *
3773get_locale_val(what)
3774 int what;
3775{
3776 char *loc;
3777
3778 /* Obtain the locale value from the libraries. For DJGPP this is
3779 * redefined and it doesn't use the arguments. */
3780 loc = setlocale(what, NULL);
3781
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003782# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783 if (loc != NULL)
3784 {
3785 char_u *p;
3786
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003787 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3788 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 p = vim_strchr(loc, '=');
3790 if (p != NULL)
3791 {
3792 loc = ++p;
3793 while (*p != NUL) /* remove trailing newline */
3794 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003795 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003796 {
3797 *p = NUL;
3798 break;
3799 }
3800 ++p;
3801 }
3802 }
3803 }
3804# endif
3805
3806 return loc;
3807}
3808#endif
3809
3810
3811#ifdef WIN32
3812/*
3813 * On MS-Windows locale names are strings like "German_Germany.1252", but
3814 * gettext expects "de". Try to translate one into another here for a few
3815 * supported languages.
3816 */
3817 static char_u *
3818gettext_lang(char_u *name)
3819{
3820 int i;
3821 static char *(mtable[]) = {
3822 "afrikaans", "af",
3823 "czech", "cs",
3824 "dutch", "nl",
3825 "german", "de",
3826 "english_united kingdom", "en_GB",
3827 "spanish", "es",
3828 "french", "fr",
3829 "italian", "it",
3830 "japanese", "ja",
3831 "korean", "ko",
3832 "norwegian", "no",
3833 "polish", "pl",
3834 "russian", "ru",
3835 "slovak", "sk",
3836 "swedish", "sv",
3837 "ukrainian", "uk",
3838 "chinese_china", "zh_CN",
3839 "chinese_taiwan", "zh_TW",
3840 NULL};
3841
3842 for (i = 0; mtable[i] != NULL; i += 2)
3843 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3844 return mtable[i + 1];
3845 return name;
3846}
3847#endif
3848
3849#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3850/*
3851 * Obtain the current messages language. Used to set the default for
3852 * 'helplang'. May return NULL or an empty string.
3853 */
3854 char_u *
3855get_mess_lang()
3856{
3857 char_u *p;
3858
3859# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3860# if defined(LC_MESSAGES)
3861 p = (char_u *)get_locale_val(LC_MESSAGES);
3862# else
3863 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003864 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3865 * and LC_MONETARY may be set differently for a Japanese working in the
3866 * US. */
3867 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868# endif
3869# else
3870 p = mch_getenv((char_u *)"LC_ALL");
3871 if (p == NULL || *p == NUL)
3872 {
3873 p = mch_getenv((char_u *)"LC_MESSAGES");
3874 if (p == NULL || *p == NUL)
3875 p = mch_getenv((char_u *)"LANG");
3876 }
3877# endif
3878# ifdef WIN32
3879 p = gettext_lang(p);
3880# endif
3881 return p;
3882}
3883#endif
3884
Bram Moolenaardef9e822004-12-31 20:58:58 +00003885/* Complicated #if; matches with where get_mess_env() is used below. */
3886#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3887 && defined(LC_MESSAGES))) \
3888 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3889 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3890 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003891static char_u *get_mess_env __ARGS((void));
3892
3893/*
3894 * Get the language used for messages from the environment.
3895 */
3896 static char_u *
3897get_mess_env()
3898{
3899 char_u *p;
3900
3901 p = mch_getenv((char_u *)"LC_ALL");
3902 if (p == NULL || *p == NUL)
3903 {
3904 p = mch_getenv((char_u *)"LC_MESSAGES");
3905 if (p == NULL || *p == NUL)
3906 {
3907 p = mch_getenv((char_u *)"LANG");
3908 if (p != NULL && VIM_ISDIGIT(*p))
3909 p = NULL; /* ignore something like "1043" */
3910# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3911 if (p == NULL || *p == NUL)
3912 p = (char_u *)get_locale_val(LC_CTYPE);
3913# endif
3914 }
3915 }
3916 return p;
3917}
3918#endif
3919
3920#if defined(FEAT_EVAL) || defined(PROTO)
3921
3922/*
3923 * Set the "v:lang" variable according to the current locale setting.
3924 * Also do "v:lc_time"and "v:ctype".
3925 */
3926 void
3927set_lang_var()
3928{
3929 char_u *loc;
3930
3931# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3932 loc = (char_u *)get_locale_val(LC_CTYPE);
3933# else
3934 /* setlocale() not supported: use the default value */
3935 loc = (char_u *)"C";
3936# endif
3937 set_vim_var_string(VV_CTYPE, loc, -1);
3938
3939 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3940 * back to LC_CTYPE if it's empty. */
3941# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
3942 loc = (char_u *)get_locale_val(LC_MESSAGES);
3943# else
3944 loc = get_mess_env();
3945# endif
3946 set_vim_var_string(VV_LANG, loc, -1);
3947
3948# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3949 loc = (char_u *)get_locale_val(LC_TIME);
3950# endif
3951 set_vim_var_string(VV_LC_TIME, loc, -1);
3952}
3953#endif
3954
3955#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3956 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
3957/*
3958 * ":language": Set the language (locale).
3959 */
3960 void
3961ex_language(eap)
3962 exarg_T *eap;
3963{
3964 char *loc;
3965 char_u *p;
3966 char_u *name;
3967 int what = LC_ALL;
3968 char *whatstr = "";
3969#ifdef LC_MESSAGES
3970# define VIM_LC_MESSAGES LC_MESSAGES
3971#else
3972# define VIM_LC_MESSAGES 6789
3973#endif
3974
3975 name = eap->arg;
3976
3977 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3978 * Allow abbreviation, but require at least 3 characters to avoid
3979 * confusion with a two letter language name "me" or "ct". */
3980 p = skiptowhite(eap->arg);
3981 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
3982 {
3983 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3984 {
3985 what = VIM_LC_MESSAGES;
3986 name = skipwhite(p);
3987 whatstr = "messages ";
3988 }
3989 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3990 {
3991 what = LC_CTYPE;
3992 name = skipwhite(p);
3993 whatstr = "ctype ";
3994 }
3995 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
3996 {
3997 what = LC_TIME;
3998 name = skipwhite(p);
3999 whatstr = "time ";
4000 }
4001 }
4002
4003 if (*name == NUL)
4004 {
4005#ifndef LC_MESSAGES
4006 if (what == VIM_LC_MESSAGES)
4007 p = get_mess_env();
4008 else
4009#endif
4010 p = (char_u *)setlocale(what, NULL);
4011 if (p == NULL || *p == NUL)
4012 p = (char_u *)"Unknown";
4013 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4014 }
4015 else
4016 {
4017#ifndef LC_MESSAGES
4018 if (what == VIM_LC_MESSAGES)
4019 loc = "";
4020 else
4021#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004022 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004024#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4025 /* Make sure strtod() uses a decimal point, not a comma. */
4026 setlocale(LC_NUMERIC, "C");
4027#endif
4028 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004029 if (loc == NULL)
4030 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4031 else
4032 {
4033#ifdef HAVE_NL_MSG_CAT_CNTR
4034 /* Need to do this for GNU gettext, otherwise cached translations
4035 * will be used again. */
4036 extern int _nl_msg_cat_cntr;
4037
4038 ++_nl_msg_cat_cntr;
4039#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004040 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004041 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4042
4043 if (what != LC_TIME)
4044 {
4045 /* Tell gettext() what to translate to. It apparently doesn't
4046 * use the currently effective locale. Also do this when
4047 * FEAT_GETTEXT isn't defined, so that shell commands use this
4048 * value. */
4049 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004050 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004051 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004052# ifdef WIN32
4053 /* Apparently MS-Windows printf() may cause a crash when
4054 * we give it 8-bit text while it's expecting text in the
4055 * current locale. This call avoids that. */
4056 setlocale(LC_CTYPE, "C");
4057# endif
4058 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004059 if (what != LC_CTYPE)
4060 {
4061 char_u *mname;
4062#ifdef WIN32
4063 mname = gettext_lang(name);
4064#else
4065 mname = name;
4066#endif
4067 vim_setenv((char_u *)"LC_MESSAGES", mname);
4068#ifdef FEAT_MULTI_LANG
4069 set_helplang_default(mname);
4070#endif
4071 }
4072
4073 /* Set $LC_CTYPE, because it overrules $LANG, and
4074 * gtk_set_locale() calls setlocale() again. gnome_init()
4075 * sets $LC_CTYPE to "en_US" (that's a bug!). */
4076 if (what != VIM_LC_MESSAGES)
4077 vim_setenv((char_u *)"LC_CTYPE", name);
4078# ifdef FEAT_GUI_GTK
4079 /* Let GTK know what locale we're using. Not sure this is
4080 * really needed... */
4081 if (gui.in_use)
4082 (void)gtk_set_locale();
4083# endif
4084 }
4085
4086# ifdef FEAT_EVAL
4087 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4088 set_lang_var();
4089# endif
4090 }
4091 }
4092}
4093
4094# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4095/*
4096 * Function given to ExpandGeneric() to obtain the possible arguments of the
4097 * ":language" command.
4098 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004099 char_u *
4100get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004101 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004102 int idx;
4103{
4104 if (idx == 0)
4105 return (char_u *)"messages";
4106 if (idx == 1)
4107 return (char_u *)"ctype";
4108 if (idx == 2)
4109 return (char_u *)"time";
4110 return NULL;
4111}
4112# endif
4113
4114#endif