blob: a4f60c46d4aa9f4b93fba021a6c93cf487e23b22 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaarc236c162008-07-13 17:41:49 +000014#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
Bram Moolenaar8c8de832008-06-24 22:58:06 +000015# include "vimio.h" /* for mch_open(), must be before vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +000016#endif
17
18#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000019#include "version.h"
20
21static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
22
Bram Moolenaar05159a02005-02-26 23:04:13 +000023#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000024/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000025 * For Unix also store the dev/ino, so that we don't have to stat() each
26 * script when going through the list. */
27typedef struct scriptitem_S
28{
29 char_u *sn_name;
30# ifdef UNIX
31 int sn_dev;
32 ino_t sn_ino;
33# endif
34# ifdef FEAT_PROFILE
35 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000036 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000037 proftime_T sn_pr_child; /* time set when going into first child */
38 int sn_pr_nest; /* nesting for sn_pr_child */
39 /* profiling the script as a whole */
40 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000041 proftime_T sn_pr_total; /* time spent in script + children */
42 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000043 proftime_T sn_pr_start; /* time at script start */
44 proftime_T sn_pr_children; /* time in children after script start */
45 /* profiling the script per line */
46 garray_T sn_prl_ga; /* things stored for every line */
47 proftime_T sn_prl_start; /* start time for current line */
48 proftime_T sn_prl_children; /* time spent in children for this line */
49 proftime_T sn_prl_wait; /* wait start time for current line */
50 int sn_prl_idx; /* index of line being timed; -1 if none */
51 int sn_prl_execed; /* line being timed was executed */
52# endif
53} scriptitem_T;
54
55static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
56#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
57
58# ifdef FEAT_PROFILE
59/* Struct used in sn_prl_ga for every line of a script. */
60typedef struct sn_prl_S
61{
62 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000063 proftime_T sn_prl_total; /* time spent in a line + children */
64 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000065} sn_prl_T;
66
67# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
68# endif
69#endif
70
Bram Moolenaar071d4272004-06-13 20:20:40 +000071#if defined(FEAT_EVAL) || defined(PROTO)
72static int debug_greedy = FALSE; /* batch mode debugging: don't save
73 and restore typeahead. */
74
75/*
76 * do_debug(): Debug mode.
77 * Repeatedly get Ex commands, until told to continue normal execution.
78 */
79 void
80do_debug(cmd)
81 char_u *cmd;
82{
83 int save_msg_scroll = msg_scroll;
84 int save_State = State;
85 int save_did_emsg = did_emsg;
86 int save_cmd_silent = cmd_silent;
87 int save_msg_silent = msg_silent;
88 int save_emsg_silent = emsg_silent;
89 int save_redir_off = redir_off;
90 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000091 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000092 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093# ifdef FEAT_EX_EXTRA
94 int save_ex_normal_busy;
95# endif
96 int n;
97 char_u *cmdline = NULL;
98 char_u *p;
99 char *tail = NULL;
100 static int last_cmd = 0;
101#define CMD_CONT 1
102#define CMD_NEXT 2
103#define CMD_STEP 3
104#define CMD_FINISH 4
105#define CMD_QUIT 5
106#define CMD_INTERRUPT 6
107
108#ifdef ALWAYS_USE_GUI
109 /* Can't do this when there is no terminal for input/output. */
110 if (!gui.in_use)
111 {
112 /* Break as soon as possible. */
113 debug_break_level = 9999;
114 return;
115 }
116#endif
117
118 /* Make sure we are in raw mode and start termcap mode. Might have side
119 * effects... */
120 settmode(TMODE_RAW);
121 starttermcap();
122
123 ++RedrawingDisabled; /* don't redisplay the window */
124 ++no_wait_return; /* don't wait for return */
125 did_emsg = FALSE; /* don't use error from debugged stuff */
126 cmd_silent = FALSE; /* display commands */
127 msg_silent = FALSE; /* display messages */
128 emsg_silent = FALSE; /* display error messages */
129 redir_off = TRUE; /* don't redirect debug commands */
130
131 State = NORMAL;
132#ifdef FEAT_SNIFF
133 want_sniff_request = 0; /* No K_SNIFF wanted */
134#endif
135
136 if (!debug_did_msg)
137 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
138 if (sourcing_name != NULL)
139 msg(sourcing_name);
140 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000141 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000142 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000143 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144
145 /*
146 * Repeat getting a command and executing it.
147 */
148 for (;;)
149 {
150 msg_scroll = TRUE;
151 need_wait_return = FALSE;
152#ifdef FEAT_SNIFF
153 ProcessSniffRequests();
154#endif
155 /* Save the current typeahead buffer and replace it with an empty one.
156 * This makes sure we get input from the user here and don't interfere
157 * with the commands being executed. Reset "ex_normal_busy" to avoid
158 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000159 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160# ifdef FEAT_EX_EXTRA
161 save_ex_normal_busy = ex_normal_busy;
162 ex_normal_busy = 0;
163# endif
164 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000165 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000167 typeahead_saved = TRUE;
168 save_ignore_script = ignore_script;
169 ignore_script = TRUE;
170 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000172 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000174 if (typeahead_saved)
175 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000177 ignore_script = save_ignore_script;
178 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179# ifdef FEAT_EX_EXTRA
180 ex_normal_busy = save_ex_normal_busy;
181# endif
182
183 cmdline_row = msg_row;
184 if (cmdline != NULL)
185 {
186 /* If this is a debug command, set "last_cmd".
187 * If not, reset "last_cmd".
188 * For a blank line use previous command. */
189 p = skipwhite(cmdline);
190 if (*p != NUL)
191 {
192 switch (*p)
193 {
194 case 'c': last_cmd = CMD_CONT;
195 tail = "ont";
196 break;
197 case 'n': last_cmd = CMD_NEXT;
198 tail = "ext";
199 break;
200 case 's': last_cmd = CMD_STEP;
201 tail = "tep";
202 break;
203 case 'f': last_cmd = CMD_FINISH;
204 tail = "inish";
205 break;
206 case 'q': last_cmd = CMD_QUIT;
207 tail = "uit";
208 break;
209 case 'i': last_cmd = CMD_INTERRUPT;
210 tail = "nterrupt";
211 break;
212 default: last_cmd = 0;
213 }
214 if (last_cmd != 0)
215 {
216 /* Check that the tail matches. */
217 ++p;
218 while (*p != NUL && *p == *tail)
219 {
220 ++p;
221 ++tail;
222 }
223 if (ASCII_ISALPHA(*p))
224 last_cmd = 0;
225 }
226 }
227
228 if (last_cmd != 0)
229 {
230 /* Execute debug command: decided where to break next and
231 * return. */
232 switch (last_cmd)
233 {
234 case CMD_CONT:
235 debug_break_level = -1;
236 break;
237 case CMD_NEXT:
238 debug_break_level = ex_nesting_level;
239 break;
240 case CMD_STEP:
241 debug_break_level = 9999;
242 break;
243 case CMD_FINISH:
244 debug_break_level = ex_nesting_level - 1;
245 break;
246 case CMD_QUIT:
247 got_int = TRUE;
248 debug_break_level = -1;
249 break;
250 case CMD_INTERRUPT:
251 got_int = TRUE;
252 debug_break_level = 9999;
253 /* Do not repeat ">interrupt" cmd, continue stepping. */
254 last_cmd = CMD_STEP;
255 break;
256 }
257 break;
258 }
259
260 /* don't debug this command */
261 n = debug_break_level;
262 debug_break_level = -1;
263 (void)do_cmdline(cmdline, getexline, NULL,
264 DOCMD_VERBOSE|DOCMD_EXCRESET);
265 debug_break_level = n;
266
267 vim_free(cmdline);
268 }
269 lines_left = Rows - 1;
270 }
271 vim_free(cmdline);
272
273 --RedrawingDisabled;
274 --no_wait_return;
275 redraw_all_later(NOT_VALID);
276 need_wait_return = FALSE;
277 msg_scroll = save_msg_scroll;
278 lines_left = Rows - 1;
279 State = save_State;
280 did_emsg = save_did_emsg;
281 cmd_silent = save_cmd_silent;
282 msg_silent = save_msg_silent;
283 emsg_silent = save_emsg_silent;
284 redir_off = save_redir_off;
285
286 /* Only print the message again when typing a command before coming back
287 * here. */
288 debug_did_msg = TRUE;
289}
290
291/*
292 * ":debug".
293 */
294 void
295ex_debug(eap)
296 exarg_T *eap;
297{
298 int debug_break_level_save = debug_break_level;
299
300 debug_break_level = 9999;
301 do_cmdline_cmd(eap->arg);
302 debug_break_level = debug_break_level_save;
303}
304
305static char_u *debug_breakpoint_name = NULL;
306static linenr_T debug_breakpoint_lnum;
307
308/*
309 * When debugging or a breakpoint is set on a skipped command, no debug prompt
310 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
311 * debug_skipped_name is then set to the source name in the breakpoint case. If
312 * a skipped command decides itself that a debug prompt should be displayed, it
313 * can do so by calling dbg_check_skipped().
314 */
315static int debug_skipped;
316static char_u *debug_skipped_name;
317
318/*
319 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
320 * at or below the break level. But only when the line is actually
321 * executed. Return TRUE and set breakpoint_name for skipped commands that
322 * decide to execute something themselves.
323 * Called from do_one_cmd() before executing a command.
324 */
325 void
326dbg_check_breakpoint(eap)
327 exarg_T *eap;
328{
329 char_u *p;
330
331 debug_skipped = FALSE;
332 if (debug_breakpoint_name != NULL)
333 {
334 if (!eap->skip)
335 {
336 /* replace K_SNR with "<SNR>" */
337 if (debug_breakpoint_name[0] == K_SPECIAL
338 && debug_breakpoint_name[1] == KS_EXTRA
339 && debug_breakpoint_name[2] == (int)KE_SNR)
340 p = (char_u *)"<SNR>";
341 else
342 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000343 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
344 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000345 debug_breakpoint_name + (*p == NUL ? 0 : 3),
346 (long)debug_breakpoint_lnum);
347 debug_breakpoint_name = NULL;
348 do_debug(eap->cmd);
349 }
350 else
351 {
352 debug_skipped = TRUE;
353 debug_skipped_name = debug_breakpoint_name;
354 debug_breakpoint_name = NULL;
355 }
356 }
357 else if (ex_nesting_level <= debug_break_level)
358 {
359 if (!eap->skip)
360 do_debug(eap->cmd);
361 else
362 {
363 debug_skipped = TRUE;
364 debug_skipped_name = NULL;
365 }
366 }
367}
368
369/*
370 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
371 * set. Return TRUE when the debug mode is entered this time.
372 */
373 int
374dbg_check_skipped(eap)
375 exarg_T *eap;
376{
377 int prev_got_int;
378
379 if (debug_skipped)
380 {
381 /*
382 * Save the value of got_int and reset it. We don't want a previous
383 * interruption cause flushing the input buffer.
384 */
385 prev_got_int = got_int;
386 got_int = FALSE;
387 debug_breakpoint_name = debug_skipped_name;
388 /* eap->skip is TRUE */
389 eap->skip = FALSE;
390 (void)dbg_check_breakpoint(eap);
391 eap->skip = TRUE;
392 got_int |= prev_got_int;
393 return TRUE;
394 }
395 return FALSE;
396}
397
398/*
399 * The list of breakpoints: dbg_breakp.
400 * This is a grow-array of structs.
401 */
402struct debuggy
403{
404 int dbg_nr; /* breakpoint number */
405 int dbg_type; /* DBG_FUNC or DBG_FILE */
406 char_u *dbg_name; /* function or file name */
407 regprog_T *dbg_prog; /* regexp program */
408 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000409 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410};
411
412static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000413#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
414#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415static int last_breakp = 0; /* nr of last defined breakpoint */
416
Bram Moolenaar05159a02005-02-26 23:04:13 +0000417#ifdef FEAT_PROFILE
418/* Profiling uses file and func names similar to breakpoints. */
419static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
420#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000421#define DBG_FUNC 1
422#define DBG_FILE 2
423
Bram Moolenaar05159a02005-02-26 23:04:13 +0000424static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
425static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, garray_T *gap, int *fp));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000426
427/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000428 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
429 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
430 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 * Returns FAIL for failure.
432 */
433 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000434dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000435 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000436 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437{
438 char_u *p = arg;
439 char_u *q;
440 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000441 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000442
Bram Moolenaar05159a02005-02-26 23:04:13 +0000443 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000444 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000445 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446
447 /* Find "func" or "file". */
448 if (STRNCMP(p, "func", 4) == 0)
449 bp->dbg_type = DBG_FUNC;
450 else if (STRNCMP(p, "file", 4) == 0)
451 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000452 else if (
453#ifdef FEAT_PROFILE
454 gap != &prof_ga &&
455#endif
456 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000457 {
458 if (curbuf->b_ffname == NULL)
459 {
460 EMSG(_(e_noname));
461 return FAIL;
462 }
463 bp->dbg_type = DBG_FILE;
464 here = TRUE;
465 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000466 else
467 {
468 EMSG2(_(e_invarg2), p);
469 return FAIL;
470 }
471 p = skipwhite(p + 4);
472
473 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000474 if (here)
475 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000476 else if (
477#ifdef FEAT_PROFILE
478 gap != &prof_ga &&
479#endif
480 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000481 {
482 bp->dbg_lnum = getdigits(&p);
483 p = skipwhite(p);
484 }
485 else
486 bp->dbg_lnum = 0;
487
488 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000489 if ((!here && *p == NUL)
490 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
492 {
493 EMSG2(_(e_invarg2), arg);
494 return FAIL;
495 }
496
497 if (bp->dbg_type == DBG_FUNC)
498 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000499 else if (here)
500 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000501 else
502 {
503 /* Expand the file name in the same way as do_source(). This means
504 * doing it twice, so that $DIR/file gets expanded when $DIR is
505 * "~/dir". */
506#ifdef RISCOS
507 q = mch_munge_fname(p);
508#else
509 q = expand_env_save(p);
510#endif
511 if (q == NULL)
512 return FAIL;
513#ifdef RISCOS
514 p = mch_munge_fname(q);
515#else
516 p = expand_env_save(q);
517#endif
518 vim_free(q);
519 if (p == NULL)
520 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000521 if (*p != '*')
522 {
523 bp->dbg_name = fix_fname(p);
524 vim_free(p);
525 }
526 else
527 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000528 }
529
530 if (bp->dbg_name == NULL)
531 return FAIL;
532 return OK;
533}
534
535/*
536 * ":breakadd".
537 */
538 void
539ex_breakadd(eap)
540 exarg_T *eap;
541{
542 struct debuggy *bp;
543 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000544 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545
Bram Moolenaar05159a02005-02-26 23:04:13 +0000546 gap = &dbg_breakp;
547#ifdef FEAT_PROFILE
548 if (eap->cmdidx == CMD_profile)
549 gap = &prof_ga;
550#endif
551
552 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000554 bp = &DEBUGGY(gap, gap->ga_len);
555 bp->dbg_forceit = eap->forceit;
556
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
558 if (pat != NULL)
559 {
560 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
561 vim_free(pat);
562 }
563 if (pat == NULL || bp->dbg_prog == NULL)
564 vim_free(bp->dbg_name);
565 else
566 {
567 if (bp->dbg_lnum == 0) /* default line number is 1 */
568 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000569#ifdef FEAT_PROFILE
570 if (eap->cmdidx != CMD_profile)
571#endif
572 {
573 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
574 ++debug_tick;
575 }
576 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577 }
578 }
579}
580
581/*
582 * ":debuggreedy".
583 */
584 void
585ex_debuggreedy(eap)
586 exarg_T *eap;
587{
588 if (eap->addr_count == 0 || eap->line2 != 0)
589 debug_greedy = TRUE;
590 else
591 debug_greedy = FALSE;
592}
593
594/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000595 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596 */
597 void
598ex_breakdel(eap)
599 exarg_T *eap;
600{
601 struct debuggy *bp, *bpi;
602 int nr;
603 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000604 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 int i;
606 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000607 garray_T *gap;
608
609 gap = &dbg_breakp;
610#ifdef FEAT_PROFILE
611 if (eap->cmdidx == CMD_profdel)
612 gap = &prof_ga;
613#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000614
615 if (vim_isdigit(*eap->arg))
616 {
617 /* ":breakdel {nr}" */
618 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000619 for (i = 0; i < gap->ga_len; ++i)
620 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000621 {
622 todel = i;
623 break;
624 }
625 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000626 else if (*eap->arg == '*')
627 {
628 todel = 0;
629 del_all = TRUE;
630 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 else
632 {
633 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000634 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000636 bp = &DEBUGGY(gap, gap->ga_len);
637 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000639 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640 if (bp->dbg_type == bpi->dbg_type
641 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
642 && (bp->dbg_lnum == bpi->dbg_lnum
643 || (bp->dbg_lnum == 0
644 && (best_lnum == 0
645 || bpi->dbg_lnum < best_lnum))))
646 {
647 todel = i;
648 best_lnum = bpi->dbg_lnum;
649 }
650 }
651 vim_free(bp->dbg_name);
652 }
653
654 if (todel < 0)
655 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
656 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000657 {
658 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000659 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000660 vim_free(DEBUGGY(gap, todel).dbg_name);
661 vim_free(DEBUGGY(gap, todel).dbg_prog);
662 --gap->ga_len;
663 if (todel < gap->ga_len)
664 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
665 (gap->ga_len - todel) * sizeof(struct debuggy));
666#ifdef FEAT_PROFILE
667 if (eap->cmdidx == CMD_breakdel)
668#endif
669 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000670 if (!del_all)
671 break;
672 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000673
674 /* If all breakpoints were removed clear the array. */
675 if (gap->ga_len == 0)
676 ga_clear(gap);
677 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678}
679
680/*
681 * ":breaklist".
682 */
683/*ARGSUSED*/
684 void
685ex_breaklist(eap)
686 exarg_T *eap;
687{
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 */
1345/*ARGSUSED*/
1346 int
1347check_changed(buf, checkaw, mult_win, forceit, allbuf)
1348 buf_T *buf;
1349 int checkaw; /* do autowrite if buffer was changed */
1350 int mult_win; /* check also when several wins for the buf */
1351 int forceit;
1352 int allbuf; /* may write all buffers */
1353{
1354 if ( !forceit
1355 && bufIsChanged(buf)
1356 && (mult_win || buf->b_nwindows <= 1)
1357 && (!checkaw || autowrite(buf, forceit) == FAIL))
1358 {
1359#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1360 if ((p_confirm || cmdmod.confirm) && p_write)
1361 {
1362 buf_T *buf2;
1363 int count = 0;
1364
1365 if (allbuf)
1366 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1367 if (bufIsChanged(buf2)
1368 && (buf2->b_ffname != NULL
1369# ifdef FEAT_BROWSE
1370 || cmdmod.browse
1371# endif
1372 ))
1373 ++count;
1374# ifdef FEAT_AUTOCMD
1375 if (!buf_valid(buf))
1376 /* Autocommand deleted buffer, oops! It's not changed now. */
1377 return FALSE;
1378# endif
1379 dialog_changed(buf, count > 1);
1380# ifdef FEAT_AUTOCMD
1381 if (!buf_valid(buf))
1382 /* Autocommand deleted buffer, oops! It's not changed now. */
1383 return FALSE;
1384# endif
1385 return bufIsChanged(buf);
1386 }
1387#endif
1388 EMSG(_(e_nowrtmsg));
1389 return TRUE;
1390 }
1391 return FALSE;
1392}
1393
1394#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1395
1396#if defined(FEAT_BROWSE) || defined(PROTO)
1397/*
1398 * When wanting to write a file without a file name, ask the user for a name.
1399 */
1400 void
1401browse_save_fname(buf)
1402 buf_T *buf;
1403{
1404 if (buf->b_fname == NULL)
1405 {
1406 char_u *fname;
1407
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001408 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1409 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001410 if (fname != NULL)
1411 {
1412 if (setfname(buf, fname, NULL, TRUE) == OK)
1413 buf->b_flags |= BF_NOTEDITED;
1414 vim_free(fname);
1415 }
1416 }
1417}
1418#endif
1419
1420/*
1421 * Ask the user what to do when abondoning a changed buffer.
1422 * Must check 'write' option first!
1423 */
1424 void
1425dialog_changed(buf, checkall)
1426 buf_T *buf;
1427 int checkall; /* may abandon all changed buffers */
1428{
1429 char_u buff[IOSIZE];
1430 int ret;
1431 buf_T *buf2;
1432
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001433 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001434 (buf->b_fname != NULL) ?
1435 buf->b_fname : (char_u *)_("Untitled"));
1436 if (checkall)
1437 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1438 else
1439 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1440
1441 if (ret == VIM_YES)
1442 {
1443#ifdef FEAT_BROWSE
1444 /* May get file name, when there is none */
1445 browse_save_fname(buf);
1446#endif
1447 if (buf->b_fname != NULL) /* didn't hit Cancel */
1448 (void)buf_write_all(buf, FALSE);
1449 }
1450 else if (ret == VIM_NO)
1451 {
1452 unchanged(buf, TRUE);
1453 }
1454 else if (ret == VIM_ALL)
1455 {
1456 /*
1457 * Write all modified files that can be written.
1458 * Skip readonly buffers, these need to be confirmed
1459 * individually.
1460 */
1461 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1462 {
1463 if (bufIsChanged(buf2)
1464 && (buf2->b_ffname != NULL
1465#ifdef FEAT_BROWSE
1466 || cmdmod.browse
1467#endif
1468 )
1469 && !buf2->b_p_ro)
1470 {
1471#ifdef FEAT_BROWSE
1472 /* May get file name, when there is none */
1473 browse_save_fname(buf2);
1474#endif
1475 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1476 (void)buf_write_all(buf2, FALSE);
1477#ifdef FEAT_AUTOCMD
1478 /* an autocommand may have deleted the buffer */
1479 if (!buf_valid(buf2))
1480 buf2 = firstbuf;
1481#endif
1482 }
1483 }
1484 }
1485 else if (ret == VIM_DISCARDALL)
1486 {
1487 /*
1488 * mark all buffers as unchanged
1489 */
1490 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1491 unchanged(buf2, TRUE);
1492 }
1493}
1494#endif
1495
1496/*
1497 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1498 * hidden, autowriting it or unloading it.
1499 */
1500 int
1501can_abandon(buf, forceit)
1502 buf_T *buf;
1503 int forceit;
1504{
1505 return ( P_HID(buf)
1506 || !bufIsChanged(buf)
1507 || buf->b_nwindows > 1
1508 || autowrite(buf, forceit) == OK
1509 || forceit);
1510}
1511
1512/*
1513 * Return TRUE if any buffer was changed and cannot be abandoned.
1514 * That changed buffer becomes the current buffer.
1515 */
1516 int
1517check_changed_any(hidden)
1518 int hidden; /* Only check hidden buffers */
1519{
1520 buf_T *buf;
1521 int save;
1522#ifdef FEAT_WINDOWS
1523 win_T *wp;
1524#endif
1525
1526 for (;;)
1527 {
1528 /* check curbuf first: if it was changed we can't abandon it */
1529 if (!hidden && curbufIsChanged())
1530 buf = curbuf;
1531 else
1532 {
1533 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1534 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1535 break;
1536 }
1537 if (buf == NULL) /* No buffers changed */
1538 return FALSE;
1539
Bram Moolenaar373154b2007-02-13 05:19:30 +00001540 /* Try auto-writing the buffer. If this fails but the buffer no
1541 * longer exists it's not changed, that's OK. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001542 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1543 break; /* didn't save - still changes */
1544 }
1545
1546 exiting = FALSE;
1547#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1548 /*
1549 * When ":confirm" used, don't give an error message.
1550 */
1551 if (!(p_confirm || cmdmod.confirm))
1552#endif
1553 {
1554 /* There must be a wait_return for this message, do_buffer()
1555 * may cause a redraw. But wait_return() is a no-op when vgetc()
1556 * is busy (Quit used from window menu), then make sure we don't
1557 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001558 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001559 {
1560 msg_row = cmdline_row;
1561 msg_col = 0;
1562 msg_didout = FALSE;
1563 }
1564 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1565 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1566 buf->b_fname))
1567 {
1568 save = no_wait_return;
1569 no_wait_return = FALSE;
1570 wait_return(FALSE);
1571 no_wait_return = save;
1572 }
1573 }
1574
1575#ifdef FEAT_WINDOWS
1576 /* Try to find a window that contains the buffer. */
1577 if (buf != curbuf)
1578 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1579 if (wp->w_buffer == buf)
1580 {
1581 win_goto(wp);
1582# ifdef FEAT_AUTOCMD
1583 /* Paranoia: did autocms wipe out the buffer with changes? */
1584 if (!buf_valid(buf))
1585 return TRUE;
1586# endif
1587 break;
1588 }
1589#endif
1590
1591 /* Open the changed buffer in the current window. */
1592 if (buf != curbuf)
1593 set_curbuf(buf, DOBUF_GOTO);
1594
1595 return TRUE;
1596}
1597
1598/*
1599 * return FAIL if there is no file name, OK if there is one
1600 * give error message for FAIL
1601 */
1602 int
1603check_fname()
1604{
1605 if (curbuf->b_ffname == NULL)
1606 {
1607 EMSG(_(e_noname));
1608 return FAIL;
1609 }
1610 return OK;
1611}
1612
1613/*
1614 * flush the contents of a buffer, unless it has no file name
1615 *
1616 * return FAIL for failure, OK otherwise
1617 */
1618 int
1619buf_write_all(buf, forceit)
1620 buf_T *buf;
1621 int forceit;
1622{
1623 int retval;
1624#ifdef FEAT_AUTOCMD
1625 buf_T *old_curbuf = curbuf;
1626#endif
1627
1628 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1629 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1630 FALSE, forceit, TRUE, FALSE));
1631#ifdef FEAT_AUTOCMD
1632 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001633 {
1634 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001635 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001636 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001637#endif
1638 return retval;
1639}
1640
1641/*
1642 * Code to handle the argument list.
1643 */
1644
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001645static char_u *do_one_arg __ARGS((char_u *str));
1646static int do_arglist __ARGS((char_u *str, int what, int after));
1647static void alist_check_arg_idx __ARGS((void));
1648static int editing_arg_idx __ARGS((win_T *win));
1649#ifdef FEAT_LISTCMDS
1650static int alist_add_list __ARGS((int count, char_u **files, int after));
1651#endif
1652#define AL_SET 1
1653#define AL_ADD 2
1654#define AL_DEL 3
1655
Bram Moolenaar071d4272004-06-13 20:20:40 +00001656/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001657 * Isolate one argument, taking backticks.
1658 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001659 * Return a pointer to the start of the next argument.
1660 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001661 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662do_one_arg(str)
1663 char_u *str;
1664{
1665 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001666 int inbacktick;
1667
Bram Moolenaar071d4272004-06-13 20:20:40 +00001668 inbacktick = FALSE;
1669 for (p = str; *str; ++str)
1670 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001671 /* When the backslash is used for escaping the special meaning of a
1672 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001673 if (rem_backslash(str))
1674 {
1675 *p++ = *str++;
1676 *p++ = *str;
1677 }
1678 else
1679 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001680 /* An item ends at a space not in backticks */
1681 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001682 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001683 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001685 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686 }
1687 }
1688 str = skipwhite(str);
1689 *p = NUL;
1690
1691 return str;
1692}
1693
Bram Moolenaar86b68352004-12-27 21:59:20 +00001694/*
1695 * Separate the arguments in "str" and return a list of pointers in the
1696 * growarray "gap".
1697 */
1698 int
1699get_arglist(gap, str)
1700 garray_T *gap;
1701 char_u *str;
1702{
1703 ga_init2(gap, (int)sizeof(char_u *), 20);
1704 while (*str != NUL)
1705 {
1706 if (ga_grow(gap, 1) == FAIL)
1707 {
1708 ga_clear(gap);
1709 return FAIL;
1710 }
1711 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1712
1713 /* Isolate one argument, change it in-place, put a NUL after it. */
1714 str = do_one_arg(str);
1715 }
1716 return OK;
1717}
1718
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001719#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001720/*
1721 * Parse a list of arguments (file names), expand them and return in
1722 * "fnames[fcountp]".
1723 * Return FAIL or OK.
1724 */
1725 int
1726get_arglist_exp(str, fcountp, fnamesp)
1727 char_u *str;
1728 int *fcountp;
1729 char_u ***fnamesp;
1730{
1731 garray_T ga;
1732 int i;
1733
1734 if (get_arglist(&ga, str) == FAIL)
1735 return FAIL;
1736 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1737 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1738 ga_clear(&ga);
1739 return i;
1740}
1741#endif
1742
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1744/*
1745 * Redefine the argument list.
1746 */
1747 void
1748set_arglist(str)
1749 char_u *str;
1750{
1751 do_arglist(str, AL_SET, 0);
1752}
1753#endif
1754
1755/*
1756 * "what" == AL_SET: Redefine the argument list to 'str'.
1757 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1758 * "what" == AL_DEL: remove files in 'str' from the argument list.
1759 *
1760 * Return FAIL for failure, OK otherwise.
1761 */
1762/*ARGSUSED*/
1763 static int
1764do_arglist(str, what, after)
1765 char_u *str;
1766 int what;
1767 int after; /* 0 means before first one */
1768{
1769 garray_T new_ga;
1770 int exp_count;
1771 char_u **exp_files;
1772 int i;
1773#ifdef FEAT_LISTCMDS
1774 char_u *p;
1775 int match;
1776#endif
1777
1778 /*
1779 * Collect all file name arguments in "new_ga".
1780 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001781 if (get_arglist(&new_ga, str) == FAIL)
1782 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783
1784#ifdef FEAT_LISTCMDS
1785 if (what == AL_DEL)
1786 {
1787 regmatch_T regmatch;
1788 int didone;
1789
1790 /*
1791 * Delete the items: use each item as a regexp and find a match in the
1792 * argument list.
1793 */
1794#ifdef CASE_INSENSITIVE_FILENAME
1795 regmatch.rm_ic = TRUE; /* Always ignore case */
1796#else
1797 regmatch.rm_ic = FALSE; /* Never ignore case */
1798#endif
1799 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1800 {
1801 p = ((char_u **)new_ga.ga_data)[i];
1802 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1803 if (p == NULL)
1804 break;
1805 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1806 if (regmatch.regprog == NULL)
1807 {
1808 vim_free(p);
1809 break;
1810 }
1811
1812 didone = FALSE;
1813 for (match = 0; match < ARGCOUNT; ++match)
1814 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1815 (colnr_T)0))
1816 {
1817 didone = TRUE;
1818 vim_free(ARGLIST[match].ae_fname);
1819 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1820 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1821 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822 if (curwin->w_arg_idx > match)
1823 --curwin->w_arg_idx;
1824 --match;
1825 }
1826
1827 vim_free(regmatch.regprog);
1828 vim_free(p);
1829 if (!didone)
1830 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1831 }
1832 ga_clear(&new_ga);
1833 }
1834 else
1835#endif
1836 {
1837 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1838 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1839 ga_clear(&new_ga);
1840 if (i == FAIL)
1841 return FAIL;
1842 if (exp_count == 0)
1843 {
1844 EMSG(_(e_nomatch));
1845 return FAIL;
1846 }
1847
1848#ifdef FEAT_LISTCMDS
1849 if (what == AL_ADD)
1850 {
1851 (void)alist_add_list(exp_count, exp_files, after);
1852 vim_free(exp_files);
1853 }
1854 else /* what == AL_SET */
1855#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001856 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857 }
1858
1859 alist_check_arg_idx();
1860
1861 return OK;
1862}
1863
1864/*
1865 * Check the validity of the arg_idx for each other window.
1866 */
1867 static void
1868alist_check_arg_idx()
1869{
1870#ifdef FEAT_WINDOWS
1871 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001872 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873
Bram Moolenaarf740b292006-02-16 22:11:02 +00001874 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875 if (win->w_alist == curwin->w_alist)
1876 check_arg_idx(win);
1877#else
1878 check_arg_idx(curwin);
1879#endif
1880}
1881
1882/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001883 * Return TRUE if window "win" is editing then file at the current argument
1884 * index.
1885 */
1886 static int
1887editing_arg_idx(win)
1888 win_T *win;
1889{
1890 return !(win->w_arg_idx >= WARGCOUNT(win)
1891 || (win->w_buffer->b_fnum
1892 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1893 && (win->w_buffer->b_ffname == NULL
1894 || !(fullpathcmp(
1895 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1896 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1897}
1898
1899/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 * Check if window "win" is editing the w_arg_idx file in its argument list.
1901 */
1902 void
1903check_arg_idx(win)
1904 win_T *win;
1905{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001906 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907 {
1908 /* We are not editing the current entry in the argument list.
1909 * Set "arg_had_last" if we are editing the last one. */
1910 win->w_arg_idx_invalid = TRUE;
1911 if (win->w_arg_idx != WARGCOUNT(win) - 1
1912 && arg_had_last == FALSE
1913#ifdef FEAT_WINDOWS
1914 && ALIST(win) == &global_alist
1915#endif
1916 && GARGCOUNT > 0
1917 && win->w_arg_idx < GARGCOUNT
1918 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1919 || (win->w_buffer->b_ffname != NULL
1920 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1921 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1922 arg_had_last = TRUE;
1923 }
1924 else
1925 {
1926 /* We are editing the current entry in the argument list.
1927 * Set "arg_had_last" if it's also the last one */
1928 win->w_arg_idx_invalid = FALSE;
1929 if (win->w_arg_idx == WARGCOUNT(win) - 1
1930#ifdef FEAT_WINDOWS
1931 && win->w_alist == &global_alist
1932#endif
1933 )
1934 arg_had_last = TRUE;
1935 }
1936}
1937
1938/*
1939 * ":args", ":argslocal" and ":argsglobal".
1940 */
1941 void
1942ex_args(eap)
1943 exarg_T *eap;
1944{
1945 int i;
1946
1947 if (eap->cmdidx != CMD_args)
1948 {
1949#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1950 alist_unlink(ALIST(curwin));
1951 if (eap->cmdidx == CMD_argglobal)
1952 ALIST(curwin) = &global_alist;
1953 else /* eap->cmdidx == CMD_arglocal */
1954 alist_new();
1955#else
1956 ex_ni(eap);
1957 return;
1958#endif
1959 }
1960
1961 if (!ends_excmd(*eap->arg))
1962 {
1963 /*
1964 * ":args file ..": define new argument list, handle like ":next"
1965 * Also for ":argslocal file .." and ":argsglobal file ..".
1966 */
1967 ex_next(eap);
1968 }
1969 else
1970#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1971 if (eap->cmdidx == CMD_args)
1972#endif
1973 {
1974 /*
1975 * ":args": list arguments.
1976 */
1977 if (ARGCOUNT > 0)
1978 {
1979 /* Overwrite the command, for a short list there is no scrolling
1980 * required and no wait_return(). */
1981 gotocmdline(TRUE);
1982 for (i = 0; i < ARGCOUNT; ++i)
1983 {
1984 if (i == curwin->w_arg_idx)
1985 msg_putchar('[');
1986 msg_outtrans(alist_name(&ARGLIST[i]));
1987 if (i == curwin->w_arg_idx)
1988 msg_putchar(']');
1989 msg_putchar(' ');
1990 }
1991 }
1992 }
1993#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1994 else if (eap->cmdidx == CMD_arglocal)
1995 {
1996 garray_T *gap = &curwin->w_alist->al_ga;
1997
1998 /*
1999 * ":argslocal": make a local copy of the global argument list.
2000 */
2001 if (ga_grow(gap, GARGCOUNT) == OK)
2002 for (i = 0; i < GARGCOUNT; ++i)
2003 if (GARGLIST[i].ae_fname != NULL)
2004 {
2005 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2006 vim_strsave(GARGLIST[i].ae_fname);
2007 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2008 GARGLIST[i].ae_fnum;
2009 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002010 }
2011 }
2012#endif
2013}
2014
2015/*
2016 * ":previous", ":sprevious", ":Next" and ":sNext".
2017 */
2018 void
2019ex_previous(eap)
2020 exarg_T *eap;
2021{
2022 /* If past the last one already, go to the last one. */
2023 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2024 do_argfile(eap, ARGCOUNT - 1);
2025 else
2026 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2027}
2028
2029/*
2030 * ":rewind", ":first", ":sfirst" and ":srewind".
2031 */
2032 void
2033ex_rewind(eap)
2034 exarg_T *eap;
2035{
2036 do_argfile(eap, 0);
2037}
2038
2039/*
2040 * ":last" and ":slast".
2041 */
2042 void
2043ex_last(eap)
2044 exarg_T *eap;
2045{
2046 do_argfile(eap, ARGCOUNT - 1);
2047}
2048
2049/*
2050 * ":argument" and ":sargument".
2051 */
2052 void
2053ex_argument(eap)
2054 exarg_T *eap;
2055{
2056 int i;
2057
2058 if (eap->addr_count > 0)
2059 i = eap->line2 - 1;
2060 else
2061 i = curwin->w_arg_idx;
2062 do_argfile(eap, i);
2063}
2064
2065/*
2066 * Edit file "argn" of the argument lists.
2067 */
2068 void
2069do_argfile(eap, argn)
2070 exarg_T *eap;
2071 int argn;
2072{
2073 int other;
2074 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002075 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002076
2077 if (argn < 0 || argn >= ARGCOUNT)
2078 {
2079 if (ARGCOUNT <= 1)
2080 EMSG(_("E163: There is only one file to edit"));
2081 else if (argn < 0)
2082 EMSG(_("E164: Cannot go before first file"));
2083 else
2084 EMSG(_("E165: Cannot go beyond last file"));
2085 }
2086 else
2087 {
2088 setpcmark();
2089#ifdef FEAT_GUI
2090 need_mouse_correct = TRUE;
2091#endif
2092
2093#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002094 /* split window or create new tab page first */
2095 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096 {
2097 if (win_split(0, 0) == FAIL)
2098 return;
2099# ifdef FEAT_SCROLLBIND
2100 curwin->w_p_scb = FALSE;
2101# endif
2102 }
2103 else
2104#endif
2105 {
2106 /*
2107 * if 'hidden' set, only check for changed file when re-editing
2108 * the same buffer
2109 */
2110 other = TRUE;
2111 if (P_HID(curbuf))
2112 {
2113 p = fix_fname(alist_name(&ARGLIST[argn]));
2114 other = otherfile(p);
2115 vim_free(p);
2116 }
2117 if ((!P_HID(curbuf) || !other)
2118 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2119 return;
2120 }
2121
2122 curwin->w_arg_idx = argn;
2123 if (argn == ARGCOUNT - 1
2124#ifdef FEAT_WINDOWS
2125 && curwin->w_alist == &global_alist
2126#endif
2127 )
2128 arg_had_last = TRUE;
2129
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002130 /* Edit the file; always use the last known line number.
2131 * When it fails (e.g. Abort for already edited file) restore the
2132 * argument index. */
2133 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002134 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002135 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2136 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002137 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002138 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002139 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002140 setmark('\'');
2141 }
2142}
2143
2144/*
2145 * ":next", and commands that behave like it.
2146 */
2147 void
2148ex_next(eap)
2149 exarg_T *eap;
2150{
2151 int i;
2152
2153 /*
2154 * check for changed buffer now, if this fails the argument list is not
2155 * redefined.
2156 */
2157 if ( P_HID(curbuf)
2158 || eap->cmdidx == CMD_snext
2159 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2160 {
2161 if (*eap->arg != NUL) /* redefine file list */
2162 {
2163 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2164 return;
2165 i = 0;
2166 }
2167 else
2168 i = curwin->w_arg_idx + (int)eap->line2;
2169 do_argfile(eap, i);
2170 }
2171}
2172
2173#ifdef FEAT_LISTCMDS
2174/*
2175 * ":argedit"
2176 */
2177 void
2178ex_argedit(eap)
2179 exarg_T *eap;
2180{
2181 int fnum;
2182 int i;
2183 char_u *s;
2184
2185 /* Add the argument to the buffer list and get the buffer number. */
2186 fnum = buflist_add(eap->arg, BLN_LISTED);
2187
2188 /* Check if this argument is already in the argument list. */
2189 for (i = 0; i < ARGCOUNT; ++i)
2190 if (ARGLIST[i].ae_fnum == fnum)
2191 break;
2192 if (i == ARGCOUNT)
2193 {
2194 /* Can't find it, add it to the argument list. */
2195 s = vim_strsave(eap->arg);
2196 if (s == NULL)
2197 return;
2198 i = alist_add_list(1, &s,
2199 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2200 if (i < 0)
2201 return;
2202 curwin->w_arg_idx = i;
2203 }
2204
2205 alist_check_arg_idx();
2206
2207 /* Edit the argument. */
2208 do_argfile(eap, i);
2209}
2210
2211/*
2212 * ":argadd"
2213 */
2214 void
2215ex_argadd(eap)
2216 exarg_T *eap;
2217{
2218 do_arglist(eap->arg, AL_ADD,
2219 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2220#ifdef FEAT_TITLE
2221 maketitle();
2222#endif
2223}
2224
2225/*
2226 * ":argdelete"
2227 */
2228 void
2229ex_argdelete(eap)
2230 exarg_T *eap;
2231{
2232 int i;
2233 int n;
2234
2235 if (eap->addr_count > 0)
2236 {
2237 /* ":1,4argdel": Delete all arguments in the range. */
2238 if (eap->line2 > ARGCOUNT)
2239 eap->line2 = ARGCOUNT;
2240 n = eap->line2 - eap->line1 + 1;
2241 if (*eap->arg != NUL || n <= 0)
2242 EMSG(_(e_invarg));
2243 else
2244 {
2245 for (i = eap->line1; i <= eap->line2; ++i)
2246 vim_free(ARGLIST[i - 1].ae_fname);
2247 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2248 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2249 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002250 if (curwin->w_arg_idx >= eap->line2)
2251 curwin->w_arg_idx -= n;
2252 else if (curwin->w_arg_idx > eap->line1)
2253 curwin->w_arg_idx = eap->line1;
2254 }
2255 }
2256 else if (*eap->arg == NUL)
2257 EMSG(_(e_argreq));
2258 else
2259 do_arglist(eap->arg, AL_DEL, 0);
2260#ifdef FEAT_TITLE
2261 maketitle();
2262#endif
2263}
2264
2265/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002266 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 */
2268 void
2269ex_listdo(eap)
2270 exarg_T *eap;
2271{
2272 int i;
2273#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002274 win_T *wp;
2275 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276#endif
2277 buf_T *buf;
2278 int next_fnum = 0;
2279#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2280 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002281#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002282 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283
2284#ifndef FEAT_WINDOWS
2285 if (eap->cmdidx == CMD_windo)
2286 {
2287 ex_ni(eap);
2288 return;
2289 }
2290#endif
2291
2292#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002293 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002294 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2295 * great speed improvement. */
2296 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297#endif
2298
2299 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002300 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301 || P_HID(curbuf)
2302 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2303 {
2304 /* start at the first argument/window/buffer */
2305 i = 0;
2306#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002307 wp = firstwin;
2308 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309#endif
2310 /* set pcmark now */
2311 if (eap->cmdidx == CMD_bufdo)
2312 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2313 else
2314 setpcmark();
2315 listcmd_busy = TRUE; /* avoids setting pcmark below */
2316
2317 while (!got_int)
2318 {
2319 if (eap->cmdidx == CMD_argdo)
2320 {
2321 /* go to argument "i" */
2322 if (i == ARGCOUNT)
2323 break;
2324 /* Don't call do_argfile() when already there, it will try
2325 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002326 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002327 {
2328 /* Clear 'shm' to avoid that the file message overwrites
2329 * any output from the command. */
2330 p_shm_save = vim_strsave(p_shm);
2331 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002333 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2334 vim_free(p_shm_save);
2335 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336 if (curwin->w_arg_idx != i)
2337 break;
2338 ++i;
2339 }
2340#ifdef FEAT_WINDOWS
2341 else if (eap->cmdidx == CMD_windo)
2342 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002343 /* go to window "wp" */
2344 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002346 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002347 if (curwin != wp)
2348 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002349 wp = curwin->w_next;
2350 }
2351 else if (eap->cmdidx == CMD_tabdo)
2352 {
2353 /* go to window "tp" */
2354 if (!valid_tabpage(tp))
2355 break;
2356 goto_tabpage_tp(tp);
2357 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 }
2359#endif
2360 else if (eap->cmdidx == CMD_bufdo)
2361 {
2362 /* Remember the number of the next listed buffer, in case
2363 * ":bwipe" is used or autocommands do something strange. */
2364 next_fnum = -1;
2365 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2366 if (buf->b_p_bl)
2367 {
2368 next_fnum = buf->b_fnum;
2369 break;
2370 }
2371 }
2372
2373 /* execute the command */
2374 do_cmdline(eap->arg, eap->getline, eap->cookie,
2375 DOCMD_VERBOSE + DOCMD_NOWAIT);
2376
2377 if (eap->cmdidx == CMD_bufdo)
2378 {
2379 /* Done? */
2380 if (next_fnum < 0)
2381 break;
2382 /* Check if the buffer still exists. */
2383 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2384 if (buf->b_fnum == next_fnum)
2385 break;
2386 if (buf == NULL)
2387 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002388
2389 /* Go to the next buffer. Clear 'shm' to avoid that the file
2390 * message overwrites any output from the command. */
2391 p_shm_save = vim_strsave(p_shm);
2392 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002394 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2395 vim_free(p_shm_save);
2396
Bram Moolenaar071d4272004-06-13 20:20:40 +00002397 /* If autocommands took us elsewhere, quit here */
2398 if (curbuf->b_fnum != next_fnum)
2399 break;
2400 }
2401
2402 if (eap->cmdidx == CMD_windo)
2403 {
2404 validate_cursor(); /* cursor may have moved */
2405#ifdef FEAT_SCROLLBIND
2406 /* required when 'scrollbind' has been set */
2407 if (curwin->w_p_scb)
2408 do_check_scrollbind(TRUE);
2409#endif
2410 }
2411 }
2412 listcmd_busy = FALSE;
2413 }
2414
2415#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002416 if (save_ei != NULL)
2417 {
2418 au_event_restore(save_ei);
2419 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2420 curbuf->b_fname, TRUE, curbuf);
2421 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002422#endif
2423}
2424
2425/*
2426 * Add files[count] to the arglist of the current window after arg "after".
2427 * The file names in files[count] must have been allocated and are taken over.
2428 * Files[] itself is not taken over.
2429 * Returns index of first added argument. Returns -1 when failed (out of mem).
2430 */
2431 static int
2432alist_add_list(count, files, after)
2433 int count;
2434 char_u **files;
2435 int after; /* where to add: 0 = before first one */
2436{
2437 int i;
2438
2439 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2440 {
2441 if (after < 0)
2442 after = 0;
2443 if (after > ARGCOUNT)
2444 after = ARGCOUNT;
2445 if (after < ARGCOUNT)
2446 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2447 (ARGCOUNT - after) * sizeof(aentry_T));
2448 for (i = 0; i < count; ++i)
2449 {
2450 ARGLIST[after + i].ae_fname = files[i];
2451 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2452 }
2453 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454 if (curwin->w_arg_idx >= after)
2455 ++curwin->w_arg_idx;
2456 return after;
2457 }
2458
2459 for (i = 0; i < count; ++i)
2460 vim_free(files[i]);
2461 return -1;
2462}
2463
2464#endif /* FEAT_LISTCMDS */
2465
2466#ifdef FEAT_EVAL
2467/*
2468 * ":compiler[!] {name}"
2469 */
2470 void
2471ex_compiler(eap)
2472 exarg_T *eap;
2473{
2474 char_u *buf;
2475 char_u *old_cur_comp = NULL;
2476 char_u *p;
2477
2478 if (*eap->arg == NUL)
2479 {
2480 /* List all compiler scripts. */
2481 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2482 /* ) keep the indenter happy... */
2483 }
2484 else
2485 {
2486 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2487 if (buf != NULL)
2488 {
2489 if (eap->forceit)
2490 {
2491 /* ":compiler! {name}" sets global options */
2492 do_cmdline_cmd((char_u *)
2493 "command -nargs=* CompilerSet set <args>");
2494 }
2495 else
2496 {
2497 /* ":compiler! {name}" sets local options.
2498 * To remain backwards compatible "current_compiler" is always
2499 * used. A user's compiler plugin may set it, the distributed
2500 * plugin will then skip the settings. Afterwards set
2501 * "b:current_compiler" and restore "current_compiler". */
2502 old_cur_comp = get_var_value((char_u *)"current_compiler");
2503 if (old_cur_comp != NULL)
2504 old_cur_comp = vim_strsave(old_cur_comp);
2505 do_cmdline_cmd((char_u *)
2506 "command -nargs=* CompilerSet setlocal <args>");
2507 }
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002508 do_unlet((char_u *)"current_compiler", TRUE);
2509 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510
2511 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002512 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002513 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2514 vim_free(buf);
2515
2516 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2517
2518 /* Set "b:current_compiler" from "current_compiler". */
2519 p = get_var_value((char_u *)"current_compiler");
2520 if (p != NULL)
2521 set_internal_string_var((char_u *)"b:current_compiler", p);
2522
2523 /* Restore "current_compiler" for ":compiler {name}". */
2524 if (!eap->forceit)
2525 {
2526 if (old_cur_comp != NULL)
2527 {
2528 set_internal_string_var((char_u *)"current_compiler",
2529 old_cur_comp);
2530 vim_free(old_cur_comp);
2531 }
2532 else
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002533 do_unlet((char_u *)"current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002534 }
2535 }
2536 }
2537}
2538#endif
2539
2540/*
2541 * ":runtime {name}"
2542 */
2543 void
2544ex_runtime(eap)
2545 exarg_T *eap;
2546{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002547 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548}
2549
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002550static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002551
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002552/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00002553 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002554source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555 char_u *fname;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002556 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002558 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559}
2560
2561/*
2562 * Source the file "name" from all directories in 'runtimepath'.
2563 * "name" can contain wildcards.
2564 * When "all" is TRUE, source all files, otherwise only the first one.
2565 * return FAIL when no file could be sourced, OK otherwise.
2566 */
2567 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002568source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002569 char_u *name;
2570 int all;
2571{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002572 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573}
2574
2575/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002576 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2577 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2579 * used.
2580 * Returns OK when at least one match found, FAIL otherwise.
2581 */
2582 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002583do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 char_u *name;
2585 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002586 void (*callback)__ARGS((char_u *fname, void *ck));
2587 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588{
2589 char_u *rtp;
2590 char_u *np;
2591 char_u *buf;
2592 char_u *rtp_copy;
2593 char_u *tail;
2594 int num_files;
2595 char_u **files;
2596 int i;
2597 int did_one = FALSE;
2598#ifdef AMIGA
2599 struct Process *proc = (struct Process *)FindTask(0L);
2600 APTR save_winptr = proc->pr_WindowPtr;
2601
2602 /* Avoid a requester here for a volume that doesn't exist. */
2603 proc->pr_WindowPtr = (APTR)-1L;
2604#endif
2605
2606 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2607 * value. */
2608 rtp_copy = vim_strsave(p_rtp);
2609 buf = alloc(MAXPATHL);
2610 if (buf != NULL && rtp_copy != NULL)
2611 {
2612 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002613 {
2614 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002615 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002617 verbose_leave();
2618 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002619
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620 /* Loop over all entries in 'runtimepath'. */
2621 rtp = rtp_copy;
2622 while (*rtp != NUL && (all || !did_one))
2623 {
2624 /* Copy the path from 'runtimepath' to buf[]. */
2625 copy_option_part(&rtp, buf, MAXPATHL, ",");
2626 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2627 {
2628 add_pathsep(buf);
2629 tail = buf + STRLEN(buf);
2630
2631 /* Loop over all patterns in "name" */
2632 np = name;
2633 while (*np != NUL && (all || !did_one))
2634 {
2635 /* Append the pattern from "name" to buf[]. */
2636 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2637 "\t ");
2638
2639 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002640 {
2641 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002642 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002643 verbose_leave();
2644 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645
2646 /* Expand wildcards, invoke the callback for each match. */
2647 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2648 EW_FILE) == OK)
2649 {
2650 for (i = 0; i < num_files; ++i)
2651 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002652 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653 did_one = TRUE;
2654 if (!all)
2655 break;
2656 }
2657 FreeWild(num_files, files);
2658 }
2659 }
2660 }
2661 }
2662 }
2663 vim_free(buf);
2664 vim_free(rtp_copy);
2665 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002666 {
2667 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002668 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002669 verbose_leave();
2670 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002671
2672#ifdef AMIGA
2673 proc->pr_WindowPtr = save_winptr;
2674#endif
2675
2676 return did_one ? OK : FAIL;
2677}
2678
2679#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2680/*
2681 * ":options"
2682 */
2683/*ARGSUSED*/
2684 void
2685ex_options(eap)
2686 exarg_T *eap;
2687{
2688 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2689}
2690#endif
2691
2692/*
2693 * ":source {fname}"
2694 */
2695 void
2696ex_source(eap)
2697 exarg_T *eap;
2698{
2699#ifdef FEAT_BROWSE
2700 if (cmdmod.browse)
2701 {
2702 char_u *fname = NULL;
2703
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002704 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002705 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2706 if (fname != NULL)
2707 {
2708 cmd_source(fname, eap);
2709 vim_free(fname);
2710 }
2711 }
2712 else
2713#endif
2714 cmd_source(eap->arg, eap);
2715}
2716
2717 static void
2718cmd_source(fname, eap)
2719 char_u *fname;
2720 exarg_T *eap;
2721{
2722 if (*fname == NUL)
2723 EMSG(_(e_argreq));
2724
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002726 /* ":source!": read Normal mdoe commands
2727 * Need to execute the commands directly. This is required at least
2728 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729 * - ":g" command busy
2730 * - after ":argdo", ":windo" or ":bufdo"
2731 * - another command follows
2732 * - inside a loop
2733 */
2734 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2735#ifdef FEAT_EVAL
2736 || eap->cstack->cs_idx >= 0
2737#endif
2738 );
2739
2740 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002741 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002742 EMSG2(_(e_notopen), fname);
2743}
2744
2745/*
2746 * ":source" and associated commands.
2747 */
2748/*
2749 * Structure used to store info for each sourced file.
2750 * It is shared between do_source() and getsourceline().
2751 * This is required, because it needs to be handed to do_cmdline() and
2752 * sourcing can be done recursively.
2753 */
2754struct source_cookie
2755{
2756 FILE *fp; /* opened file for sourcing */
2757 char_u *nextline; /* if not NULL: line that was read ahead */
2758 int finished; /* ":finish" used */
2759#if defined (USE_CRNL) || defined (USE_CR)
2760 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2761 int error; /* TRUE if LF found after CR-LF */
2762#endif
2763#ifdef FEAT_EVAL
2764 linenr_T breakpoint; /* next line with breakpoint or zero */
2765 char_u *fname; /* name of sourced file */
2766 int dbg_tick; /* debug_tick when breakpoint was set */
2767 int level; /* top nesting level of sourced file */
2768#endif
2769#ifdef FEAT_MBYTE
2770 vimconv_T conv; /* type of conversion */
2771#endif
2772};
2773
2774#ifdef FEAT_EVAL
2775/*
2776 * Return the address holding the next breakpoint line for a source cookie.
2777 */
2778 linenr_T *
2779source_breakpoint(cookie)
2780 void *cookie;
2781{
2782 return &((struct source_cookie *)cookie)->breakpoint;
2783}
2784
2785/*
2786 * Return the address holding the debug tick for a source cookie.
2787 */
2788 int *
2789source_dbg_tick(cookie)
2790 void *cookie;
2791{
2792 return &((struct source_cookie *)cookie)->dbg_tick;
2793}
2794
2795/*
2796 * Return the nesting level for a source cookie.
2797 */
2798 int
2799source_level(cookie)
2800 void *cookie;
2801{
2802 return ((struct source_cookie *)cookie)->level;
2803}
2804#endif
2805
2806static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2807
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808#if defined(WIN32) && defined(FEAT_CSCOPE)
2809static FILE *fopen_noinh_readbin __ARGS((char *filename));
2810
2811/*
2812 * Special function to open a file without handle inheritance.
2813 */
2814 static FILE *
2815fopen_noinh_readbin(filename)
2816 char *filename;
2817{
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00002818 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819
2820 if (fd_tmp == -1)
2821 return NULL;
2822 return fdopen(fd_tmp, READBIN);
2823}
2824#endif
2825
2826
2827/*
2828 * do_source: Read the file "fname" and execute its lines as EX commands.
2829 *
2830 * This function may be called recursively!
2831 *
2832 * return FAIL if file could not be opened, OK otherwise
2833 */
2834 int
2835do_source(fname, check_other, is_vimrc)
2836 char_u *fname;
2837 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002838 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002839{
2840 struct source_cookie cookie;
2841 char_u *save_sourcing_name;
2842 linenr_T save_sourcing_lnum;
2843 char_u *p;
2844 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002845 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002846 int retval = FAIL;
2847#ifdef FEAT_EVAL
2848 scid_T save_current_SID;
2849 static scid_T last_current_SID = 0;
2850 void *save_funccalp;
2851 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002852 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002853# ifdef UNIX
2854 struct stat st;
2855 int stat_ok;
2856# endif
2857#endif
2858#ifdef STARTUPTIME
2859 struct timeval tv_rel;
2860 struct timeval tv_start;
2861#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002862#ifdef FEAT_PROFILE
2863 proftime_T wait_start;
2864#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002865
2866#ifdef RISCOS
2867 p = mch_munge_fname(fname);
2868#else
2869 p = expand_env_save(fname);
2870#endif
2871 if (p == NULL)
2872 return retval;
2873 fname_exp = fix_fname(p);
2874 vim_free(p);
2875 if (fname_exp == NULL)
2876 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002877 if (mch_isdir(fname_exp))
2878 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002879 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002880 goto theend;
2881 }
2882
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002883#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002884 /* Apply SourceCmd autocommands, they should get the file and source it. */
2885 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2886 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2887 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002888 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002889# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002890 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002891# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002892 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002893# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002894 goto theend;
2895 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002896
2897 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002898 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2899#endif
2900
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901#if defined(WIN32) && defined(FEAT_CSCOPE)
2902 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2903#else
2904 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2905#endif
2906 if (cookie.fp == NULL && check_other)
2907 {
2908 /*
2909 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2910 * and ".exrc" by "_exrc" or vice versa.
2911 */
2912 p = gettail(fname_exp);
2913 if ((*p == '.' || *p == '_')
2914 && (STRICMP(p + 1, "vimrc") == 0
2915 || STRICMP(p + 1, "gvimrc") == 0
2916 || STRICMP(p + 1, "exrc") == 0))
2917 {
2918 if (*p == '_')
2919 *p = '.';
2920 else
2921 *p = '_';
2922#if defined(WIN32) && defined(FEAT_CSCOPE)
2923 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2924#else
2925 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2926#endif
2927 }
2928 }
2929
2930 if (cookie.fp == NULL)
2931 {
2932 if (p_verbose > 0)
2933 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002934 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002936 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 else
2938 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002939 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002940 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941 }
2942 goto theend;
2943 }
2944
2945 /*
2946 * The file exists.
2947 * - In verbose mode, give a message.
2948 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2949 */
2950 if (p_verbose > 1)
2951 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002952 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002954 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955 else
2956 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002957 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002958 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002960 if (is_vimrc == DOSO_VIMRC)
2961 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
2962 else if (is_vimrc == DOSO_GVIMRC)
2963 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002964
2965#ifdef USE_CRNL
2966 /* If no automatic file format: Set default to CR-NL. */
2967 if (*p_ffs == NUL)
2968 cookie.fileformat = EOL_DOS;
2969 else
2970 cookie.fileformat = EOL_UNKNOWN;
2971 cookie.error = FALSE;
2972#endif
2973
2974#ifdef USE_CR
2975 /* If no automatic file format: Set default to CR. */
2976 if (*p_ffs == NUL)
2977 cookie.fileformat = EOL_MAC;
2978 else
2979 cookie.fileformat = EOL_UNKNOWN;
2980 cookie.error = FALSE;
2981#endif
2982
2983 cookie.nextline = NULL;
2984 cookie.finished = FALSE;
2985
2986#ifdef FEAT_EVAL
2987 /*
2988 * Check if this script has a breakpoint.
2989 */
2990 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2991 cookie.fname = fname_exp;
2992 cookie.dbg_tick = debug_tick;
2993
2994 cookie.level = ex_nesting_level;
2995#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002996
2997 /*
2998 * Keep the sourcing name/lnum, for recursive calls.
2999 */
3000 save_sourcing_name = sourcing_name;
3001 sourcing_name = fname_exp;
3002 save_sourcing_lnum = sourcing_lnum;
3003 sourcing_lnum = 0;
3004
Bram Moolenaar73881402009-02-04 16:50:47 +00003005#ifdef FEAT_MBYTE
3006 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3007
3008 /* Read the first line so we can check for a UTF-8 BOM. */
3009 firstline = getsourceline(0, (void *)&cookie, 0);
3010 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3011 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3012 {
3013 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3014 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3015 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003016 if (p == NULL)
3017 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003018 if (p != NULL)
3019 {
3020 vim_free(firstline);
3021 firstline = p;
3022 }
3023 }
3024#endif
3025
Bram Moolenaar071d4272004-06-13 20:20:40 +00003026#ifdef STARTUPTIME
3027 time_push(&tv_rel, &tv_start);
3028#endif
3029
3030#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003031# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003032 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003033 prof_child_enter(&wait_start); /* entering a child now */
3034# endif
3035
3036 /* Don't use local function variables, if called from a function.
3037 * Also starts profiling timer for nested script. */
3038 save_funccalp = save_funccal();
3039
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040 /*
3041 * Check if this script was sourced before to finds its SID.
3042 * If it's new, generate a new SID.
3043 */
3044 save_current_SID = current_SID;
3045# ifdef UNIX
3046 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3047# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003048 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3049 {
3050 si = &SCRIPT_ITEM(current_SID);
3051 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052 && (
3053# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003054 /* Compare dev/ino when possible, it catches symbolic
3055 * links. Also compare file names, the inode may change
3056 * when the file was edited. */
Bram Moolenaar05159a02005-02-26 23:04:13 +00003057 ((stat_ok && si->sn_dev != -1)
3058 && (si->sn_dev == st.st_dev
3059 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003061 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064 if (current_SID == 0)
3065 {
3066 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003067 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3068 == FAIL)
3069 goto almosttheend;
3070 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003072 ++script_items.ga_len;
3073 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3074# ifdef FEAT_PROFILE
3075 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003078 si = &SCRIPT_ITEM(current_SID);
3079 si->sn_name = fname_exp;
3080 fname_exp = NULL;
3081# ifdef UNIX
3082 if (stat_ok)
3083 {
3084 si->sn_dev = st.st_dev;
3085 si->sn_ino = st.st_ino;
3086 }
3087 else
3088 si->sn_dev = -1;
3089# endif
3090
Bram Moolenaar071d4272004-06-13 20:20:40 +00003091 /* Allocate the local script variables to use for this script. */
3092 new_script_vars(current_SID);
3093 }
3094
Bram Moolenaar05159a02005-02-26 23:04:13 +00003095# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003096 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003097 {
3098 int forceit;
3099
3100 /* Check if we do profiling for this script. */
3101 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3102 {
3103 script_do_profile(si);
3104 si->sn_pr_force = forceit;
3105 }
3106 if (si->sn_prof_on)
3107 {
3108 ++si->sn_pr_count;
3109 profile_start(&si->sn_pr_start);
3110 profile_zero(&si->sn_pr_children);
3111 }
3112 }
3113# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114#endif
3115
3116 /*
3117 * Call do_cmdline, which will call getsourceline() to get the lines.
3118 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003119 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003120 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003121 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003122
3123#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003124 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003125 {
3126 /* Get "si" again, "script_items" may have been reallocated. */
3127 si = &SCRIPT_ITEM(current_SID);
3128 if (si->sn_prof_on)
3129 {
3130 profile_end(&si->sn_pr_start);
3131 profile_sub_wait(&wait_start, &si->sn_pr_start);
3132 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003133 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3134 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003135 }
3136 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003137#endif
3138
3139 if (got_int)
3140 EMSG(_(e_interr));
3141 sourcing_name = save_sourcing_name;
3142 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143 if (p_verbose > 1)
3144 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003145 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003146 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003147 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003148 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003149 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150 }
3151#ifdef STARTUPTIME
Bram Moolenaare511f292008-09-07 13:50:37 +00003152 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3153 time_msg((char *)IObuff, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003154 time_pop(&tv_rel);
3155#endif
3156
3157#ifdef FEAT_EVAL
3158 /*
3159 * After a "finish" in debug mode, need to break at first command of next
3160 * sourced file.
3161 */
3162 if (save_debug_break_level > ex_nesting_level
3163 && debug_break_level == ex_nesting_level)
3164 ++debug_break_level;
3165#endif
3166
Bram Moolenaar05159a02005-02-26 23:04:13 +00003167#ifdef FEAT_EVAL
3168almosttheend:
3169 current_SID = save_current_SID;
3170 restore_funccal(save_funccalp);
3171# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003172 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003173 prof_child_exit(&wait_start); /* leaving a child now */
3174# endif
3175#endif
3176 fclose(cookie.fp);
3177 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003178 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003179#ifdef FEAT_MBYTE
3180 convert_setup(&cookie.conv, NULL, NULL);
3181#endif
3182
Bram Moolenaar071d4272004-06-13 20:20:40 +00003183theend:
3184 vim_free(fname_exp);
3185 return retval;
3186}
3187
3188#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003189
Bram Moolenaar071d4272004-06-13 20:20:40 +00003190/*
3191 * ":scriptnames"
3192 */
3193/*ARGSUSED*/
3194 void
3195ex_scriptnames(eap)
3196 exarg_T *eap;
3197{
3198 int i;
3199
Bram Moolenaar05159a02005-02-26 23:04:13 +00003200 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3201 if (SCRIPT_ITEM(i).sn_name != NULL)
3202 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003203}
3204
3205# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3206/*
3207 * Fix slashes in the list of script names for 'shellslash'.
3208 */
3209 void
3210scriptnames_slash_adjust()
3211{
3212 int i;
3213
Bram Moolenaar05159a02005-02-26 23:04:13 +00003214 for (i = 1; i <= script_items.ga_len; ++i)
3215 if (SCRIPT_ITEM(i).sn_name != NULL)
3216 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003217}
3218# endif
3219
3220/*
3221 * Get a pointer to a script name. Used for ":verbose set".
3222 */
3223 char_u *
3224get_scriptname(id)
3225 scid_T id;
3226{
3227 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003228 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003229 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003230 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003232 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003233 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003234 return (char_u *)_("environment variable");
3235 if (id == SID_ERROR)
3236 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003237 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003238}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003239
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003240# if defined(EXITFREE) || defined(PROTO)
3241 void
3242free_scriptnames()
3243{
3244 int i;
3245
3246 for (i = script_items.ga_len; i > 0; --i)
3247 vim_free(SCRIPT_ITEM(i).sn_name);
3248 ga_clear(&script_items);
3249}
3250# endif
3251
Bram Moolenaar071d4272004-06-13 20:20:40 +00003252#endif
3253
3254#if defined(USE_CR) || defined(PROTO)
3255
3256# if defined(__MSL__) && (__MSL__ >= 22)
3257/*
3258 * Newer version of the Metrowerks library handle DOS and UNIX files
3259 * without help.
3260 * Test with earlier versions, MSL 2.2 is the library supplied with
3261 * Codewarrior Pro 2.
3262 */
3263 char *
3264fgets_cr(s, n, stream)
3265 char *s;
3266 int n;
3267 FILE *stream;
3268{
3269 return fgets(s, n, stream);
3270}
3271# else
3272/*
3273 * Version of fgets() which also works for lines ending in a <CR> only
3274 * (Macintosh format).
3275 * For older versions of the Metrowerks library.
3276 * At least CodeWarrior 9 needed this code.
3277 */
3278 char *
3279fgets_cr(s, n, stream)
3280 char *s;
3281 int n;
3282 FILE *stream;
3283{
3284 int c = 0;
3285 int char_read = 0;
3286
3287 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3288 {
3289 c = fgetc(stream);
3290 s[char_read++] = c;
3291 /* If the file is in DOS format, we need to skip a NL after a CR. I
3292 * thought it was the other way around, but this appears to work... */
3293 if (c == '\n')
3294 {
3295 c = fgetc(stream);
3296 if (c != '\r')
3297 ungetc(c, stream);
3298 }
3299 }
3300
3301 s[char_read] = 0;
3302 if (char_read == 0)
3303 return NULL;
3304
3305 if (feof(stream) && char_read == 1)
3306 return NULL;
3307
3308 return s;
3309}
3310# endif
3311#endif
3312
3313/*
3314 * Get one full line from a sourced file.
3315 * Called by do_cmdline() when it's called from do_source().
3316 *
3317 * Return a pointer to the line in allocated memory.
3318 * Return NULL for end-of-file or some error.
3319 */
3320/* ARGSUSED */
3321 char_u *
3322getsourceline(c, cookie, indent)
3323 int c; /* not used */
3324 void *cookie;
3325 int indent; /* not used */
3326{
3327 struct source_cookie *sp = (struct source_cookie *)cookie;
3328 char_u *line;
3329 char_u *p, *s;
3330
3331#ifdef FEAT_EVAL
3332 /* If breakpoints have been added/deleted need to check for it. */
3333 if (sp->dbg_tick < debug_tick)
3334 {
3335 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3336 sp->dbg_tick = debug_tick;
3337 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003338# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003339 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003340 script_line_end();
3341# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342#endif
3343 /*
3344 * Get current line. If there is a read-ahead line, use it, otherwise get
3345 * one now.
3346 */
3347 if (sp->finished)
3348 line = NULL;
3349 else if (sp->nextline == NULL)
3350 line = get_one_sourceline(sp);
3351 else
3352 {
3353 line = sp->nextline;
3354 sp->nextline = NULL;
3355 ++sourcing_lnum;
3356 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003357#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003358 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003359 script_line_start();
3360#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003361
3362 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3363 * contain the 'C' flag. */
3364 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3365 {
3366 /* compensate for the one line read-ahead */
3367 --sourcing_lnum;
3368 for (;;)
3369 {
3370 sp->nextline = get_one_sourceline(sp);
3371 if (sp->nextline == NULL)
3372 break;
3373 p = skipwhite(sp->nextline);
3374 if (*p != '\\')
3375 break;
3376 s = alloc((int)(STRLEN(line) + STRLEN(p)));
3377 if (s == NULL) /* out of memory */
3378 break;
3379 STRCPY(s, line);
3380 STRCAT(s, p + 1);
3381 vim_free(line);
3382 line = s;
3383 vim_free(sp->nextline);
3384 }
3385 }
3386
3387#ifdef FEAT_MBYTE
3388 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3389 {
3390 /* Convert the encoding of the script line. */
3391 s = string_convert(&sp->conv, line, NULL);
3392 if (s != NULL)
3393 {
3394 vim_free(line);
3395 line = s;
3396 }
3397 }
3398#endif
3399
3400#ifdef FEAT_EVAL
3401 /* Did we encounter a breakpoint? */
3402 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3403 {
3404 dbg_breakpoint(sp->fname, sourcing_lnum);
3405 /* Find next breakpoint. */
3406 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3407 sp->dbg_tick = debug_tick;
3408 }
3409#endif
3410
3411 return line;
3412}
3413
3414 static char_u *
3415get_one_sourceline(sp)
3416 struct source_cookie *sp;
3417{
3418 garray_T ga;
3419 int len;
3420 int c;
3421 char_u *buf;
3422#ifdef USE_CRNL
3423 int has_cr; /* CR-LF found */
3424#endif
3425#ifdef USE_CR
3426 char_u *scan;
3427#endif
3428 int have_read = FALSE;
3429
3430 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003431 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003432
3433 /*
3434 * Loop until there is a finished line (or end-of-file).
3435 */
3436 sourcing_lnum++;
3437 for (;;)
3438 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003439 /* make room to read at least 120 (more) characters */
3440 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441 break;
3442 buf = (char_u *)ga.ga_data;
3443
3444#ifdef USE_CR
3445 if (sp->fileformat == EOL_MAC)
3446 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003447 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3448 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449 break;
3450 }
3451 else
3452#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003453 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3454 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003455 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003456 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003457#ifdef USE_CRNL
3458 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3459 * CTRL-Z by its own, or after a NL. */
3460 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3461 && sp->fileformat == EOL_DOS
3462 && buf[len - 1] == Ctrl_Z)
3463 {
3464 buf[len - 1] = NUL;
3465 break;
3466 }
3467#endif
3468
3469#ifdef USE_CR
3470 /* If the read doesn't stop on a new line, and there's
3471 * some CR then we assume a Mac format */
3472 if (sp->fileformat == EOL_UNKNOWN)
3473 {
3474 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3475 sp->fileformat = EOL_MAC;
3476 else
3477 sp->fileformat = EOL_UNIX;
3478 }
3479
3480 if (sp->fileformat == EOL_MAC)
3481 {
3482 scan = vim_strchr(buf, '\r');
3483
3484 if (scan != NULL)
3485 {
3486 *scan = '\n';
3487 if (*(scan + 1) != 0)
3488 {
3489 *(scan + 1) = 0;
3490 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3491 }
3492 }
3493 len = STRLEN(buf);
3494 }
3495#endif
3496
3497 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498 ga.ga_len = len;
3499
3500 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003501 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003502 continue;
3503
3504 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3505 {
3506#ifdef USE_CRNL
3507 has_cr = (len >= 2 && buf[len - 2] == '\r');
3508 if (sp->fileformat == EOL_UNKNOWN)
3509 {
3510 if (has_cr)
3511 sp->fileformat = EOL_DOS;
3512 else
3513 sp->fileformat = EOL_UNIX;
3514 }
3515
3516 if (sp->fileformat == EOL_DOS)
3517 {
3518 if (has_cr) /* replace trailing CR */
3519 {
3520 buf[len - 2] = '\n';
3521 --len;
3522 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003523 }
3524 else /* lines like ":map xx yy^M" will have failed */
3525 {
3526 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003527 {
3528 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003530 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531 sp->error = TRUE;
3532 sp->fileformat = EOL_UNIX;
3533 }
3534 }
3535#endif
3536 /* The '\n' is escaped if there is an odd number of ^V's just
3537 * before it, first set "c" just before the 'V's and then check
3538 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3539 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3540 ;
3541 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3542 {
3543 sourcing_lnum++;
3544 continue;
3545 }
3546
3547 buf[len - 1] = NUL; /* remove the NL */
3548 }
3549
3550 /*
3551 * Check for ^C here now and then, so recursive :so can be broken.
3552 */
3553 line_breakcheck();
3554 break;
3555 }
3556
3557 if (have_read)
3558 return (char_u *)ga.ga_data;
3559
3560 vim_free(ga.ga_data);
3561 return NULL;
3562}
3563
Bram Moolenaar05159a02005-02-26 23:04:13 +00003564#if defined(FEAT_PROFILE) || defined(PROTO)
3565/*
3566 * Called when starting to read a script line.
3567 * "sourcing_lnum" must be correct!
3568 * When skipping lines it may not actually be executed, but we won't find out
3569 * until later and we need to store the time now.
3570 */
3571 void
3572script_line_start()
3573{
3574 scriptitem_T *si;
3575 sn_prl_T *pp;
3576
3577 if (current_SID <= 0 || current_SID > script_items.ga_len)
3578 return;
3579 si = &SCRIPT_ITEM(current_SID);
3580 if (si->sn_prof_on && sourcing_lnum >= 1)
3581 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003582 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003583 * here isn't counted. */
3584 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3585 si->sn_prl_idx = sourcing_lnum - 1;
3586 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3587 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3588 {
3589 /* Zero counters for a line that was not used before. */
3590 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3591 pp->snp_count = 0;
3592 profile_zero(&pp->sn_prl_total);
3593 profile_zero(&pp->sn_prl_self);
3594 ++si->sn_prl_ga.ga_len;
3595 }
3596 si->sn_prl_execed = FALSE;
3597 profile_start(&si->sn_prl_start);
3598 profile_zero(&si->sn_prl_children);
3599 profile_get_wait(&si->sn_prl_wait);
3600 }
3601}
3602
3603/*
3604 * Called when actually executing a function line.
3605 */
3606 void
3607script_line_exec()
3608{
3609 scriptitem_T *si;
3610
3611 if (current_SID <= 0 || current_SID > script_items.ga_len)
3612 return;
3613 si = &SCRIPT_ITEM(current_SID);
3614 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3615 si->sn_prl_execed = TRUE;
3616}
3617
3618/*
3619 * Called when done with a function line.
3620 */
3621 void
3622script_line_end()
3623{
3624 scriptitem_T *si;
3625 sn_prl_T *pp;
3626
3627 if (current_SID <= 0 || current_SID > script_items.ga_len)
3628 return;
3629 si = &SCRIPT_ITEM(current_SID);
3630 if (si->sn_prof_on && si->sn_prl_idx >= 0
3631 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3632 {
3633 if (si->sn_prl_execed)
3634 {
3635 pp = &PRL_ITEM(si, si->sn_prl_idx);
3636 ++pp->snp_count;
3637 profile_end(&si->sn_prl_start);
3638 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003639 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003640 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3641 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003642 }
3643 si->sn_prl_idx = -1;
3644 }
3645}
3646#endif
3647
Bram Moolenaar071d4272004-06-13 20:20:40 +00003648/*
3649 * ":scriptencoding": Set encoding conversion for a sourced script.
3650 * Without the multi-byte feature it's simply ignored.
3651 */
3652/*ARGSUSED*/
3653 void
3654ex_scriptencoding(eap)
3655 exarg_T *eap;
3656{
3657#ifdef FEAT_MBYTE
3658 struct source_cookie *sp;
3659 char_u *name;
3660
3661 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3662 {
3663 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3664 return;
3665 }
3666
3667 if (*eap->arg != NUL)
3668 {
3669 name = enc_canonize(eap->arg);
3670 if (name == NULL) /* out of memory */
3671 return;
3672 }
3673 else
3674 name = eap->arg;
3675
3676 /* Setup for conversion from the specified encoding to 'encoding'. */
3677 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3678 convert_setup(&sp->conv, name, p_enc);
3679
3680 if (name != eap->arg)
3681 vim_free(name);
3682#endif
3683}
3684
3685#if defined(FEAT_EVAL) || defined(PROTO)
3686/*
3687 * ":finish": Mark a sourced file as finished.
3688 */
3689 void
3690ex_finish(eap)
3691 exarg_T *eap;
3692{
3693 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3694 do_finish(eap, FALSE);
3695 else
3696 EMSG(_("E168: :finish used outside of a sourced file"));
3697}
3698
3699/*
3700 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3701 * Also called for a pending finish at the ":endtry" or after returning from
3702 * an extra do_cmdline(). "reanimate" is used in the latter case.
3703 */
3704 void
3705do_finish(eap, reanimate)
3706 exarg_T *eap;
3707 int reanimate;
3708{
3709 int idx;
3710
3711 if (reanimate)
3712 ((struct source_cookie *)getline_cookie(eap->getline,
3713 eap->cookie))->finished = FALSE;
3714
3715 /*
3716 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3717 * not in its finally clause (which then is to be executed next) is found.
3718 * In this case, make the ":finish" pending for execution at the ":endtry".
3719 * Otherwise, finish normally.
3720 */
3721 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3722 if (idx >= 0)
3723 {
3724 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3725 report_make_pending(CSTP_FINISH, NULL);
3726 }
3727 else
3728 ((struct source_cookie *)getline_cookie(eap->getline,
3729 eap->cookie))->finished = TRUE;
3730}
3731
3732
3733/*
3734 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3735 * message for missing ":endif".
3736 * Return FALSE when not sourcing a file.
3737 */
3738 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003739source_finished(fgetline, cookie)
3740 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741 void *cookie;
3742{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003743 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003744 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003745 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746}
3747#endif
3748
3749#if defined(FEAT_LISTCMDS) || defined(PROTO)
3750/*
3751 * ":checktime [buffer]"
3752 */
3753 void
3754ex_checktime(eap)
3755 exarg_T *eap;
3756{
3757 buf_T *buf;
3758 int save_no_check_timestamps = no_check_timestamps;
3759
3760 no_check_timestamps = 0;
3761 if (eap->addr_count == 0) /* default is all buffers */
3762 check_timestamps(FALSE);
3763 else
3764 {
3765 buf = buflist_findnr((int)eap->line2);
3766 if (buf != NULL) /* cannot happen? */
3767 (void)buf_check_timestamp(buf, FALSE);
3768 }
3769 no_check_timestamps = save_no_check_timestamps;
3770}
3771#endif
3772
Bram Moolenaar071d4272004-06-13 20:20:40 +00003773#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3774 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3775static char *get_locale_val __ARGS((int what));
3776
3777 static char *
3778get_locale_val(what)
3779 int what;
3780{
3781 char *loc;
3782
3783 /* Obtain the locale value from the libraries. For DJGPP this is
3784 * redefined and it doesn't use the arguments. */
3785 loc = setlocale(what, NULL);
3786
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003787# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788 if (loc != NULL)
3789 {
3790 char_u *p;
3791
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003792 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3793 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794 p = vim_strchr(loc, '=');
3795 if (p != NULL)
3796 {
3797 loc = ++p;
3798 while (*p != NUL) /* remove trailing newline */
3799 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003800 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003801 {
3802 *p = NUL;
3803 break;
3804 }
3805 ++p;
3806 }
3807 }
3808 }
3809# endif
3810
3811 return loc;
3812}
3813#endif
3814
3815
3816#ifdef WIN32
3817/*
3818 * On MS-Windows locale names are strings like "German_Germany.1252", but
3819 * gettext expects "de". Try to translate one into another here for a few
3820 * supported languages.
3821 */
3822 static char_u *
3823gettext_lang(char_u *name)
3824{
3825 int i;
3826 static char *(mtable[]) = {
3827 "afrikaans", "af",
3828 "czech", "cs",
3829 "dutch", "nl",
3830 "german", "de",
3831 "english_united kingdom", "en_GB",
3832 "spanish", "es",
3833 "french", "fr",
3834 "italian", "it",
3835 "japanese", "ja",
3836 "korean", "ko",
3837 "norwegian", "no",
3838 "polish", "pl",
3839 "russian", "ru",
3840 "slovak", "sk",
3841 "swedish", "sv",
3842 "ukrainian", "uk",
3843 "chinese_china", "zh_CN",
3844 "chinese_taiwan", "zh_TW",
3845 NULL};
3846
3847 for (i = 0; mtable[i] != NULL; i += 2)
3848 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3849 return mtable[i + 1];
3850 return name;
3851}
3852#endif
3853
3854#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3855/*
3856 * Obtain the current messages language. Used to set the default for
3857 * 'helplang'. May return NULL or an empty string.
3858 */
3859 char_u *
3860get_mess_lang()
3861{
3862 char_u *p;
3863
3864# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3865# if defined(LC_MESSAGES)
3866 p = (char_u *)get_locale_val(LC_MESSAGES);
3867# else
3868 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003869 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3870 * and LC_MONETARY may be set differently for a Japanese working in the
3871 * US. */
3872 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873# endif
3874# else
3875 p = mch_getenv((char_u *)"LC_ALL");
3876 if (p == NULL || *p == NUL)
3877 {
3878 p = mch_getenv((char_u *)"LC_MESSAGES");
3879 if (p == NULL || *p == NUL)
3880 p = mch_getenv((char_u *)"LANG");
3881 }
3882# endif
3883# ifdef WIN32
3884 p = gettext_lang(p);
3885# endif
3886 return p;
3887}
3888#endif
3889
Bram Moolenaardef9e822004-12-31 20:58:58 +00003890/* Complicated #if; matches with where get_mess_env() is used below. */
3891#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3892 && defined(LC_MESSAGES))) \
3893 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3894 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3895 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896static char_u *get_mess_env __ARGS((void));
3897
3898/*
3899 * Get the language used for messages from the environment.
3900 */
3901 static char_u *
3902get_mess_env()
3903{
3904 char_u *p;
3905
3906 p = mch_getenv((char_u *)"LC_ALL");
3907 if (p == NULL || *p == NUL)
3908 {
3909 p = mch_getenv((char_u *)"LC_MESSAGES");
3910 if (p == NULL || *p == NUL)
3911 {
3912 p = mch_getenv((char_u *)"LANG");
3913 if (p != NULL && VIM_ISDIGIT(*p))
3914 p = NULL; /* ignore something like "1043" */
3915# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3916 if (p == NULL || *p == NUL)
3917 p = (char_u *)get_locale_val(LC_CTYPE);
3918# endif
3919 }
3920 }
3921 return p;
3922}
3923#endif
3924
3925#if defined(FEAT_EVAL) || defined(PROTO)
3926
3927/*
3928 * Set the "v:lang" variable according to the current locale setting.
3929 * Also do "v:lc_time"and "v:ctype".
3930 */
3931 void
3932set_lang_var()
3933{
3934 char_u *loc;
3935
3936# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3937 loc = (char_u *)get_locale_val(LC_CTYPE);
3938# else
3939 /* setlocale() not supported: use the default value */
3940 loc = (char_u *)"C";
3941# endif
3942 set_vim_var_string(VV_CTYPE, loc, -1);
3943
3944 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3945 * back to LC_CTYPE if it's empty. */
3946# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
3947 loc = (char_u *)get_locale_val(LC_MESSAGES);
3948# else
3949 loc = get_mess_env();
3950# endif
3951 set_vim_var_string(VV_LANG, loc, -1);
3952
3953# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3954 loc = (char_u *)get_locale_val(LC_TIME);
3955# endif
3956 set_vim_var_string(VV_LC_TIME, loc, -1);
3957}
3958#endif
3959
3960#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3961 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
3962/*
3963 * ":language": Set the language (locale).
3964 */
3965 void
3966ex_language(eap)
3967 exarg_T *eap;
3968{
3969 char *loc;
3970 char_u *p;
3971 char_u *name;
3972 int what = LC_ALL;
3973 char *whatstr = "";
3974#ifdef LC_MESSAGES
3975# define VIM_LC_MESSAGES LC_MESSAGES
3976#else
3977# define VIM_LC_MESSAGES 6789
3978#endif
3979
3980 name = eap->arg;
3981
3982 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3983 * Allow abbreviation, but require at least 3 characters to avoid
3984 * confusion with a two letter language name "me" or "ct". */
3985 p = skiptowhite(eap->arg);
3986 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
3987 {
3988 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3989 {
3990 what = VIM_LC_MESSAGES;
3991 name = skipwhite(p);
3992 whatstr = "messages ";
3993 }
3994 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3995 {
3996 what = LC_CTYPE;
3997 name = skipwhite(p);
3998 whatstr = "ctype ";
3999 }
4000 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4001 {
4002 what = LC_TIME;
4003 name = skipwhite(p);
4004 whatstr = "time ";
4005 }
4006 }
4007
4008 if (*name == NUL)
4009 {
4010#ifndef LC_MESSAGES
4011 if (what == VIM_LC_MESSAGES)
4012 p = get_mess_env();
4013 else
4014#endif
4015 p = (char_u *)setlocale(what, NULL);
4016 if (p == NULL || *p == NUL)
4017 p = (char_u *)"Unknown";
4018 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4019 }
4020 else
4021 {
4022#ifndef LC_MESSAGES
4023 if (what == VIM_LC_MESSAGES)
4024 loc = "";
4025 else
4026#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004027 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004029#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4030 /* Make sure strtod() uses a decimal point, not a comma. */
4031 setlocale(LC_NUMERIC, "C");
4032#endif
4033 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004034 if (loc == NULL)
4035 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4036 else
4037 {
4038#ifdef HAVE_NL_MSG_CAT_CNTR
4039 /* Need to do this for GNU gettext, otherwise cached translations
4040 * will be used again. */
4041 extern int _nl_msg_cat_cntr;
4042
4043 ++_nl_msg_cat_cntr;
4044#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004045 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004046 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4047
4048 if (what != LC_TIME)
4049 {
4050 /* Tell gettext() what to translate to. It apparently doesn't
4051 * use the currently effective locale. Also do this when
4052 * FEAT_GETTEXT isn't defined, so that shell commands use this
4053 * value. */
4054 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004055 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004056 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004057# ifdef WIN32
4058 /* Apparently MS-Windows printf() may cause a crash when
4059 * we give it 8-bit text while it's expecting text in the
4060 * current locale. This call avoids that. */
4061 setlocale(LC_CTYPE, "C");
4062# endif
4063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004064 if (what != LC_CTYPE)
4065 {
4066 char_u *mname;
4067#ifdef WIN32
4068 mname = gettext_lang(name);
4069#else
4070 mname = name;
4071#endif
4072 vim_setenv((char_u *)"LC_MESSAGES", mname);
4073#ifdef FEAT_MULTI_LANG
4074 set_helplang_default(mname);
4075#endif
4076 }
4077
4078 /* Set $LC_CTYPE, because it overrules $LANG, and
4079 * gtk_set_locale() calls setlocale() again. gnome_init()
4080 * sets $LC_CTYPE to "en_US" (that's a bug!). */
4081 if (what != VIM_LC_MESSAGES)
4082 vim_setenv((char_u *)"LC_CTYPE", name);
4083# ifdef FEAT_GUI_GTK
4084 /* Let GTK know what locale we're using. Not sure this is
4085 * really needed... */
4086 if (gui.in_use)
4087 (void)gtk_set_locale();
4088# endif
4089 }
4090
4091# ifdef FEAT_EVAL
4092 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4093 set_lang_var();
4094# endif
4095 }
4096 }
4097}
4098
4099# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4100/*
4101 * Function given to ExpandGeneric() to obtain the possible arguments of the
4102 * ":language" command.
4103 */
4104/*ARGSUSED*/
4105 char_u *
4106get_lang_arg(xp, idx)
4107 expand_T *xp;
4108 int idx;
4109{
4110 if (idx == 0)
4111 return (char_u *)"messages";
4112 if (idx == 1)
4113 return (char_u *)"ctype";
4114 if (idx == 2)
4115 return (char_u *)"time";
4116 return NULL;
4117}
4118# endif
4119
4120#endif