blob: 92cd73358e8a16efce1f128d3314a2f8c72246d6 [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 Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
17static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
18
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
71
72/*
73 * do_debug(): Debug mode.
74 * Repeatedly get Ex commands, until told to continue normal execution.
75 */
76 void
77do_debug(cmd)
78 char_u *cmd;
79{
80 int save_msg_scroll = msg_scroll;
81 int save_State = State;
82 int save_did_emsg = did_emsg;
83 int save_cmd_silent = cmd_silent;
84 int save_msg_silent = msg_silent;
85 int save_emsg_silent = emsg_silent;
86 int save_redir_off = redir_off;
87 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000088 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000089 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000090# ifdef FEAT_EX_EXTRA
91 int save_ex_normal_busy;
92# endif
93 int n;
94 char_u *cmdline = NULL;
95 char_u *p;
96 char *tail = NULL;
97 static int last_cmd = 0;
98#define CMD_CONT 1
99#define CMD_NEXT 2
100#define CMD_STEP 3
101#define CMD_FINISH 4
102#define CMD_QUIT 5
103#define CMD_INTERRUPT 6
104
105#ifdef ALWAYS_USE_GUI
106 /* Can't do this when there is no terminal for input/output. */
107 if (!gui.in_use)
108 {
109 /* Break as soon as possible. */
110 debug_break_level = 9999;
111 return;
112 }
113#endif
114
115 /* Make sure we are in raw mode and start termcap mode. Might have side
116 * effects... */
117 settmode(TMODE_RAW);
118 starttermcap();
119
120 ++RedrawingDisabled; /* don't redisplay the window */
121 ++no_wait_return; /* don't wait for return */
122 did_emsg = FALSE; /* don't use error from debugged stuff */
123 cmd_silent = FALSE; /* display commands */
124 msg_silent = FALSE; /* display messages */
125 emsg_silent = FALSE; /* display error messages */
126 redir_off = TRUE; /* don't redirect debug commands */
127
128 State = NORMAL;
129#ifdef FEAT_SNIFF
130 want_sniff_request = 0; /* No K_SNIFF wanted */
131#endif
132
133 if (!debug_did_msg)
134 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
135 if (sourcing_name != NULL)
136 msg(sourcing_name);
137 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000138 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141
142 /*
143 * Repeat getting a command and executing it.
144 */
145 for (;;)
146 {
147 msg_scroll = TRUE;
148 need_wait_return = FALSE;
149#ifdef FEAT_SNIFF
150 ProcessSniffRequests();
151#endif
152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157# ifdef FEAT_EX_EXTRA
158 save_ex_normal_busy = ex_normal_busy;
159 ex_normal_busy = 0;
160# endif
161 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000164 typeahead_saved = TRUE;
165 save_ignore_script = ignore_script;
166 ignore_script = TRUE;
167 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000169 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000171 if (typeahead_saved)
172 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000174 ignore_script = save_ignore_script;
175 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176# ifdef FEAT_EX_EXTRA
177 ex_normal_busy = save_ex_normal_busy;
178# endif
179
180 cmdline_row = msg_row;
181 if (cmdline != NULL)
182 {
183 /* If this is a debug command, set "last_cmd".
184 * If not, reset "last_cmd".
185 * For a blank line use previous command. */
186 p = skipwhite(cmdline);
187 if (*p != NUL)
188 {
189 switch (*p)
190 {
191 case 'c': last_cmd = CMD_CONT;
192 tail = "ont";
193 break;
194 case 'n': last_cmd = CMD_NEXT;
195 tail = "ext";
196 break;
197 case 's': last_cmd = CMD_STEP;
198 tail = "tep";
199 break;
200 case 'f': last_cmd = CMD_FINISH;
201 tail = "inish";
202 break;
203 case 'q': last_cmd = CMD_QUIT;
204 tail = "uit";
205 break;
206 case 'i': last_cmd = CMD_INTERRUPT;
207 tail = "nterrupt";
208 break;
209 default: last_cmd = 0;
210 }
211 if (last_cmd != 0)
212 {
213 /* Check that the tail matches. */
214 ++p;
215 while (*p != NUL && *p == *tail)
216 {
217 ++p;
218 ++tail;
219 }
220 if (ASCII_ISALPHA(*p))
221 last_cmd = 0;
222 }
223 }
224
225 if (last_cmd != 0)
226 {
227 /* Execute debug command: decided where to break next and
228 * return. */
229 switch (last_cmd)
230 {
231 case CMD_CONT:
232 debug_break_level = -1;
233 break;
234 case CMD_NEXT:
235 debug_break_level = ex_nesting_level;
236 break;
237 case CMD_STEP:
238 debug_break_level = 9999;
239 break;
240 case CMD_FINISH:
241 debug_break_level = ex_nesting_level - 1;
242 break;
243 case CMD_QUIT:
244 got_int = TRUE;
245 debug_break_level = -1;
246 break;
247 case CMD_INTERRUPT:
248 got_int = TRUE;
249 debug_break_level = 9999;
250 /* Do not repeat ">interrupt" cmd, continue stepping. */
251 last_cmd = CMD_STEP;
252 break;
253 }
254 break;
255 }
256
257 /* don't debug this command */
258 n = debug_break_level;
259 debug_break_level = -1;
260 (void)do_cmdline(cmdline, getexline, NULL,
261 DOCMD_VERBOSE|DOCMD_EXCRESET);
262 debug_break_level = n;
263
264 vim_free(cmdline);
265 }
266 lines_left = Rows - 1;
267 }
268 vim_free(cmdline);
269
270 --RedrawingDisabled;
271 --no_wait_return;
272 redraw_all_later(NOT_VALID);
273 need_wait_return = FALSE;
274 msg_scroll = save_msg_scroll;
275 lines_left = Rows - 1;
276 State = save_State;
277 did_emsg = save_did_emsg;
278 cmd_silent = save_cmd_silent;
279 msg_silent = save_msg_silent;
280 emsg_silent = save_emsg_silent;
281 redir_off = save_redir_off;
282
283 /* Only print the message again when typing a command before coming back
284 * here. */
285 debug_did_msg = TRUE;
286}
287
288/*
289 * ":debug".
290 */
291 void
292ex_debug(eap)
293 exarg_T *eap;
294{
295 int debug_break_level_save = debug_break_level;
296
297 debug_break_level = 9999;
298 do_cmdline_cmd(eap->arg);
299 debug_break_level = debug_break_level_save;
300}
301
302static char_u *debug_breakpoint_name = NULL;
303static linenr_T debug_breakpoint_lnum;
304
305/*
306 * When debugging or a breakpoint is set on a skipped command, no debug prompt
307 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
308 * debug_skipped_name is then set to the source name in the breakpoint case. If
309 * a skipped command decides itself that a debug prompt should be displayed, it
310 * can do so by calling dbg_check_skipped().
311 */
312static int debug_skipped;
313static char_u *debug_skipped_name;
314
315/*
316 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
317 * at or below the break level. But only when the line is actually
318 * executed. Return TRUE and set breakpoint_name for skipped commands that
319 * decide to execute something themselves.
320 * Called from do_one_cmd() before executing a command.
321 */
322 void
323dbg_check_breakpoint(eap)
324 exarg_T *eap;
325{
326 char_u *p;
327
328 debug_skipped = FALSE;
329 if (debug_breakpoint_name != NULL)
330 {
331 if (!eap->skip)
332 {
333 /* replace K_SNR with "<SNR>" */
334 if (debug_breakpoint_name[0] == K_SPECIAL
335 && debug_breakpoint_name[1] == KS_EXTRA
336 && debug_breakpoint_name[2] == (int)KE_SNR)
337 p = (char_u *)"<SNR>";
338 else
339 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000340 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
341 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 debug_breakpoint_name + (*p == NUL ? 0 : 3),
343 (long)debug_breakpoint_lnum);
344 debug_breakpoint_name = NULL;
345 do_debug(eap->cmd);
346 }
347 else
348 {
349 debug_skipped = TRUE;
350 debug_skipped_name = debug_breakpoint_name;
351 debug_breakpoint_name = NULL;
352 }
353 }
354 else if (ex_nesting_level <= debug_break_level)
355 {
356 if (!eap->skip)
357 do_debug(eap->cmd);
358 else
359 {
360 debug_skipped = TRUE;
361 debug_skipped_name = NULL;
362 }
363 }
364}
365
366/*
367 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
368 * set. Return TRUE when the debug mode is entered this time.
369 */
370 int
371dbg_check_skipped(eap)
372 exarg_T *eap;
373{
374 int prev_got_int;
375
376 if (debug_skipped)
377 {
378 /*
379 * Save the value of got_int and reset it. We don't want a previous
380 * interruption cause flushing the input buffer.
381 */
382 prev_got_int = got_int;
383 got_int = FALSE;
384 debug_breakpoint_name = debug_skipped_name;
385 /* eap->skip is TRUE */
386 eap->skip = FALSE;
387 (void)dbg_check_breakpoint(eap);
388 eap->skip = TRUE;
389 got_int |= prev_got_int;
390 return TRUE;
391 }
392 return FALSE;
393}
394
395/*
396 * The list of breakpoints: dbg_breakp.
397 * This is a grow-array of structs.
398 */
399struct debuggy
400{
401 int dbg_nr; /* breakpoint number */
402 int dbg_type; /* DBG_FUNC or DBG_FILE */
403 char_u *dbg_name; /* function or file name */
404 regprog_T *dbg_prog; /* regexp program */
405 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000406 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407};
408
409static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000410#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
411#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412static int last_breakp = 0; /* nr of last defined breakpoint */
413
Bram Moolenaar05159a02005-02-26 23:04:13 +0000414#ifdef FEAT_PROFILE
415/* Profiling uses file and func names similar to breakpoints. */
416static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
417#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418#define DBG_FUNC 1
419#define DBG_FILE 2
420
Bram Moolenaar05159a02005-02-26 23:04:13 +0000421static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
422static 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 +0000423
424/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000425 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
426 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
427 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428 * Returns FAIL for failure.
429 */
430 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000431dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000433 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000434{
435 char_u *p = arg;
436 char_u *q;
437 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000438 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439
Bram Moolenaar05159a02005-02-26 23:04:13 +0000440 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000442 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443
444 /* Find "func" or "file". */
445 if (STRNCMP(p, "func", 4) == 0)
446 bp->dbg_type = DBG_FUNC;
447 else if (STRNCMP(p, "file", 4) == 0)
448 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000449 else if (
450#ifdef FEAT_PROFILE
451 gap != &prof_ga &&
452#endif
453 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000454 {
455 if (curbuf->b_ffname == NULL)
456 {
457 EMSG(_(e_noname));
458 return FAIL;
459 }
460 bp->dbg_type = DBG_FILE;
461 here = TRUE;
462 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463 else
464 {
465 EMSG2(_(e_invarg2), p);
466 return FAIL;
467 }
468 p = skipwhite(p + 4);
469
470 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000471 if (here)
472 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000473 else if (
474#ifdef FEAT_PROFILE
475 gap != &prof_ga &&
476#endif
477 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000478 {
479 bp->dbg_lnum = getdigits(&p);
480 p = skipwhite(p);
481 }
482 else
483 bp->dbg_lnum = 0;
484
485 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000486 if ((!here && *p == NUL)
487 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
489 {
490 EMSG2(_(e_invarg2), arg);
491 return FAIL;
492 }
493
494 if (bp->dbg_type == DBG_FUNC)
495 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000496 else if (here)
497 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 else
499 {
500 /* Expand the file name in the same way as do_source(). This means
501 * doing it twice, so that $DIR/file gets expanded when $DIR is
502 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 if (q == NULL)
505 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507 vim_free(q);
508 if (p == NULL)
509 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000510 if (*p != '*')
511 {
512 bp->dbg_name = fix_fname(p);
513 vim_free(p);
514 }
515 else
516 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517 }
518
519 if (bp->dbg_name == NULL)
520 return FAIL;
521 return OK;
522}
523
524/*
525 * ":breakadd".
526 */
527 void
528ex_breakadd(eap)
529 exarg_T *eap;
530{
531 struct debuggy *bp;
532 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534
Bram Moolenaar05159a02005-02-26 23:04:13 +0000535 gap = &dbg_breakp;
536#ifdef FEAT_PROFILE
537 if (eap->cmdidx == CMD_profile)
538 gap = &prof_ga;
539#endif
540
541 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000543 bp = &DEBUGGY(gap, gap->ga_len);
544 bp->dbg_forceit = eap->forceit;
545
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
547 if (pat != NULL)
548 {
549 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
550 vim_free(pat);
551 }
552 if (pat == NULL || bp->dbg_prog == NULL)
553 vim_free(bp->dbg_name);
554 else
555 {
556 if (bp->dbg_lnum == 0) /* default line number is 1 */
557 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000558#ifdef FEAT_PROFILE
559 if (eap->cmdidx != CMD_profile)
560#endif
561 {
562 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
563 ++debug_tick;
564 }
565 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 }
567 }
568}
569
570/*
571 * ":debuggreedy".
572 */
573 void
574ex_debuggreedy(eap)
575 exarg_T *eap;
576{
577 if (eap->addr_count == 0 || eap->line2 != 0)
578 debug_greedy = TRUE;
579 else
580 debug_greedy = FALSE;
581}
582
583/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000584 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585 */
586 void
587ex_breakdel(eap)
588 exarg_T *eap;
589{
590 struct debuggy *bp, *bpi;
591 int nr;
592 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000593 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 int i;
595 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000596 garray_T *gap;
597
598 gap = &dbg_breakp;
599#ifdef FEAT_PROFILE
600 if (eap->cmdidx == CMD_profdel)
601 gap = &prof_ga;
602#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603
604 if (vim_isdigit(*eap->arg))
605 {
606 /* ":breakdel {nr}" */
607 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000608 for (i = 0; i < gap->ga_len; ++i)
609 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610 {
611 todel = i;
612 break;
613 }
614 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000615 else if (*eap->arg == '*')
616 {
617 todel = 0;
618 del_all = TRUE;
619 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620 else
621 {
622 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000623 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000625 bp = &DEBUGGY(gap, gap->ga_len);
626 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000628 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629 if (bp->dbg_type == bpi->dbg_type
630 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
631 && (bp->dbg_lnum == bpi->dbg_lnum
632 || (bp->dbg_lnum == 0
633 && (best_lnum == 0
634 || bpi->dbg_lnum < best_lnum))))
635 {
636 todel = i;
637 best_lnum = bpi->dbg_lnum;
638 }
639 }
640 vim_free(bp->dbg_name);
641 }
642
643 if (todel < 0)
644 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
645 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000646 {
647 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000648 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000649 vim_free(DEBUGGY(gap, todel).dbg_name);
650 vim_free(DEBUGGY(gap, todel).dbg_prog);
651 --gap->ga_len;
652 if (todel < gap->ga_len)
653 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
654 (gap->ga_len - todel) * sizeof(struct debuggy));
655#ifdef FEAT_PROFILE
656 if (eap->cmdidx == CMD_breakdel)
657#endif
658 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000659 if (!del_all)
660 break;
661 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000662
663 /* If all breakpoints were removed clear the array. */
664 if (gap->ga_len == 0)
665 ga_clear(gap);
666 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667}
668
669/*
670 * ":breaklist".
671 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 void
673ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000674 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675{
676 struct debuggy *bp;
677 int i;
678
679 if (dbg_breakp.ga_len == 0)
680 MSG(_("No breakpoints defined"));
681 else
682 for (i = 0; i < dbg_breakp.ga_len; ++i)
683 {
684 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200685 if (bp->dbg_type == DBG_FILE)
686 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687 smsg((char_u *)_("%3d %s %s line %ld"),
688 bp->dbg_nr,
689 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200690 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691 (long)bp->dbg_lnum);
692 }
693}
694
695/*
696 * Find a breakpoint for a function or sourced file.
697 * Returns line number at which to break; zero when no matching breakpoint.
698 */
699 linenr_T
700dbg_find_breakpoint(file, fname, after)
701 int file; /* TRUE for a file, FALSE for a function */
702 char_u *fname; /* file or function name */
703 linenr_T after; /* after this line number */
704{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000705 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
706}
707
708#if defined(FEAT_PROFILE) || defined(PROTO)
709/*
710 * Return TRUE if profiling is on for a function or sourced file.
711 */
712 int
713has_profiling(file, fname, fp)
714 int file; /* TRUE for a file, FALSE for a function */
715 char_u *fname; /* file or function name */
716 int *fp; /* return: forceit */
717{
718 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
719 != (linenr_T)0);
720}
721#endif
722
723/*
724 * Common code for dbg_find_breakpoint() and has_profiling().
725 */
726 static linenr_T
727debuggy_find(file, fname, after, gap, fp)
728 int file; /* TRUE for a file, FALSE for a function */
729 char_u *fname; /* file or function name */
730 linenr_T after; /* after this line number */
731 garray_T *gap; /* either &dbg_breakp or &prof_ga */
732 int *fp; /* if not NULL: return forceit */
733{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 struct debuggy *bp;
735 int i;
736 linenr_T lnum = 0;
737 regmatch_T regmatch;
738 char_u *name = fname;
739 int prev_got_int;
740
Bram Moolenaar05159a02005-02-26 23:04:13 +0000741 /* Return quickly when there are no breakpoints. */
742 if (gap->ga_len == 0)
743 return (linenr_T)0;
744
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 /* Replace K_SNR in function name with "<SNR>". */
746 if (!file && fname[0] == K_SPECIAL)
747 {
748 name = alloc((unsigned)STRLEN(fname) + 3);
749 if (name == NULL)
750 name = fname;
751 else
752 {
753 STRCPY(name, "<SNR>");
754 STRCPY(name + 5, fname + 3);
755 }
756 }
757
Bram Moolenaar05159a02005-02-26 23:04:13 +0000758 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000760 /* Skip entries that are not useful or are for a line that is beyond
761 * an already found breakpoint. */
762 bp = &DEBUGGY(gap, i);
763 if (((bp->dbg_type == DBG_FILE) == file && (
764#ifdef FEAT_PROFILE
765 gap == &prof_ga ||
766#endif
767 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768 {
769 regmatch.regprog = bp->dbg_prog;
770 regmatch.rm_ic = FALSE;
771 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000772 * Save the value of got_int and reset it. We don't want a
773 * previous interruption cancel matching, only hitting CTRL-C
774 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 */
776 prev_got_int = got_int;
777 got_int = FALSE;
778 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000779 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000781 if (fp != NULL)
782 *fp = bp->dbg_forceit;
783 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 got_int |= prev_got_int;
785 }
786 }
787 if (name != fname)
788 vim_free(name);
789
790 return lnum;
791}
792
793/*
794 * Called when a breakpoint was encountered.
795 */
796 void
797dbg_breakpoint(name, lnum)
798 char_u *name;
799 linenr_T lnum;
800{
801 /* We need to check if this line is actually executed in do_one_cmd() */
802 debug_breakpoint_name = name;
803 debug_breakpoint_lnum = lnum;
804}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000805
806
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000807# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000808/*
809 * Store the current time in "tm".
810 */
811 void
812profile_start(tm)
813 proftime_T *tm;
814{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000815# ifdef WIN3264
816 QueryPerformanceCounter(tm);
817# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000818 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000819# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000820}
821
822/*
823 * Compute the elapsed time from "tm" till now and store in "tm".
824 */
825 void
826profile_end(tm)
827 proftime_T *tm;
828{
829 proftime_T now;
830
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000831# ifdef WIN3264
832 QueryPerformanceCounter(&now);
833 tm->QuadPart = now.QuadPart - tm->QuadPart;
834# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000835 gettimeofday(&now, NULL);
836 tm->tv_usec = now.tv_usec - tm->tv_usec;
837 tm->tv_sec = now.tv_sec - tm->tv_sec;
838 if (tm->tv_usec < 0)
839 {
840 tm->tv_usec += 1000000;
841 --tm->tv_sec;
842 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000843# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000844}
845
846/*
847 * Subtract the time "tm2" from "tm".
848 */
849 void
850profile_sub(tm, tm2)
851 proftime_T *tm, *tm2;
852{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000853# ifdef WIN3264
854 tm->QuadPart -= tm2->QuadPart;
855# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000856 tm->tv_usec -= tm2->tv_usec;
857 tm->tv_sec -= tm2->tv_sec;
858 if (tm->tv_usec < 0)
859 {
860 tm->tv_usec += 1000000;
861 --tm->tv_sec;
862 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000863# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000864}
865
866/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000867 * Return a string that represents the time in "tm".
868 * Uses a static buffer!
869 */
870 char *
871profile_msg(tm)
872 proftime_T *tm;
873{
874 static char buf[50];
875
876# ifdef WIN3264
877 LARGE_INTEGER fr;
878
879 QueryPerformanceFrequency(&fr);
880 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
881# else
882 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000883# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000884 return buf;
885}
886
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000887/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000888 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000889 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000890 void
891profile_setlimit(msec, tm)
892 long msec;
893 proftime_T *tm;
894{
895 if (msec <= 0) /* no limit */
896 profile_zero(tm);
897 else
898 {
899# ifdef WIN3264
900 LARGE_INTEGER fr;
901
902 QueryPerformanceCounter(tm);
903 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000904 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000905# else
906 long usec;
907
908 gettimeofday(tm, NULL);
909 usec = (long)tm->tv_usec + (long)msec * 1000;
910 tm->tv_usec = usec % 1000000L;
911 tm->tv_sec += usec / 1000000L;
912# endif
913 }
914}
915
916/*
917 * Return TRUE if the current time is past "tm".
918 */
919 int
920profile_passed_limit(tm)
921 proftime_T *tm;
922{
923 proftime_T now;
924
925# ifdef WIN3264
926 if (tm->QuadPart == 0) /* timer was not set */
927 return FALSE;
928 QueryPerformanceCounter(&now);
929 return (now.QuadPart > tm->QuadPart);
930# else
931 if (tm->tv_sec == 0) /* timer was not set */
932 return FALSE;
933 gettimeofday(&now, NULL);
934 return (now.tv_sec > tm->tv_sec
935 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
936# endif
937}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000938
939/*
940 * Set the time in "tm" to zero.
941 */
942 void
943profile_zero(tm)
944 proftime_T *tm;
945{
946# ifdef WIN3264
947 tm->QuadPart = 0;
948# else
949 tm->tv_usec = 0;
950 tm->tv_sec = 0;
951# endif
952}
953
Bram Moolenaar76929292008-01-06 19:07:36 +0000954# endif /* FEAT_PROFILE || FEAT_RELTIME */
955
956# if defined(FEAT_PROFILE) || defined(PROTO)
957/*
958 * Functions for profiling.
959 */
960static void script_do_profile __ARGS((scriptitem_T *si));
961static void script_dump_profile __ARGS((FILE *fd));
962static proftime_T prof_wait_time;
963
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000964/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000965 * Add the time "tm2" to "tm".
966 */
967 void
968profile_add(tm, tm2)
969 proftime_T *tm, *tm2;
970{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000971# ifdef WIN3264
972 tm->QuadPart += tm2->QuadPart;
973# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000974 tm->tv_usec += tm2->tv_usec;
975 tm->tv_sec += tm2->tv_sec;
976 if (tm->tv_usec >= 1000000)
977 {
978 tm->tv_usec -= 1000000;
979 ++tm->tv_sec;
980 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000981# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000982}
983
984/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000985 * Add the "self" time from the total time and the children's time.
986 */
987 void
988profile_self(self, total, children)
989 proftime_T *self, *total, *children;
990{
991 /* Check that the result won't be negative. Can happen with recursive
992 * calls. */
993#ifdef WIN3264
994 if (total->QuadPart <= children->QuadPart)
995 return;
996#else
997 if (total->tv_sec < children->tv_sec
998 || (total->tv_sec == children->tv_sec
999 && total->tv_usec <= children->tv_usec))
1000 return;
1001#endif
1002 profile_add(self, total);
1003 profile_sub(self, children);
1004}
1005
1006/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001007 * Get the current waittime.
1008 */
1009 void
1010profile_get_wait(tm)
1011 proftime_T *tm;
1012{
1013 *tm = prof_wait_time;
1014}
1015
1016/*
1017 * Subtract the passed waittime since "tm" from "tma".
1018 */
1019 void
1020profile_sub_wait(tm, tma)
1021 proftime_T *tm, *tma;
1022{
1023 proftime_T tm3 = prof_wait_time;
1024
1025 profile_sub(&tm3, tm);
1026 profile_sub(tma, &tm3);
1027}
1028
1029/*
1030 * Return TRUE if "tm1" and "tm2" are equal.
1031 */
1032 int
1033profile_equal(tm1, tm2)
1034 proftime_T *tm1, *tm2;
1035{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001036# ifdef WIN3264
1037 return (tm1->QuadPart == tm2->QuadPart);
1038# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001039 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001040# endif
1041}
1042
1043/*
1044 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1045 */
1046 int
1047profile_cmp(tm1, tm2)
1048 proftime_T *tm1, *tm2;
1049{
1050# ifdef WIN3264
1051 return (int)(tm2->QuadPart - tm1->QuadPart);
1052# else
1053 if (tm1->tv_sec == tm2->tv_sec)
1054 return tm2->tv_usec - tm1->tv_usec;
1055 return tm2->tv_sec - tm1->tv_sec;
1056# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001057}
1058
Bram Moolenaar05159a02005-02-26 23:04:13 +00001059static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001060static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001061
1062/*
1063 * ":profile cmd args"
1064 */
1065 void
1066ex_profile(eap)
1067 exarg_T *eap;
1068{
1069 char_u *e;
1070 int len;
1071
1072 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001073 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001074 e = skipwhite(e);
1075
1076 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1077 {
1078 vim_free(profile_fname);
1079 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001080 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001081 profile_zero(&prof_wait_time);
1082 set_vim_var_nr(VV_PROFILING, 1L);
1083 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001084 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001085 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001086 else if (STRCMP(eap->arg, "pause") == 0)
1087 {
1088 if (do_profiling == PROF_YES)
1089 profile_start(&pause_time);
1090 do_profiling = PROF_PAUSED;
1091 }
1092 else if (STRCMP(eap->arg, "continue") == 0)
1093 {
1094 if (do_profiling == PROF_PAUSED)
1095 {
1096 profile_end(&pause_time);
1097 profile_add(&prof_wait_time, &pause_time);
1098 }
1099 do_profiling = PROF_YES;
1100 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001101 else
1102 {
1103 /* The rest is similar to ":breakadd". */
1104 ex_breakadd(eap);
1105 }
1106}
1107
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001108/* Command line expansion for :profile. */
1109static enum
1110{
1111 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001112 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001113} pexpand_what;
1114
1115static char *pexpand_cmds[] = {
1116 "start",
1117#define PROFCMD_START 0
1118 "pause",
1119#define PROFCMD_PAUSE 1
1120 "continue",
1121#define PROFCMD_CONTINUE 2
1122 "func",
1123#define PROFCMD_FUNC 3
1124 "file",
1125#define PROFCMD_FILE 4
1126 NULL
1127#define PROFCMD_LAST 5
1128};
1129
1130/*
1131 * Function given to ExpandGeneric() to obtain the profile command
1132 * specific expansion.
1133 */
1134 char_u *
1135get_profile_name(xp, idx)
1136 expand_T *xp UNUSED;
1137 int idx;
1138{
1139 switch (pexpand_what)
1140 {
1141 case PEXP_SUBCMD:
1142 return (char_u *)pexpand_cmds[idx];
1143 /* case PEXP_FUNC: TODO */
1144 default:
1145 return NULL;
1146 }
1147}
1148
1149/*
1150 * Handle command line completion for :profile command.
1151 */
1152 void
1153set_context_in_profile_cmd(xp, arg)
1154 expand_T *xp;
1155 char_u *arg;
1156{
1157 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001158
1159 /* Default: expand subcommands. */
1160 xp->xp_context = EXPAND_PROFILE;
1161 pexpand_what = PEXP_SUBCMD;
1162 xp->xp_pattern = arg;
1163
1164 end_subcmd = skiptowhite(arg);
1165 if (*end_subcmd == NUL)
1166 return;
1167
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001168 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001169 {
1170 xp->xp_context = EXPAND_FILES;
1171 xp->xp_pattern = skipwhite(end_subcmd);
1172 return;
1173 }
1174
1175 /* TODO: expand function names after "func" */
1176 xp->xp_context = EXPAND_NOTHING;
1177}
1178
Bram Moolenaar05159a02005-02-26 23:04:13 +00001179/*
1180 * Dump the profiling info.
1181 */
1182 void
1183profile_dump()
1184{
1185 FILE *fd;
1186
1187 if (profile_fname != NULL)
1188 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001189 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001190 if (fd == NULL)
1191 EMSG2(_(e_notopen), profile_fname);
1192 else
1193 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001194 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001195 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001196 fclose(fd);
1197 }
1198 }
1199}
1200
1201/*
1202 * Start profiling script "fp".
1203 */
1204 static void
1205script_do_profile(si)
1206 scriptitem_T *si;
1207{
1208 si->sn_pr_count = 0;
1209 profile_zero(&si->sn_pr_total);
1210 profile_zero(&si->sn_pr_self);
1211
1212 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1213 si->sn_prl_idx = -1;
1214 si->sn_prof_on = TRUE;
1215 si->sn_pr_nest = 0;
1216}
1217
1218/*
1219 * save time when starting to invoke another script or function.
1220 */
1221 void
1222script_prof_save(tm)
1223 proftime_T *tm; /* place to store wait time */
1224{
1225 scriptitem_T *si;
1226
1227 if (current_SID > 0 && current_SID <= script_items.ga_len)
1228 {
1229 si = &SCRIPT_ITEM(current_SID);
1230 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1231 profile_start(&si->sn_pr_child);
1232 }
1233 profile_get_wait(tm);
1234}
1235
1236/*
1237 * Count time spent in children after invoking another script or function.
1238 */
1239 void
1240script_prof_restore(tm)
1241 proftime_T *tm;
1242{
1243 scriptitem_T *si;
1244
1245 if (current_SID > 0 && current_SID <= script_items.ga_len)
1246 {
1247 si = &SCRIPT_ITEM(current_SID);
1248 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1249 {
1250 profile_end(&si->sn_pr_child);
1251 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1252 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1253 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1254 }
1255 }
1256}
1257
1258static proftime_T inchar_time;
1259
1260/*
1261 * Called when starting to wait for the user to type a character.
1262 */
1263 void
1264prof_inchar_enter()
1265{
1266 profile_start(&inchar_time);
1267}
1268
1269/*
1270 * Called when finished waiting for the user to type a character.
1271 */
1272 void
1273prof_inchar_exit()
1274{
1275 profile_end(&inchar_time);
1276 profile_add(&prof_wait_time, &inchar_time);
1277}
1278
1279/*
1280 * Dump the profiling results for all scripts in file "fd".
1281 */
1282 static void
1283script_dump_profile(fd)
1284 FILE *fd;
1285{
1286 int id;
1287 scriptitem_T *si;
1288 int i;
1289 FILE *sfd;
1290 sn_prl_T *pp;
1291
1292 for (id = 1; id <= script_items.ga_len; ++id)
1293 {
1294 si = &SCRIPT_ITEM(id);
1295 if (si->sn_prof_on)
1296 {
1297 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1298 if (si->sn_pr_count == 1)
1299 fprintf(fd, "Sourced 1 time\n");
1300 else
1301 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1302 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1303 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1304 fprintf(fd, "\n");
1305 fprintf(fd, "count total (s) self (s)\n");
1306
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001307 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001308 if (sfd == NULL)
1309 fprintf(fd, "Cannot open file!\n");
1310 else
1311 {
1312 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1313 {
1314 if (vim_fgets(IObuff, IOSIZE, sfd))
1315 break;
1316 pp = &PRL_ITEM(si, i);
1317 if (pp->snp_count > 0)
1318 {
1319 fprintf(fd, "%5d ", pp->snp_count);
1320 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1321 fprintf(fd, " ");
1322 else
1323 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1324 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1325 }
1326 else
1327 fprintf(fd, " ");
1328 fprintf(fd, "%s", IObuff);
1329 }
1330 fclose(sfd);
1331 }
1332 fprintf(fd, "\n");
1333 }
1334 }
1335}
1336
1337/*
1338 * Return TRUE when a function defined in the current script should be
1339 * profiled.
1340 */
1341 int
1342prof_def_func()
1343{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001344 if (current_SID > 0)
1345 return SCRIPT_ITEM(current_SID).sn_pr_force;
1346 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001347}
1348
1349# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001350#endif
1351
1352/*
1353 * If 'autowrite' option set, try to write the file.
1354 * Careful: autocommands may make "buf" invalid!
1355 *
1356 * return FAIL for failure, OK otherwise
1357 */
1358 int
1359autowrite(buf, forceit)
1360 buf_T *buf;
1361 int forceit;
1362{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001363 int r;
1364
Bram Moolenaar071d4272004-06-13 20:20:40 +00001365 if (!(p_aw || p_awa) || !p_write
1366#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001367 /* never autowrite a "nofile" or "nowrite" buffer */
1368 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001369#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001370 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001371 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001372 r = buf_write_all(buf, forceit);
1373
1374 /* Writing may succeed but the buffer still changed, e.g., when there is a
1375 * conversion error. We do want to return FAIL then. */
1376 if (buf_valid(buf) && bufIsChanged(buf))
1377 r = FAIL;
1378 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001379}
1380
1381/*
1382 * flush all buffers, except the ones that are readonly
1383 */
1384 void
1385autowrite_all()
1386{
1387 buf_T *buf;
1388
1389 if (!(p_aw || p_awa) || !p_write)
1390 return;
1391 for (buf = firstbuf; buf; buf = buf->b_next)
1392 if (bufIsChanged(buf) && !buf->b_p_ro)
1393 {
1394 (void)buf_write_all(buf, FALSE);
1395#ifdef FEAT_AUTOCMD
1396 /* an autocommand may have deleted the buffer */
1397 if (!buf_valid(buf))
1398 buf = firstbuf;
1399#endif
1400 }
1401}
1402
1403/*
1404 * return TRUE if buffer was changed and cannot be abandoned.
1405 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001406 int
1407check_changed(buf, checkaw, mult_win, forceit, allbuf)
1408 buf_T *buf;
1409 int checkaw; /* do autowrite if buffer was changed */
1410 int mult_win; /* check also when several wins for the buf */
1411 int forceit;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001412 int allbuf UNUSED; /* may write all buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001413{
1414 if ( !forceit
1415 && bufIsChanged(buf)
1416 && (mult_win || buf->b_nwindows <= 1)
1417 && (!checkaw || autowrite(buf, forceit) == FAIL))
1418 {
1419#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1420 if ((p_confirm || cmdmod.confirm) && p_write)
1421 {
1422 buf_T *buf2;
1423 int count = 0;
1424
1425 if (allbuf)
1426 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1427 if (bufIsChanged(buf2)
1428 && (buf2->b_ffname != NULL
1429# ifdef FEAT_BROWSE
1430 || cmdmod.browse
1431# endif
1432 ))
1433 ++count;
1434# ifdef FEAT_AUTOCMD
1435 if (!buf_valid(buf))
1436 /* Autocommand deleted buffer, oops! It's not changed now. */
1437 return FALSE;
1438# endif
1439 dialog_changed(buf, count > 1);
1440# ifdef FEAT_AUTOCMD
1441 if (!buf_valid(buf))
1442 /* Autocommand deleted buffer, oops! It's not changed now. */
1443 return FALSE;
1444# endif
1445 return bufIsChanged(buf);
1446 }
1447#endif
1448 EMSG(_(e_nowrtmsg));
1449 return TRUE;
1450 }
1451 return FALSE;
1452}
1453
1454#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1455
1456#if defined(FEAT_BROWSE) || defined(PROTO)
1457/*
1458 * When wanting to write a file without a file name, ask the user for a name.
1459 */
1460 void
1461browse_save_fname(buf)
1462 buf_T *buf;
1463{
1464 if (buf->b_fname == NULL)
1465 {
1466 char_u *fname;
1467
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001468 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1469 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001470 if (fname != NULL)
1471 {
1472 if (setfname(buf, fname, NULL, TRUE) == OK)
1473 buf->b_flags |= BF_NOTEDITED;
1474 vim_free(fname);
1475 }
1476 }
1477}
1478#endif
1479
1480/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001481 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001482 * Must check 'write' option first!
1483 */
1484 void
1485dialog_changed(buf, checkall)
1486 buf_T *buf;
1487 int checkall; /* may abandon all changed buffers */
1488{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001489 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001490 int ret;
1491 buf_T *buf2;
1492
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001493 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001494 (buf->b_fname != NULL) ?
1495 buf->b_fname : (char_u *)_("Untitled"));
1496 if (checkall)
1497 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1498 else
1499 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1500
1501 if (ret == VIM_YES)
1502 {
1503#ifdef FEAT_BROWSE
1504 /* May get file name, when there is none */
1505 browse_save_fname(buf);
1506#endif
1507 if (buf->b_fname != NULL) /* didn't hit Cancel */
1508 (void)buf_write_all(buf, FALSE);
1509 }
1510 else if (ret == VIM_NO)
1511 {
1512 unchanged(buf, TRUE);
1513 }
1514 else if (ret == VIM_ALL)
1515 {
1516 /*
1517 * Write all modified files that can be written.
1518 * Skip readonly buffers, these need to be confirmed
1519 * individually.
1520 */
1521 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1522 {
1523 if (bufIsChanged(buf2)
1524 && (buf2->b_ffname != NULL
1525#ifdef FEAT_BROWSE
1526 || cmdmod.browse
1527#endif
1528 )
1529 && !buf2->b_p_ro)
1530 {
1531#ifdef FEAT_BROWSE
1532 /* May get file name, when there is none */
1533 browse_save_fname(buf2);
1534#endif
1535 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1536 (void)buf_write_all(buf2, FALSE);
1537#ifdef FEAT_AUTOCMD
1538 /* an autocommand may have deleted the buffer */
1539 if (!buf_valid(buf2))
1540 buf2 = firstbuf;
1541#endif
1542 }
1543 }
1544 }
1545 else if (ret == VIM_DISCARDALL)
1546 {
1547 /*
1548 * mark all buffers as unchanged
1549 */
1550 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1551 unchanged(buf2, TRUE);
1552 }
1553}
1554#endif
1555
1556/*
1557 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1558 * hidden, autowriting it or unloading it.
1559 */
1560 int
1561can_abandon(buf, forceit)
1562 buf_T *buf;
1563 int forceit;
1564{
1565 return ( P_HID(buf)
1566 || !bufIsChanged(buf)
1567 || buf->b_nwindows > 1
1568 || autowrite(buf, forceit) == OK
1569 || forceit);
1570}
1571
1572/*
1573 * Return TRUE if any buffer was changed and cannot be abandoned.
1574 * That changed buffer becomes the current buffer.
1575 */
1576 int
1577check_changed_any(hidden)
1578 int hidden; /* Only check hidden buffers */
1579{
1580 buf_T *buf;
1581 int save;
1582#ifdef FEAT_WINDOWS
1583 win_T *wp;
1584#endif
1585
1586 for (;;)
1587 {
1588 /* check curbuf first: if it was changed we can't abandon it */
1589 if (!hidden && curbufIsChanged())
1590 buf = curbuf;
1591 else
1592 {
1593 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1594 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1595 break;
1596 }
1597 if (buf == NULL) /* No buffers changed */
1598 return FALSE;
1599
Bram Moolenaar373154b2007-02-13 05:19:30 +00001600 /* Try auto-writing the buffer. If this fails but the buffer no
1601 * longer exists it's not changed, that's OK. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1603 break; /* didn't save - still changes */
1604 }
1605
1606 exiting = FALSE;
1607#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1608 /*
1609 * When ":confirm" used, don't give an error message.
1610 */
1611 if (!(p_confirm || cmdmod.confirm))
1612#endif
1613 {
1614 /* There must be a wait_return for this message, do_buffer()
1615 * may cause a redraw. But wait_return() is a no-op when vgetc()
1616 * is busy (Quit used from window menu), then make sure we don't
1617 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001618 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001619 {
1620 msg_row = cmdline_row;
1621 msg_col = 0;
1622 msg_didout = FALSE;
1623 }
1624 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1625 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1626 buf->b_fname))
1627 {
1628 save = no_wait_return;
1629 no_wait_return = FALSE;
1630 wait_return(FALSE);
1631 no_wait_return = save;
1632 }
1633 }
1634
1635#ifdef FEAT_WINDOWS
1636 /* Try to find a window that contains the buffer. */
1637 if (buf != curbuf)
1638 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1639 if (wp->w_buffer == buf)
1640 {
1641 win_goto(wp);
1642# ifdef FEAT_AUTOCMD
1643 /* Paranoia: did autocms wipe out the buffer with changes? */
1644 if (!buf_valid(buf))
1645 return TRUE;
1646# endif
1647 break;
1648 }
1649#endif
1650
1651 /* Open the changed buffer in the current window. */
1652 if (buf != curbuf)
1653 set_curbuf(buf, DOBUF_GOTO);
1654
1655 return TRUE;
1656}
1657
1658/*
1659 * return FAIL if there is no file name, OK if there is one
1660 * give error message for FAIL
1661 */
1662 int
1663check_fname()
1664{
1665 if (curbuf->b_ffname == NULL)
1666 {
1667 EMSG(_(e_noname));
1668 return FAIL;
1669 }
1670 return OK;
1671}
1672
1673/*
1674 * flush the contents of a buffer, unless it has no file name
1675 *
1676 * return FAIL for failure, OK otherwise
1677 */
1678 int
1679buf_write_all(buf, forceit)
1680 buf_T *buf;
1681 int forceit;
1682{
1683 int retval;
1684#ifdef FEAT_AUTOCMD
1685 buf_T *old_curbuf = curbuf;
1686#endif
1687
1688 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1689 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1690 FALSE, forceit, TRUE, FALSE));
1691#ifdef FEAT_AUTOCMD
1692 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001693 {
1694 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001695 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001696 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697#endif
1698 return retval;
1699}
1700
1701/*
1702 * Code to handle the argument list.
1703 */
1704
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001705static char_u *do_one_arg __ARGS((char_u *str));
1706static int do_arglist __ARGS((char_u *str, int what, int after));
1707static void alist_check_arg_idx __ARGS((void));
1708static int editing_arg_idx __ARGS((win_T *win));
1709#ifdef FEAT_LISTCMDS
1710static int alist_add_list __ARGS((int count, char_u **files, int after));
1711#endif
1712#define AL_SET 1
1713#define AL_ADD 2
1714#define AL_DEL 3
1715
Bram Moolenaar071d4272004-06-13 20:20:40 +00001716/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001717 * Isolate one argument, taking backticks.
1718 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719 * Return a pointer to the start of the next argument.
1720 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001721 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722do_one_arg(str)
1723 char_u *str;
1724{
1725 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726 int inbacktick;
1727
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 inbacktick = FALSE;
1729 for (p = str; *str; ++str)
1730 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001731 /* When the backslash is used for escaping the special meaning of a
1732 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001733 if (rem_backslash(str))
1734 {
1735 *p++ = *str++;
1736 *p++ = *str;
1737 }
1738 else
1739 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001740 /* An item ends at a space not in backticks */
1741 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001743 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001745 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001746 }
1747 }
1748 str = skipwhite(str);
1749 *p = NUL;
1750
1751 return str;
1752}
1753
Bram Moolenaar86b68352004-12-27 21:59:20 +00001754/*
1755 * Separate the arguments in "str" and return a list of pointers in the
1756 * growarray "gap".
1757 */
1758 int
1759get_arglist(gap, str)
1760 garray_T *gap;
1761 char_u *str;
1762{
1763 ga_init2(gap, (int)sizeof(char_u *), 20);
1764 while (*str != NUL)
1765 {
1766 if (ga_grow(gap, 1) == FAIL)
1767 {
1768 ga_clear(gap);
1769 return FAIL;
1770 }
1771 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1772
1773 /* Isolate one argument, change it in-place, put a NUL after it. */
1774 str = do_one_arg(str);
1775 }
1776 return OK;
1777}
1778
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001779#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001780/*
1781 * Parse a list of arguments (file names), expand them and return in
1782 * "fnames[fcountp]".
1783 * Return FAIL or OK.
1784 */
1785 int
1786get_arglist_exp(str, fcountp, fnamesp)
1787 char_u *str;
1788 int *fcountp;
1789 char_u ***fnamesp;
1790{
1791 garray_T ga;
1792 int i;
1793
1794 if (get_arglist(&ga, str) == FAIL)
1795 return FAIL;
1796 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1797 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1798 ga_clear(&ga);
1799 return i;
1800}
1801#endif
1802
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1804/*
1805 * Redefine the argument list.
1806 */
1807 void
1808set_arglist(str)
1809 char_u *str;
1810{
1811 do_arglist(str, AL_SET, 0);
1812}
1813#endif
1814
1815/*
1816 * "what" == AL_SET: Redefine the argument list to 'str'.
1817 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1818 * "what" == AL_DEL: remove files in 'str' from the argument list.
1819 *
1820 * Return FAIL for failure, OK otherwise.
1821 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822 static int
1823do_arglist(str, what, after)
1824 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001825 int what UNUSED;
1826 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827{
1828 garray_T new_ga;
1829 int exp_count;
1830 char_u **exp_files;
1831 int i;
1832#ifdef FEAT_LISTCMDS
1833 char_u *p;
1834 int match;
1835#endif
1836
1837 /*
1838 * Collect all file name arguments in "new_ga".
1839 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001840 if (get_arglist(&new_ga, str) == FAIL)
1841 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001842
1843#ifdef FEAT_LISTCMDS
1844 if (what == AL_DEL)
1845 {
1846 regmatch_T regmatch;
1847 int didone;
1848
1849 /*
1850 * Delete the items: use each item as a regexp and find a match in the
1851 * argument list.
1852 */
1853#ifdef CASE_INSENSITIVE_FILENAME
1854 regmatch.rm_ic = TRUE; /* Always ignore case */
1855#else
1856 regmatch.rm_ic = FALSE; /* Never ignore case */
1857#endif
1858 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1859 {
1860 p = ((char_u **)new_ga.ga_data)[i];
1861 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1862 if (p == NULL)
1863 break;
1864 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1865 if (regmatch.regprog == NULL)
1866 {
1867 vim_free(p);
1868 break;
1869 }
1870
1871 didone = FALSE;
1872 for (match = 0; match < ARGCOUNT; ++match)
1873 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1874 (colnr_T)0))
1875 {
1876 didone = TRUE;
1877 vim_free(ARGLIST[match].ae_fname);
1878 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1879 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1880 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001881 if (curwin->w_arg_idx > match)
1882 --curwin->w_arg_idx;
1883 --match;
1884 }
1885
1886 vim_free(regmatch.regprog);
1887 vim_free(p);
1888 if (!didone)
1889 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1890 }
1891 ga_clear(&new_ga);
1892 }
1893 else
1894#endif
1895 {
1896 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1897 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1898 ga_clear(&new_ga);
1899 if (i == FAIL)
1900 return FAIL;
1901 if (exp_count == 0)
1902 {
1903 EMSG(_(e_nomatch));
1904 return FAIL;
1905 }
1906
1907#ifdef FEAT_LISTCMDS
1908 if (what == AL_ADD)
1909 {
1910 (void)alist_add_list(exp_count, exp_files, after);
1911 vim_free(exp_files);
1912 }
1913 else /* what == AL_SET */
1914#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001915 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001916 }
1917
1918 alist_check_arg_idx();
1919
1920 return OK;
1921}
1922
1923/*
1924 * Check the validity of the arg_idx for each other window.
1925 */
1926 static void
1927alist_check_arg_idx()
1928{
1929#ifdef FEAT_WINDOWS
1930 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001931 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932
Bram Moolenaarf740b292006-02-16 22:11:02 +00001933 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934 if (win->w_alist == curwin->w_alist)
1935 check_arg_idx(win);
1936#else
1937 check_arg_idx(curwin);
1938#endif
1939}
1940
1941/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01001942 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001943 * index.
1944 */
1945 static int
1946editing_arg_idx(win)
1947 win_T *win;
1948{
1949 return !(win->w_arg_idx >= WARGCOUNT(win)
1950 || (win->w_buffer->b_fnum
1951 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1952 && (win->w_buffer->b_ffname == NULL
1953 || !(fullpathcmp(
1954 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1955 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1956}
1957
1958/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 * Check if window "win" is editing the w_arg_idx file in its argument list.
1960 */
1961 void
1962check_arg_idx(win)
1963 win_T *win;
1964{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001965 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966 {
1967 /* We are not editing the current entry in the argument list.
1968 * Set "arg_had_last" if we are editing the last one. */
1969 win->w_arg_idx_invalid = TRUE;
1970 if (win->w_arg_idx != WARGCOUNT(win) - 1
1971 && arg_had_last == FALSE
1972#ifdef FEAT_WINDOWS
1973 && ALIST(win) == &global_alist
1974#endif
1975 && GARGCOUNT > 0
1976 && win->w_arg_idx < GARGCOUNT
1977 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1978 || (win->w_buffer->b_ffname != NULL
1979 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1980 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1981 arg_had_last = TRUE;
1982 }
1983 else
1984 {
1985 /* We are editing the current entry in the argument list.
1986 * Set "arg_had_last" if it's also the last one */
1987 win->w_arg_idx_invalid = FALSE;
1988 if (win->w_arg_idx == WARGCOUNT(win) - 1
1989#ifdef FEAT_WINDOWS
1990 && win->w_alist == &global_alist
1991#endif
1992 )
1993 arg_had_last = TRUE;
1994 }
1995}
1996
1997/*
1998 * ":args", ":argslocal" and ":argsglobal".
1999 */
2000 void
2001ex_args(eap)
2002 exarg_T *eap;
2003{
2004 int i;
2005
2006 if (eap->cmdidx != CMD_args)
2007 {
2008#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2009 alist_unlink(ALIST(curwin));
2010 if (eap->cmdidx == CMD_argglobal)
2011 ALIST(curwin) = &global_alist;
2012 else /* eap->cmdidx == CMD_arglocal */
2013 alist_new();
2014#else
2015 ex_ni(eap);
2016 return;
2017#endif
2018 }
2019
2020 if (!ends_excmd(*eap->arg))
2021 {
2022 /*
2023 * ":args file ..": define new argument list, handle like ":next"
2024 * Also for ":argslocal file .." and ":argsglobal file ..".
2025 */
2026 ex_next(eap);
2027 }
2028 else
2029#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2030 if (eap->cmdidx == CMD_args)
2031#endif
2032 {
2033 /*
2034 * ":args": list arguments.
2035 */
2036 if (ARGCOUNT > 0)
2037 {
2038 /* Overwrite the command, for a short list there is no scrolling
2039 * required and no wait_return(). */
2040 gotocmdline(TRUE);
2041 for (i = 0; i < ARGCOUNT; ++i)
2042 {
2043 if (i == curwin->w_arg_idx)
2044 msg_putchar('[');
2045 msg_outtrans(alist_name(&ARGLIST[i]));
2046 if (i == curwin->w_arg_idx)
2047 msg_putchar(']');
2048 msg_putchar(' ');
2049 }
2050 }
2051 }
2052#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2053 else if (eap->cmdidx == CMD_arglocal)
2054 {
2055 garray_T *gap = &curwin->w_alist->al_ga;
2056
2057 /*
2058 * ":argslocal": make a local copy of the global argument list.
2059 */
2060 if (ga_grow(gap, GARGCOUNT) == OK)
2061 for (i = 0; i < GARGCOUNT; ++i)
2062 if (GARGLIST[i].ae_fname != NULL)
2063 {
2064 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2065 vim_strsave(GARGLIST[i].ae_fname);
2066 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2067 GARGLIST[i].ae_fnum;
2068 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002069 }
2070 }
2071#endif
2072}
2073
2074/*
2075 * ":previous", ":sprevious", ":Next" and ":sNext".
2076 */
2077 void
2078ex_previous(eap)
2079 exarg_T *eap;
2080{
2081 /* If past the last one already, go to the last one. */
2082 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2083 do_argfile(eap, ARGCOUNT - 1);
2084 else
2085 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2086}
2087
2088/*
2089 * ":rewind", ":first", ":sfirst" and ":srewind".
2090 */
2091 void
2092ex_rewind(eap)
2093 exarg_T *eap;
2094{
2095 do_argfile(eap, 0);
2096}
2097
2098/*
2099 * ":last" and ":slast".
2100 */
2101 void
2102ex_last(eap)
2103 exarg_T *eap;
2104{
2105 do_argfile(eap, ARGCOUNT - 1);
2106}
2107
2108/*
2109 * ":argument" and ":sargument".
2110 */
2111 void
2112ex_argument(eap)
2113 exarg_T *eap;
2114{
2115 int i;
2116
2117 if (eap->addr_count > 0)
2118 i = eap->line2 - 1;
2119 else
2120 i = curwin->w_arg_idx;
2121 do_argfile(eap, i);
2122}
2123
2124/*
2125 * Edit file "argn" of the argument lists.
2126 */
2127 void
2128do_argfile(eap, argn)
2129 exarg_T *eap;
2130 int argn;
2131{
2132 int other;
2133 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002134 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002135
2136 if (argn < 0 || argn >= ARGCOUNT)
2137 {
2138 if (ARGCOUNT <= 1)
2139 EMSG(_("E163: There is only one file to edit"));
2140 else if (argn < 0)
2141 EMSG(_("E164: Cannot go before first file"));
2142 else
2143 EMSG(_("E165: Cannot go beyond last file"));
2144 }
2145 else
2146 {
2147 setpcmark();
2148#ifdef FEAT_GUI
2149 need_mouse_correct = TRUE;
2150#endif
2151
2152#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002153 /* split window or create new tab page first */
2154 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002155 {
2156 if (win_split(0, 0) == FAIL)
2157 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002158 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002159 }
2160 else
2161#endif
2162 {
2163 /*
2164 * if 'hidden' set, only check for changed file when re-editing
2165 * the same buffer
2166 */
2167 other = TRUE;
2168 if (P_HID(curbuf))
2169 {
2170 p = fix_fname(alist_name(&ARGLIST[argn]));
2171 other = otherfile(p);
2172 vim_free(p);
2173 }
2174 if ((!P_HID(curbuf) || !other)
2175 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2176 return;
2177 }
2178
2179 curwin->w_arg_idx = argn;
2180 if (argn == ARGCOUNT - 1
2181#ifdef FEAT_WINDOWS
2182 && curwin->w_alist == &global_alist
2183#endif
2184 )
2185 arg_had_last = TRUE;
2186
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002187 /* Edit the file; always use the last known line number.
2188 * When it fails (e.g. Abort for already edited file) restore the
2189 * argument index. */
2190 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002191 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002192 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2193 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002194 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002196 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002197 setmark('\'');
2198 }
2199}
2200
2201/*
2202 * ":next", and commands that behave like it.
2203 */
2204 void
2205ex_next(eap)
2206 exarg_T *eap;
2207{
2208 int i;
2209
2210 /*
2211 * check for changed buffer now, if this fails the argument list is not
2212 * redefined.
2213 */
2214 if ( P_HID(curbuf)
2215 || eap->cmdidx == CMD_snext
2216 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2217 {
2218 if (*eap->arg != NUL) /* redefine file list */
2219 {
2220 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2221 return;
2222 i = 0;
2223 }
2224 else
2225 i = curwin->w_arg_idx + (int)eap->line2;
2226 do_argfile(eap, i);
2227 }
2228}
2229
2230#ifdef FEAT_LISTCMDS
2231/*
2232 * ":argedit"
2233 */
2234 void
2235ex_argedit(eap)
2236 exarg_T *eap;
2237{
2238 int fnum;
2239 int i;
2240 char_u *s;
2241
2242 /* Add the argument to the buffer list and get the buffer number. */
2243 fnum = buflist_add(eap->arg, BLN_LISTED);
2244
2245 /* Check if this argument is already in the argument list. */
2246 for (i = 0; i < ARGCOUNT; ++i)
2247 if (ARGLIST[i].ae_fnum == fnum)
2248 break;
2249 if (i == ARGCOUNT)
2250 {
2251 /* Can't find it, add it to the argument list. */
2252 s = vim_strsave(eap->arg);
2253 if (s == NULL)
2254 return;
2255 i = alist_add_list(1, &s,
2256 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2257 if (i < 0)
2258 return;
2259 curwin->w_arg_idx = i;
2260 }
2261
2262 alist_check_arg_idx();
2263
2264 /* Edit the argument. */
2265 do_argfile(eap, i);
2266}
2267
2268/*
2269 * ":argadd"
2270 */
2271 void
2272ex_argadd(eap)
2273 exarg_T *eap;
2274{
2275 do_arglist(eap->arg, AL_ADD,
2276 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2277#ifdef FEAT_TITLE
2278 maketitle();
2279#endif
2280}
2281
2282/*
2283 * ":argdelete"
2284 */
2285 void
2286ex_argdelete(eap)
2287 exarg_T *eap;
2288{
2289 int i;
2290 int n;
2291
2292 if (eap->addr_count > 0)
2293 {
2294 /* ":1,4argdel": Delete all arguments in the range. */
2295 if (eap->line2 > ARGCOUNT)
2296 eap->line2 = ARGCOUNT;
2297 n = eap->line2 - eap->line1 + 1;
2298 if (*eap->arg != NUL || n <= 0)
2299 EMSG(_(e_invarg));
2300 else
2301 {
2302 for (i = eap->line1; i <= eap->line2; ++i)
2303 vim_free(ARGLIST[i - 1].ae_fname);
2304 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2305 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2306 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307 if (curwin->w_arg_idx >= eap->line2)
2308 curwin->w_arg_idx -= n;
2309 else if (curwin->w_arg_idx > eap->line1)
2310 curwin->w_arg_idx = eap->line1;
2311 }
2312 }
2313 else if (*eap->arg == NUL)
2314 EMSG(_(e_argreq));
2315 else
2316 do_arglist(eap->arg, AL_DEL, 0);
2317#ifdef FEAT_TITLE
2318 maketitle();
2319#endif
2320}
2321
2322/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002323 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324 */
2325 void
2326ex_listdo(eap)
2327 exarg_T *eap;
2328{
2329 int i;
2330#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002331 win_T *wp;
2332 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333#endif
2334 buf_T *buf;
2335 int next_fnum = 0;
2336#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2337 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002338#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002339 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340
2341#ifndef FEAT_WINDOWS
2342 if (eap->cmdidx == CMD_windo)
2343 {
2344 ex_ni(eap);
2345 return;
2346 }
2347#endif
2348
2349#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002350 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002351 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2352 * great speed improvement. */
2353 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354#endif
2355
2356 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002357 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 || P_HID(curbuf)
2359 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2360 {
2361 /* start at the first argument/window/buffer */
2362 i = 0;
2363#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002364 wp = firstwin;
2365 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366#endif
2367 /* set pcmark now */
2368 if (eap->cmdidx == CMD_bufdo)
2369 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2370 else
2371 setpcmark();
2372 listcmd_busy = TRUE; /* avoids setting pcmark below */
2373
2374 while (!got_int)
2375 {
2376 if (eap->cmdidx == CMD_argdo)
2377 {
2378 /* go to argument "i" */
2379 if (i == ARGCOUNT)
2380 break;
2381 /* Don't call do_argfile() when already there, it will try
2382 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002383 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002384 {
2385 /* Clear 'shm' to avoid that the file message overwrites
2386 * any output from the command. */
2387 p_shm_save = vim_strsave(p_shm);
2388 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002390 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2391 vim_free(p_shm_save);
2392 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393 if (curwin->w_arg_idx != i)
2394 break;
2395 ++i;
2396 }
2397#ifdef FEAT_WINDOWS
2398 else if (eap->cmdidx == CMD_windo)
2399 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002400 /* go to window "wp" */
2401 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002403 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002404 if (curwin != wp)
2405 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002406 wp = curwin->w_next;
2407 }
2408 else if (eap->cmdidx == CMD_tabdo)
2409 {
2410 /* go to window "tp" */
2411 if (!valid_tabpage(tp))
2412 break;
2413 goto_tabpage_tp(tp);
2414 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415 }
2416#endif
2417 else if (eap->cmdidx == CMD_bufdo)
2418 {
2419 /* Remember the number of the next listed buffer, in case
2420 * ":bwipe" is used or autocommands do something strange. */
2421 next_fnum = -1;
2422 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2423 if (buf->b_p_bl)
2424 {
2425 next_fnum = buf->b_fnum;
2426 break;
2427 }
2428 }
2429
2430 /* execute the command */
2431 do_cmdline(eap->arg, eap->getline, eap->cookie,
2432 DOCMD_VERBOSE + DOCMD_NOWAIT);
2433
2434 if (eap->cmdidx == CMD_bufdo)
2435 {
2436 /* Done? */
2437 if (next_fnum < 0)
2438 break;
2439 /* Check if the buffer still exists. */
2440 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2441 if (buf->b_fnum == next_fnum)
2442 break;
2443 if (buf == NULL)
2444 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002445
2446 /* Go to the next buffer. Clear 'shm' to avoid that the file
2447 * message overwrites any output from the command. */
2448 p_shm_save = vim_strsave(p_shm);
2449 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002451 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2452 vim_free(p_shm_save);
2453
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454 /* If autocommands took us elsewhere, quit here */
2455 if (curbuf->b_fnum != next_fnum)
2456 break;
2457 }
2458
2459 if (eap->cmdidx == CMD_windo)
2460 {
2461 validate_cursor(); /* cursor may have moved */
2462#ifdef FEAT_SCROLLBIND
2463 /* required when 'scrollbind' has been set */
2464 if (curwin->w_p_scb)
2465 do_check_scrollbind(TRUE);
2466#endif
2467 }
2468 }
2469 listcmd_busy = FALSE;
2470 }
2471
2472#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002473 if (save_ei != NULL)
2474 {
2475 au_event_restore(save_ei);
2476 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2477 curbuf->b_fname, TRUE, curbuf);
2478 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479#endif
2480}
2481
2482/*
2483 * Add files[count] to the arglist of the current window after arg "after".
2484 * The file names in files[count] must have been allocated and are taken over.
2485 * Files[] itself is not taken over.
2486 * Returns index of first added argument. Returns -1 when failed (out of mem).
2487 */
2488 static int
2489alist_add_list(count, files, after)
2490 int count;
2491 char_u **files;
2492 int after; /* where to add: 0 = before first one */
2493{
2494 int i;
2495
2496 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2497 {
2498 if (after < 0)
2499 after = 0;
2500 if (after > ARGCOUNT)
2501 after = ARGCOUNT;
2502 if (after < ARGCOUNT)
2503 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2504 (ARGCOUNT - after) * sizeof(aentry_T));
2505 for (i = 0; i < count; ++i)
2506 {
2507 ARGLIST[after + i].ae_fname = files[i];
2508 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2509 }
2510 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002511 if (curwin->w_arg_idx >= after)
2512 ++curwin->w_arg_idx;
2513 return after;
2514 }
2515
2516 for (i = 0; i < count; ++i)
2517 vim_free(files[i]);
2518 return -1;
2519}
2520
2521#endif /* FEAT_LISTCMDS */
2522
2523#ifdef FEAT_EVAL
2524/*
2525 * ":compiler[!] {name}"
2526 */
2527 void
2528ex_compiler(eap)
2529 exarg_T *eap;
2530{
2531 char_u *buf;
2532 char_u *old_cur_comp = NULL;
2533 char_u *p;
2534
2535 if (*eap->arg == NUL)
2536 {
2537 /* List all compiler scripts. */
2538 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2539 /* ) keep the indenter happy... */
2540 }
2541 else
2542 {
2543 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2544 if (buf != NULL)
2545 {
2546 if (eap->forceit)
2547 {
2548 /* ":compiler! {name}" sets global options */
2549 do_cmdline_cmd((char_u *)
2550 "command -nargs=* CompilerSet set <args>");
2551 }
2552 else
2553 {
2554 /* ":compiler! {name}" sets local options.
2555 * To remain backwards compatible "current_compiler" is always
2556 * used. A user's compiler plugin may set it, the distributed
2557 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002558 * "b:current_compiler" and restore "current_compiler".
2559 * Explicitly prepend "g:" to make it work in a function. */
2560 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002561 if (old_cur_comp != NULL)
2562 old_cur_comp = vim_strsave(old_cur_comp);
2563 do_cmdline_cmd((char_u *)
2564 "command -nargs=* CompilerSet setlocal <args>");
2565 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002566 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002567 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568
2569 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002570 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2572 vim_free(buf);
2573
2574 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2575
2576 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002577 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578 if (p != NULL)
2579 set_internal_string_var((char_u *)"b:current_compiler", p);
2580
2581 /* Restore "current_compiler" for ":compiler {name}". */
2582 if (!eap->forceit)
2583 {
2584 if (old_cur_comp != NULL)
2585 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002586 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587 old_cur_comp);
2588 vim_free(old_cur_comp);
2589 }
2590 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002591 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592 }
2593 }
2594 }
2595}
2596#endif
2597
2598/*
2599 * ":runtime {name}"
2600 */
2601 void
2602ex_runtime(eap)
2603 exarg_T *eap;
2604{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002605 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606}
2607
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002608static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002609
2610 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002611source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002613 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002615 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616}
2617
2618/*
2619 * Source the file "name" from all directories in 'runtimepath'.
2620 * "name" can contain wildcards.
2621 * When "all" is TRUE, source all files, otherwise only the first one.
2622 * return FAIL when no file could be sourced, OK otherwise.
2623 */
2624 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002625source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 char_u *name;
2627 int all;
2628{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002629 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630}
2631
2632/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002633 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2634 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002635 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2636 * used.
2637 * Returns OK when at least one match found, FAIL otherwise.
2638 */
2639 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002640do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641 char_u *name;
2642 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002643 void (*callback)__ARGS((char_u *fname, void *ck));
2644 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645{
2646 char_u *rtp;
2647 char_u *np;
2648 char_u *buf;
2649 char_u *rtp_copy;
2650 char_u *tail;
2651 int num_files;
2652 char_u **files;
2653 int i;
2654 int did_one = FALSE;
2655#ifdef AMIGA
2656 struct Process *proc = (struct Process *)FindTask(0L);
2657 APTR save_winptr = proc->pr_WindowPtr;
2658
2659 /* Avoid a requester here for a volume that doesn't exist. */
2660 proc->pr_WindowPtr = (APTR)-1L;
2661#endif
2662
2663 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2664 * value. */
2665 rtp_copy = vim_strsave(p_rtp);
2666 buf = alloc(MAXPATHL);
2667 if (buf != NULL && rtp_copy != NULL)
2668 {
2669 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002670 {
2671 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002672 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002674 verbose_leave();
2675 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002676
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677 /* Loop over all entries in 'runtimepath'. */
2678 rtp = rtp_copy;
2679 while (*rtp != NUL && (all || !did_one))
2680 {
2681 /* Copy the path from 'runtimepath' to buf[]. */
2682 copy_option_part(&rtp, buf, MAXPATHL, ",");
2683 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2684 {
2685 add_pathsep(buf);
2686 tail = buf + STRLEN(buf);
2687
2688 /* Loop over all patterns in "name" */
2689 np = name;
2690 while (*np != NUL && (all || !did_one))
2691 {
2692 /* Append the pattern from "name" to buf[]. */
2693 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2694 "\t ");
2695
2696 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002697 {
2698 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002699 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002700 verbose_leave();
2701 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702
2703 /* Expand wildcards, invoke the callback for each match. */
2704 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2705 EW_FILE) == OK)
2706 {
2707 for (i = 0; i < num_files; ++i)
2708 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002709 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710 did_one = TRUE;
2711 if (!all)
2712 break;
2713 }
2714 FreeWild(num_files, files);
2715 }
2716 }
2717 }
2718 }
2719 }
2720 vim_free(buf);
2721 vim_free(rtp_copy);
2722 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002723 {
2724 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002725 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002726 verbose_leave();
2727 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002728
2729#ifdef AMIGA
2730 proc->pr_WindowPtr = save_winptr;
2731#endif
2732
2733 return did_one ? OK : FAIL;
2734}
2735
2736#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2737/*
2738 * ":options"
2739 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002740 void
2741ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002742 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743{
2744 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2745}
2746#endif
2747
2748/*
2749 * ":source {fname}"
2750 */
2751 void
2752ex_source(eap)
2753 exarg_T *eap;
2754{
2755#ifdef FEAT_BROWSE
2756 if (cmdmod.browse)
2757 {
2758 char_u *fname = NULL;
2759
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002760 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2762 if (fname != NULL)
2763 {
2764 cmd_source(fname, eap);
2765 vim_free(fname);
2766 }
2767 }
2768 else
2769#endif
2770 cmd_source(eap->arg, eap);
2771}
2772
2773 static void
2774cmd_source(fname, eap)
2775 char_u *fname;
2776 exarg_T *eap;
2777{
2778 if (*fname == NUL)
2779 EMSG(_(e_argreq));
2780
Bram Moolenaar071d4272004-06-13 20:20:40 +00002781 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002782 /* ":source!": read Normal mdoe commands
2783 * Need to execute the commands directly. This is required at least
2784 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785 * - ":g" command busy
2786 * - after ":argdo", ":windo" or ":bufdo"
2787 * - another command follows
2788 * - inside a loop
2789 */
2790 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2791#ifdef FEAT_EVAL
2792 || eap->cstack->cs_idx >= 0
2793#endif
2794 );
2795
2796 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002797 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798 EMSG2(_(e_notopen), fname);
2799}
2800
2801/*
2802 * ":source" and associated commands.
2803 */
2804/*
2805 * Structure used to store info for each sourced file.
2806 * It is shared between do_source() and getsourceline().
2807 * This is required, because it needs to be handed to do_cmdline() and
2808 * sourcing can be done recursively.
2809 */
2810struct source_cookie
2811{
2812 FILE *fp; /* opened file for sourcing */
2813 char_u *nextline; /* if not NULL: line that was read ahead */
2814 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002815#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002816 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2817 int error; /* TRUE if LF found after CR-LF */
2818#endif
2819#ifdef FEAT_EVAL
2820 linenr_T breakpoint; /* next line with breakpoint or zero */
2821 char_u *fname; /* name of sourced file */
2822 int dbg_tick; /* debug_tick when breakpoint was set */
2823 int level; /* top nesting level of sourced file */
2824#endif
2825#ifdef FEAT_MBYTE
2826 vimconv_T conv; /* type of conversion */
2827#endif
2828};
2829
2830#ifdef FEAT_EVAL
2831/*
2832 * Return the address holding the next breakpoint line for a source cookie.
2833 */
2834 linenr_T *
2835source_breakpoint(cookie)
2836 void *cookie;
2837{
2838 return &((struct source_cookie *)cookie)->breakpoint;
2839}
2840
2841/*
2842 * Return the address holding the debug tick for a source cookie.
2843 */
2844 int *
2845source_dbg_tick(cookie)
2846 void *cookie;
2847{
2848 return &((struct source_cookie *)cookie)->dbg_tick;
2849}
2850
2851/*
2852 * Return the nesting level for a source cookie.
2853 */
2854 int
2855source_level(cookie)
2856 void *cookie;
2857{
2858 return ((struct source_cookie *)cookie)->level;
2859}
2860#endif
2861
2862static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2863
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002864#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2865# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002866static FILE *fopen_noinh_readbin __ARGS((char *filename));
2867
2868/*
2869 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002870 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871 */
2872 static FILE *
2873fopen_noinh_readbin(filename)
2874 char *filename;
2875{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002876# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002877 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2878# else
2879 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002880# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881
2882 if (fd_tmp == -1)
2883 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002884
2885# ifdef HAVE_FD_CLOEXEC
2886 {
2887 int fdflags = fcntl(fd_tmp, F_GETFD);
2888 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
2889 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
2890 }
2891# endif
2892
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893 return fdopen(fd_tmp, READBIN);
2894}
2895#endif
2896
2897
2898/*
2899 * do_source: Read the file "fname" and execute its lines as EX commands.
2900 *
2901 * This function may be called recursively!
2902 *
2903 * return FAIL if file could not be opened, OK otherwise
2904 */
2905 int
2906do_source(fname, check_other, is_vimrc)
2907 char_u *fname;
2908 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002909 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910{
2911 struct source_cookie cookie;
2912 char_u *save_sourcing_name;
2913 linenr_T save_sourcing_lnum;
2914 char_u *p;
2915 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002916 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917 int retval = FAIL;
2918#ifdef FEAT_EVAL
2919 scid_T save_current_SID;
2920 static scid_T last_current_SID = 0;
2921 void *save_funccalp;
2922 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002923 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924# ifdef UNIX
2925 struct stat st;
2926 int stat_ok;
2927# endif
2928#endif
2929#ifdef STARTUPTIME
2930 struct timeval tv_rel;
2931 struct timeval tv_start;
2932#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002933#ifdef FEAT_PROFILE
2934 proftime_T wait_start;
2935#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 if (p == NULL)
2939 return retval;
2940 fname_exp = fix_fname(p);
2941 vim_free(p);
2942 if (fname_exp == NULL)
2943 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002944 if (mch_isdir(fname_exp))
2945 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002946 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947 goto theend;
2948 }
2949
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002950#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002951 /* Apply SourceCmd autocommands, they should get the file and source it. */
2952 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2953 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2954 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002955 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002956# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002957 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002958# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002959 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002960# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002961 goto theend;
2962 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002963
2964 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002965 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2966#endif
2967
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002968#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002969 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2970#else
2971 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2972#endif
2973 if (cookie.fp == NULL && check_other)
2974 {
2975 /*
2976 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2977 * and ".exrc" by "_exrc" or vice versa.
2978 */
2979 p = gettail(fname_exp);
2980 if ((*p == '.' || *p == '_')
2981 && (STRICMP(p + 1, "vimrc") == 0
2982 || STRICMP(p + 1, "gvimrc") == 0
2983 || STRICMP(p + 1, "exrc") == 0))
2984 {
2985 if (*p == '_')
2986 *p = '.';
2987 else
2988 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002989#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2991#else
2992 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2993#endif
2994 }
2995 }
2996
2997 if (cookie.fp == NULL)
2998 {
2999 if (p_verbose > 0)
3000 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003001 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003002 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003003 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 else
3005 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003006 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003007 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008 }
3009 goto theend;
3010 }
3011
3012 /*
3013 * The file exists.
3014 * - In verbose mode, give a message.
3015 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3016 */
3017 if (p_verbose > 1)
3018 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003019 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003021 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022 else
3023 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003024 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003025 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003026 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003027 if (is_vimrc == DOSO_VIMRC)
3028 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3029 else if (is_vimrc == DOSO_GVIMRC)
3030 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031
3032#ifdef USE_CRNL
3033 /* If no automatic file format: Set default to CR-NL. */
3034 if (*p_ffs == NUL)
3035 cookie.fileformat = EOL_DOS;
3036 else
3037 cookie.fileformat = EOL_UNKNOWN;
3038 cookie.error = FALSE;
3039#endif
3040
3041#ifdef USE_CR
3042 /* If no automatic file format: Set default to CR. */
3043 if (*p_ffs == NUL)
3044 cookie.fileformat = EOL_MAC;
3045 else
3046 cookie.fileformat = EOL_UNKNOWN;
3047 cookie.error = FALSE;
3048#endif
3049
3050 cookie.nextline = NULL;
3051 cookie.finished = FALSE;
3052
3053#ifdef FEAT_EVAL
3054 /*
3055 * Check if this script has a breakpoint.
3056 */
3057 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3058 cookie.fname = fname_exp;
3059 cookie.dbg_tick = debug_tick;
3060
3061 cookie.level = ex_nesting_level;
3062#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003063
3064 /*
3065 * Keep the sourcing name/lnum, for recursive calls.
3066 */
3067 save_sourcing_name = sourcing_name;
3068 sourcing_name = fname_exp;
3069 save_sourcing_lnum = sourcing_lnum;
3070 sourcing_lnum = 0;
3071
Bram Moolenaar73881402009-02-04 16:50:47 +00003072#ifdef FEAT_MBYTE
3073 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3074
3075 /* Read the first line so we can check for a UTF-8 BOM. */
3076 firstline = getsourceline(0, (void *)&cookie, 0);
3077 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3078 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3079 {
3080 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3081 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3082 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003083 if (p == NULL)
3084 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003085 if (p != NULL)
3086 {
3087 vim_free(firstline);
3088 firstline = p;
3089 }
3090 }
3091#endif
3092
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003094 if (time_fd != NULL)
3095 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003096#endif
3097
3098#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003099# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003100 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003101 prof_child_enter(&wait_start); /* entering a child now */
3102# endif
3103
3104 /* Don't use local function variables, if called from a function.
3105 * Also starts profiling timer for nested script. */
3106 save_funccalp = save_funccal();
3107
Bram Moolenaar071d4272004-06-13 20:20:40 +00003108 /*
3109 * Check if this script was sourced before to finds its SID.
3110 * If it's new, generate a new SID.
3111 */
3112 save_current_SID = current_SID;
3113# ifdef UNIX
3114 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3115# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003116 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3117 {
3118 si = &SCRIPT_ITEM(current_SID);
3119 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003120 && (
3121# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003122 /* Compare dev/ino when possible, it catches symbolic
3123 * links. Also compare file names, the inode may change
3124 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003125 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003126 && (si->sn_dev == st.st_dev
3127 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003129 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003131 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 if (current_SID == 0)
3133 {
3134 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003135 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3136 == FAIL)
3137 goto almosttheend;
3138 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003140 ++script_items.ga_len;
3141 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3142# ifdef FEAT_PROFILE
3143 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003146 si = &SCRIPT_ITEM(current_SID);
3147 si->sn_name = fname_exp;
3148 fname_exp = NULL;
3149# ifdef UNIX
3150 if (stat_ok)
3151 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003152 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003153 si->sn_dev = st.st_dev;
3154 si->sn_ino = st.st_ino;
3155 }
3156 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003157 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003158# endif
3159
Bram Moolenaar071d4272004-06-13 20:20:40 +00003160 /* Allocate the local script variables to use for this script. */
3161 new_script_vars(current_SID);
3162 }
3163
Bram Moolenaar05159a02005-02-26 23:04:13 +00003164# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003165 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003166 {
3167 int forceit;
3168
3169 /* Check if we do profiling for this script. */
3170 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3171 {
3172 script_do_profile(si);
3173 si->sn_pr_force = forceit;
3174 }
3175 if (si->sn_prof_on)
3176 {
3177 ++si->sn_pr_count;
3178 profile_start(&si->sn_pr_start);
3179 profile_zero(&si->sn_pr_children);
3180 }
3181 }
3182# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003183#endif
3184
3185 /*
3186 * Call do_cmdline, which will call getsourceline() to get the lines.
3187 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003188 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003190 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003191
3192#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003193 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003194 {
3195 /* Get "si" again, "script_items" may have been reallocated. */
3196 si = &SCRIPT_ITEM(current_SID);
3197 if (si->sn_prof_on)
3198 {
3199 profile_end(&si->sn_pr_start);
3200 profile_sub_wait(&wait_start, &si->sn_pr_start);
3201 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003202 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3203 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003204 }
3205 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003206#endif
3207
3208 if (got_int)
3209 EMSG(_(e_interr));
3210 sourcing_name = save_sourcing_name;
3211 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 if (p_verbose > 1)
3213 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003214 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003215 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003217 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003218 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003219 }
3220#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003221 if (time_fd != NULL)
3222 {
3223 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3224 time_msg((char *)IObuff, &tv_start);
3225 time_pop(&tv_rel);
3226 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227#endif
3228
3229#ifdef FEAT_EVAL
3230 /*
3231 * After a "finish" in debug mode, need to break at first command of next
3232 * sourced file.
3233 */
3234 if (save_debug_break_level > ex_nesting_level
3235 && debug_break_level == ex_nesting_level)
3236 ++debug_break_level;
3237#endif
3238
Bram Moolenaar05159a02005-02-26 23:04:13 +00003239#ifdef FEAT_EVAL
3240almosttheend:
3241 current_SID = save_current_SID;
3242 restore_funccal(save_funccalp);
3243# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003244 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003245 prof_child_exit(&wait_start); /* leaving a child now */
3246# endif
3247#endif
3248 fclose(cookie.fp);
3249 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003250 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003251#ifdef FEAT_MBYTE
3252 convert_setup(&cookie.conv, NULL, NULL);
3253#endif
3254
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255theend:
3256 vim_free(fname_exp);
3257 return retval;
3258}
3259
3260#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003261
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262/*
3263 * ":scriptnames"
3264 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 void
3266ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003267 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268{
3269 int i;
3270
Bram Moolenaar05159a02005-02-26 23:04:13 +00003271 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3272 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003273 {
3274 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3275 NameBuff, MAXPATHL, TRUE);
3276 smsg((char_u *)"%3d: %s", i, NameBuff);
3277 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278}
3279
3280# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3281/*
3282 * Fix slashes in the list of script names for 'shellslash'.
3283 */
3284 void
3285scriptnames_slash_adjust()
3286{
3287 int i;
3288
Bram Moolenaar05159a02005-02-26 23:04:13 +00003289 for (i = 1; i <= script_items.ga_len; ++i)
3290 if (SCRIPT_ITEM(i).sn_name != NULL)
3291 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292}
3293# endif
3294
3295/*
3296 * Get a pointer to a script name. Used for ":verbose set".
3297 */
3298 char_u *
3299get_scriptname(id)
3300 scid_T id;
3301{
3302 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003303 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003304 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003305 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003307 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003308 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003309 return (char_u *)_("environment variable");
3310 if (id == SID_ERROR)
3311 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003312 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003314
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003315# if defined(EXITFREE) || defined(PROTO)
3316 void
3317free_scriptnames()
3318{
3319 int i;
3320
3321 for (i = script_items.ga_len; i > 0; --i)
3322 vim_free(SCRIPT_ITEM(i).sn_name);
3323 ga_clear(&script_items);
3324}
3325# endif
3326
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327#endif
3328
3329#if defined(USE_CR) || defined(PROTO)
3330
3331# if defined(__MSL__) && (__MSL__ >= 22)
3332/*
3333 * Newer version of the Metrowerks library handle DOS and UNIX files
3334 * without help.
3335 * Test with earlier versions, MSL 2.2 is the library supplied with
3336 * Codewarrior Pro 2.
3337 */
3338 char *
3339fgets_cr(s, n, stream)
3340 char *s;
3341 int n;
3342 FILE *stream;
3343{
3344 return fgets(s, n, stream);
3345}
3346# else
3347/*
3348 * Version of fgets() which also works for lines ending in a <CR> only
3349 * (Macintosh format).
3350 * For older versions of the Metrowerks library.
3351 * At least CodeWarrior 9 needed this code.
3352 */
3353 char *
3354fgets_cr(s, n, stream)
3355 char *s;
3356 int n;
3357 FILE *stream;
3358{
3359 int c = 0;
3360 int char_read = 0;
3361
3362 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3363 {
3364 c = fgetc(stream);
3365 s[char_read++] = c;
3366 /* If the file is in DOS format, we need to skip a NL after a CR. I
3367 * thought it was the other way around, but this appears to work... */
3368 if (c == '\n')
3369 {
3370 c = fgetc(stream);
3371 if (c != '\r')
3372 ungetc(c, stream);
3373 }
3374 }
3375
3376 s[char_read] = 0;
3377 if (char_read == 0)
3378 return NULL;
3379
3380 if (feof(stream) && char_read == 1)
3381 return NULL;
3382
3383 return s;
3384}
3385# endif
3386#endif
3387
3388/*
3389 * Get one full line from a sourced file.
3390 * Called by do_cmdline() when it's called from do_source().
3391 *
3392 * Return a pointer to the line in allocated memory.
3393 * Return NULL for end-of-file or some error.
3394 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395 char_u *
3396getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003397 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003398 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003399 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003400{
3401 struct source_cookie *sp = (struct source_cookie *)cookie;
3402 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003403 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003404
3405#ifdef FEAT_EVAL
3406 /* If breakpoints have been added/deleted need to check for it. */
3407 if (sp->dbg_tick < debug_tick)
3408 {
3409 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3410 sp->dbg_tick = debug_tick;
3411 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003412# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003413 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003414 script_line_end();
3415# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003416#endif
3417 /*
3418 * Get current line. If there is a read-ahead line, use it, otherwise get
3419 * one now.
3420 */
3421 if (sp->finished)
3422 line = NULL;
3423 else if (sp->nextline == NULL)
3424 line = get_one_sourceline(sp);
3425 else
3426 {
3427 line = sp->nextline;
3428 sp->nextline = NULL;
3429 ++sourcing_lnum;
3430 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003431#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003432 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003433 script_line_start();
3434#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003435
3436 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3437 * contain the 'C' flag. */
3438 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3439 {
3440 /* compensate for the one line read-ahead */
3441 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003442
3443 /* Get the next line and concatenate it when it starts with a
3444 * backslash. We always need to read the next line, keep it in
3445 * sp->nextline. */
3446 sp->nextline = get_one_sourceline(sp);
3447 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003449 garray_T ga;
3450
3451 ga_init2(&ga, (int)sizeof(char_u), 200);
3452 ga_concat(&ga, line);
3453 ga_concat(&ga, p + 1);
3454 for (;;)
3455 {
3456 vim_free(sp->nextline);
3457 sp->nextline = get_one_sourceline(sp);
3458 if (sp->nextline == NULL)
3459 break;
3460 p = skipwhite(sp->nextline);
3461 if (*p != '\\')
3462 break;
3463 ga_concat(&ga, p + 1);
3464 }
3465 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003467 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468 }
3469 }
3470
3471#ifdef FEAT_MBYTE
3472 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3473 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003474 char_u *s;
3475
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476 /* Convert the encoding of the script line. */
3477 s = string_convert(&sp->conv, line, NULL);
3478 if (s != NULL)
3479 {
3480 vim_free(line);
3481 line = s;
3482 }
3483 }
3484#endif
3485
3486#ifdef FEAT_EVAL
3487 /* Did we encounter a breakpoint? */
3488 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3489 {
3490 dbg_breakpoint(sp->fname, sourcing_lnum);
3491 /* Find next breakpoint. */
3492 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3493 sp->dbg_tick = debug_tick;
3494 }
3495#endif
3496
3497 return line;
3498}
3499
3500 static char_u *
3501get_one_sourceline(sp)
3502 struct source_cookie *sp;
3503{
3504 garray_T ga;
3505 int len;
3506 int c;
3507 char_u *buf;
3508#ifdef USE_CRNL
3509 int has_cr; /* CR-LF found */
3510#endif
3511#ifdef USE_CR
3512 char_u *scan;
3513#endif
3514 int have_read = FALSE;
3515
3516 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003517 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518
3519 /*
3520 * Loop until there is a finished line (or end-of-file).
3521 */
3522 sourcing_lnum++;
3523 for (;;)
3524 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003525 /* make room to read at least 120 (more) characters */
3526 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527 break;
3528 buf = (char_u *)ga.ga_data;
3529
3530#ifdef USE_CR
3531 if (sp->fileformat == EOL_MAC)
3532 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003533 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3534 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003535 break;
3536 }
3537 else
3538#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003539 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3540 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003542 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003543#ifdef USE_CRNL
3544 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3545 * CTRL-Z by its own, or after a NL. */
3546 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3547 && sp->fileformat == EOL_DOS
3548 && buf[len - 1] == Ctrl_Z)
3549 {
3550 buf[len - 1] = NUL;
3551 break;
3552 }
3553#endif
3554
3555#ifdef USE_CR
3556 /* If the read doesn't stop on a new line, and there's
3557 * some CR then we assume a Mac format */
3558 if (sp->fileformat == EOL_UNKNOWN)
3559 {
3560 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3561 sp->fileformat = EOL_MAC;
3562 else
3563 sp->fileformat = EOL_UNIX;
3564 }
3565
3566 if (sp->fileformat == EOL_MAC)
3567 {
3568 scan = vim_strchr(buf, '\r');
3569
3570 if (scan != NULL)
3571 {
3572 *scan = '\n';
3573 if (*(scan + 1) != 0)
3574 {
3575 *(scan + 1) = 0;
3576 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3577 }
3578 }
3579 len = STRLEN(buf);
3580 }
3581#endif
3582
3583 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584 ga.ga_len = len;
3585
3586 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003587 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588 continue;
3589
3590 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3591 {
3592#ifdef USE_CRNL
3593 has_cr = (len >= 2 && buf[len - 2] == '\r');
3594 if (sp->fileformat == EOL_UNKNOWN)
3595 {
3596 if (has_cr)
3597 sp->fileformat = EOL_DOS;
3598 else
3599 sp->fileformat = EOL_UNIX;
3600 }
3601
3602 if (sp->fileformat == EOL_DOS)
3603 {
3604 if (has_cr) /* replace trailing CR */
3605 {
3606 buf[len - 2] = '\n';
3607 --len;
3608 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003609 }
3610 else /* lines like ":map xx yy^M" will have failed */
3611 {
3612 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003613 {
3614 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003615 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003616 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617 sp->error = TRUE;
3618 sp->fileformat = EOL_UNIX;
3619 }
3620 }
3621#endif
3622 /* The '\n' is escaped if there is an odd number of ^V's just
3623 * before it, first set "c" just before the 'V's and then check
3624 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3625 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3626 ;
3627 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3628 {
3629 sourcing_lnum++;
3630 continue;
3631 }
3632
3633 buf[len - 1] = NUL; /* remove the NL */
3634 }
3635
3636 /*
3637 * Check for ^C here now and then, so recursive :so can be broken.
3638 */
3639 line_breakcheck();
3640 break;
3641 }
3642
3643 if (have_read)
3644 return (char_u *)ga.ga_data;
3645
3646 vim_free(ga.ga_data);
3647 return NULL;
3648}
3649
Bram Moolenaar05159a02005-02-26 23:04:13 +00003650#if defined(FEAT_PROFILE) || defined(PROTO)
3651/*
3652 * Called when starting to read a script line.
3653 * "sourcing_lnum" must be correct!
3654 * When skipping lines it may not actually be executed, but we won't find out
3655 * until later and we need to store the time now.
3656 */
3657 void
3658script_line_start()
3659{
3660 scriptitem_T *si;
3661 sn_prl_T *pp;
3662
3663 if (current_SID <= 0 || current_SID > script_items.ga_len)
3664 return;
3665 si = &SCRIPT_ITEM(current_SID);
3666 if (si->sn_prof_on && sourcing_lnum >= 1)
3667 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003668 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003669 * here isn't counted. */
3670 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3671 si->sn_prl_idx = sourcing_lnum - 1;
3672 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3673 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3674 {
3675 /* Zero counters for a line that was not used before. */
3676 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3677 pp->snp_count = 0;
3678 profile_zero(&pp->sn_prl_total);
3679 profile_zero(&pp->sn_prl_self);
3680 ++si->sn_prl_ga.ga_len;
3681 }
3682 si->sn_prl_execed = FALSE;
3683 profile_start(&si->sn_prl_start);
3684 profile_zero(&si->sn_prl_children);
3685 profile_get_wait(&si->sn_prl_wait);
3686 }
3687}
3688
3689/*
3690 * Called when actually executing a function line.
3691 */
3692 void
3693script_line_exec()
3694{
3695 scriptitem_T *si;
3696
3697 if (current_SID <= 0 || current_SID > script_items.ga_len)
3698 return;
3699 si = &SCRIPT_ITEM(current_SID);
3700 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3701 si->sn_prl_execed = TRUE;
3702}
3703
3704/*
3705 * Called when done with a function line.
3706 */
3707 void
3708script_line_end()
3709{
3710 scriptitem_T *si;
3711 sn_prl_T *pp;
3712
3713 if (current_SID <= 0 || current_SID > script_items.ga_len)
3714 return;
3715 si = &SCRIPT_ITEM(current_SID);
3716 if (si->sn_prof_on && si->sn_prl_idx >= 0
3717 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3718 {
3719 if (si->sn_prl_execed)
3720 {
3721 pp = &PRL_ITEM(si, si->sn_prl_idx);
3722 ++pp->snp_count;
3723 profile_end(&si->sn_prl_start);
3724 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003725 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003726 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3727 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003728 }
3729 si->sn_prl_idx = -1;
3730 }
3731}
3732#endif
3733
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734/*
3735 * ":scriptencoding": Set encoding conversion for a sourced script.
3736 * Without the multi-byte feature it's simply ignored.
3737 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003738 void
3739ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003740 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741{
3742#ifdef FEAT_MBYTE
3743 struct source_cookie *sp;
3744 char_u *name;
3745
3746 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3747 {
3748 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3749 return;
3750 }
3751
3752 if (*eap->arg != NUL)
3753 {
3754 name = enc_canonize(eap->arg);
3755 if (name == NULL) /* out of memory */
3756 return;
3757 }
3758 else
3759 name = eap->arg;
3760
3761 /* Setup for conversion from the specified encoding to 'encoding'. */
3762 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3763 convert_setup(&sp->conv, name, p_enc);
3764
3765 if (name != eap->arg)
3766 vim_free(name);
3767#endif
3768}
3769
3770#if defined(FEAT_EVAL) || defined(PROTO)
3771/*
3772 * ":finish": Mark a sourced file as finished.
3773 */
3774 void
3775ex_finish(eap)
3776 exarg_T *eap;
3777{
3778 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3779 do_finish(eap, FALSE);
3780 else
3781 EMSG(_("E168: :finish used outside of a sourced file"));
3782}
3783
3784/*
3785 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3786 * Also called for a pending finish at the ":endtry" or after returning from
3787 * an extra do_cmdline(). "reanimate" is used in the latter case.
3788 */
3789 void
3790do_finish(eap, reanimate)
3791 exarg_T *eap;
3792 int reanimate;
3793{
3794 int idx;
3795
3796 if (reanimate)
3797 ((struct source_cookie *)getline_cookie(eap->getline,
3798 eap->cookie))->finished = FALSE;
3799
3800 /*
3801 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3802 * not in its finally clause (which then is to be executed next) is found.
3803 * In this case, make the ":finish" pending for execution at the ":endtry".
3804 * Otherwise, finish normally.
3805 */
3806 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3807 if (idx >= 0)
3808 {
3809 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3810 report_make_pending(CSTP_FINISH, NULL);
3811 }
3812 else
3813 ((struct source_cookie *)getline_cookie(eap->getline,
3814 eap->cookie))->finished = TRUE;
3815}
3816
3817
3818/*
3819 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3820 * message for missing ":endif".
3821 * Return FALSE when not sourcing a file.
3822 */
3823 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003824source_finished(fgetline, cookie)
3825 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826 void *cookie;
3827{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003828 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003830 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003831}
3832#endif
3833
3834#if defined(FEAT_LISTCMDS) || defined(PROTO)
3835/*
3836 * ":checktime [buffer]"
3837 */
3838 void
3839ex_checktime(eap)
3840 exarg_T *eap;
3841{
3842 buf_T *buf;
3843 int save_no_check_timestamps = no_check_timestamps;
3844
3845 no_check_timestamps = 0;
3846 if (eap->addr_count == 0) /* default is all buffers */
3847 check_timestamps(FALSE);
3848 else
3849 {
3850 buf = buflist_findnr((int)eap->line2);
3851 if (buf != NULL) /* cannot happen? */
3852 (void)buf_check_timestamp(buf, FALSE);
3853 }
3854 no_check_timestamps = save_no_check_timestamps;
3855}
3856#endif
3857
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3859 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003860# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003861static char *get_locale_val __ARGS((int what));
3862
3863 static char *
3864get_locale_val(what)
3865 int what;
3866{
3867 char *loc;
3868
3869 /* Obtain the locale value from the libraries. For DJGPP this is
3870 * redefined and it doesn't use the arguments. */
3871 loc = setlocale(what, NULL);
3872
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003873# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 if (loc != NULL)
3875 {
3876 char_u *p;
3877
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003878 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3879 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003880 p = vim_strchr(loc, '=');
3881 if (p != NULL)
3882 {
3883 loc = ++p;
3884 while (*p != NUL) /* remove trailing newline */
3885 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003886 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003887 {
3888 *p = NUL;
3889 break;
3890 }
3891 ++p;
3892 }
3893 }
3894 }
3895# endif
3896
3897 return loc;
3898}
3899#endif
3900
3901
3902#ifdef WIN32
3903/*
3904 * On MS-Windows locale names are strings like "German_Germany.1252", but
3905 * gettext expects "de". Try to translate one into another here for a few
3906 * supported languages.
3907 */
3908 static char_u *
3909gettext_lang(char_u *name)
3910{
3911 int i;
3912 static char *(mtable[]) = {
3913 "afrikaans", "af",
3914 "czech", "cs",
3915 "dutch", "nl",
3916 "german", "de",
3917 "english_united kingdom", "en_GB",
3918 "spanish", "es",
3919 "french", "fr",
3920 "italian", "it",
3921 "japanese", "ja",
3922 "korean", "ko",
3923 "norwegian", "no",
3924 "polish", "pl",
3925 "russian", "ru",
3926 "slovak", "sk",
3927 "swedish", "sv",
3928 "ukrainian", "uk",
3929 "chinese_china", "zh_CN",
3930 "chinese_taiwan", "zh_TW",
3931 NULL};
3932
3933 for (i = 0; mtable[i] != NULL; i += 2)
3934 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3935 return mtable[i + 1];
3936 return name;
3937}
3938#endif
3939
3940#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3941/*
3942 * Obtain the current messages language. Used to set the default for
3943 * 'helplang'. May return NULL or an empty string.
3944 */
3945 char_u *
3946get_mess_lang()
3947{
3948 char_u *p;
3949
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003950# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003951# if defined(LC_MESSAGES)
3952 p = (char_u *)get_locale_val(LC_MESSAGES);
3953# else
3954 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003955 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3956 * and LC_MONETARY may be set differently for a Japanese working in the
3957 * US. */
3958 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003959# endif
3960# else
3961 p = mch_getenv((char_u *)"LC_ALL");
3962 if (p == NULL || *p == NUL)
3963 {
3964 p = mch_getenv((char_u *)"LC_MESSAGES");
3965 if (p == NULL || *p == NUL)
3966 p = mch_getenv((char_u *)"LANG");
3967 }
3968# endif
3969# ifdef WIN32
3970 p = gettext_lang(p);
3971# endif
3972 return p;
3973}
3974#endif
3975
Bram Moolenaardef9e822004-12-31 20:58:58 +00003976/* Complicated #if; matches with where get_mess_env() is used below. */
3977#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3978 && defined(LC_MESSAGES))) \
3979 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3980 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3981 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003982static char_u *get_mess_env __ARGS((void));
3983
3984/*
3985 * Get the language used for messages from the environment.
3986 */
3987 static char_u *
3988get_mess_env()
3989{
3990 char_u *p;
3991
3992 p = mch_getenv((char_u *)"LC_ALL");
3993 if (p == NULL || *p == NUL)
3994 {
3995 p = mch_getenv((char_u *)"LC_MESSAGES");
3996 if (p == NULL || *p == NUL)
3997 {
3998 p = mch_getenv((char_u *)"LANG");
3999 if (p != NULL && VIM_ISDIGIT(*p))
4000 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004001# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002 if (p == NULL || *p == NUL)
4003 p = (char_u *)get_locale_val(LC_CTYPE);
4004# endif
4005 }
4006 }
4007 return p;
4008}
4009#endif
4010
4011#if defined(FEAT_EVAL) || defined(PROTO)
4012
4013/*
4014 * Set the "v:lang" variable according to the current locale setting.
4015 * Also do "v:lc_time"and "v:ctype".
4016 */
4017 void
4018set_lang_var()
4019{
4020 char_u *loc;
4021
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004022# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023 loc = (char_u *)get_locale_val(LC_CTYPE);
4024# else
4025 /* setlocale() not supported: use the default value */
4026 loc = (char_u *)"C";
4027# endif
4028 set_vim_var_string(VV_CTYPE, loc, -1);
4029
4030 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4031 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004032# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033 loc = (char_u *)get_locale_val(LC_MESSAGES);
4034# else
4035 loc = get_mess_env();
4036# endif
4037 set_vim_var_string(VV_LANG, loc, -1);
4038
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004039# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040 loc = (char_u *)get_locale_val(LC_TIME);
4041# endif
4042 set_vim_var_string(VV_LC_TIME, loc, -1);
4043}
4044#endif
4045
4046#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4047 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4048/*
4049 * ":language": Set the language (locale).
4050 */
4051 void
4052ex_language(eap)
4053 exarg_T *eap;
4054{
4055 char *loc;
4056 char_u *p;
4057 char_u *name;
4058 int what = LC_ALL;
4059 char *whatstr = "";
4060#ifdef LC_MESSAGES
4061# define VIM_LC_MESSAGES LC_MESSAGES
4062#else
4063# define VIM_LC_MESSAGES 6789
4064#endif
4065
4066 name = eap->arg;
4067
4068 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4069 * Allow abbreviation, but require at least 3 characters to avoid
4070 * confusion with a two letter language name "me" or "ct". */
4071 p = skiptowhite(eap->arg);
4072 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4073 {
4074 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4075 {
4076 what = VIM_LC_MESSAGES;
4077 name = skipwhite(p);
4078 whatstr = "messages ";
4079 }
4080 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4081 {
4082 what = LC_CTYPE;
4083 name = skipwhite(p);
4084 whatstr = "ctype ";
4085 }
4086 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4087 {
4088 what = LC_TIME;
4089 name = skipwhite(p);
4090 whatstr = "time ";
4091 }
4092 }
4093
4094 if (*name == NUL)
4095 {
4096#ifndef LC_MESSAGES
4097 if (what == VIM_LC_MESSAGES)
4098 p = get_mess_env();
4099 else
4100#endif
4101 p = (char_u *)setlocale(what, NULL);
4102 if (p == NULL || *p == NUL)
4103 p = (char_u *)"Unknown";
4104 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4105 }
4106 else
4107 {
4108#ifndef LC_MESSAGES
4109 if (what == VIM_LC_MESSAGES)
4110 loc = "";
4111 else
4112#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004113 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004115#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4116 /* Make sure strtod() uses a decimal point, not a comma. */
4117 setlocale(LC_NUMERIC, "C");
4118#endif
4119 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004120 if (loc == NULL)
4121 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4122 else
4123 {
4124#ifdef HAVE_NL_MSG_CAT_CNTR
4125 /* Need to do this for GNU gettext, otherwise cached translations
4126 * will be used again. */
4127 extern int _nl_msg_cat_cntr;
4128
4129 ++_nl_msg_cat_cntr;
4130#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004131 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004132 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4133
4134 if (what != LC_TIME)
4135 {
4136 /* Tell gettext() what to translate to. It apparently doesn't
4137 * use the currently effective locale. Also do this when
4138 * FEAT_GETTEXT isn't defined, so that shell commands use this
4139 * value. */
4140 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004141 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004143# ifdef WIN32
4144 /* Apparently MS-Windows printf() may cause a crash when
4145 * we give it 8-bit text while it's expecting text in the
4146 * current locale. This call avoids that. */
4147 setlocale(LC_CTYPE, "C");
4148# endif
4149 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150 if (what != LC_CTYPE)
4151 {
4152 char_u *mname;
4153#ifdef WIN32
4154 mname = gettext_lang(name);
4155#else
4156 mname = name;
4157#endif
4158 vim_setenv((char_u *)"LC_MESSAGES", mname);
4159#ifdef FEAT_MULTI_LANG
4160 set_helplang_default(mname);
4161#endif
4162 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163 }
4164
4165# ifdef FEAT_EVAL
4166 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4167 set_lang_var();
4168# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004169# ifdef FEAT_TITLE
4170 maketitle();
4171# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172 }
4173 }
4174}
4175
4176# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004177
4178static char_u **locales = NULL; /* Array of all available locales */
4179static int did_init_locales = FALSE;
4180
4181static void init_locales __ARGS((void));
4182static char_u **find_locales __ARGS((void));
4183
4184/*
4185 * Lazy initialization of all available locales.
4186 */
4187 static void
4188init_locales()
4189{
4190 if (!did_init_locales)
4191 {
4192 did_init_locales = TRUE;
4193 locales = find_locales();
4194 }
4195}
4196
4197/* Return an array of strings for all available locales + NULL for the
4198 * last element. Return NULL in case of error. */
4199 static char_u **
4200find_locales()
4201{
4202 garray_T locales_ga;
4203 char_u *loc;
4204
4205 /* Find all available locales by running command "locale -a". If this
4206 * doesn't work we won't have completion. */
4207 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
4208 NULL, SHELL_SILENT);
4209 if (locale_a == NULL)
4210 return NULL;
4211 ga_init2(&locales_ga, sizeof(char_u *), 20);
4212
4213 /* Transform locale_a string where each locale is separated by "\n"
4214 * into an array of locale strings. */
4215 loc = (char_u *)strtok((char *)locale_a, "\n");
4216
4217 while (loc != NULL)
4218 {
4219 if (ga_grow(&locales_ga, 1) == FAIL)
4220 break;
4221 loc = vim_strsave(loc);
4222 if (loc == NULL)
4223 break;
4224
4225 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4226 loc = (char_u *)strtok(NULL, "\n");
4227 }
4228 vim_free(locale_a);
4229 if (ga_grow(&locales_ga, 1) == FAIL)
4230 {
4231 ga_clear(&locales_ga);
4232 return NULL;
4233 }
4234 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4235 return (char_u **)locales_ga.ga_data;
4236}
4237
4238# if defined(EXITFREE) || defined(PROTO)
4239 void
4240free_locales()
4241{
4242 int i;
4243 if (locales != NULL)
4244 {
4245 for (i = 0; locales[i] != NULL; i++)
4246 vim_free(locales[i]);
4247 vim_free(locales);
4248 locales = NULL;
4249 }
4250}
4251# endif
4252
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253/*
4254 * Function given to ExpandGeneric() to obtain the possible arguments of the
4255 * ":language" command.
4256 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257 char_u *
4258get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004259 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004260 int idx;
4261{
4262 if (idx == 0)
4263 return (char_u *)"messages";
4264 if (idx == 1)
4265 return (char_u *)"ctype";
4266 if (idx == 2)
4267 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004268
4269 init_locales();
4270 if (locales == NULL)
4271 return NULL;
4272 return locales[idx - 3];
4273}
4274
4275/*
4276 * Function given to ExpandGeneric() to obtain the available locales.
4277 */
4278 char_u *
4279get_locales(xp, idx)
4280 expand_T *xp UNUSED;
4281 int idx;
4282{
4283 init_locales();
4284 if (locales == NULL)
4285 return NULL;
4286 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287}
4288# endif
4289
4290#endif