blob: 54e4f07b811677d05e4fb3747b432a937cf76d09 [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". */
503#ifdef RISCOS
504 q = mch_munge_fname(p);
505#else
506 q = expand_env_save(p);
507#endif
508 if (q == NULL)
509 return FAIL;
510#ifdef RISCOS
511 p = mch_munge_fname(q);
512#else
513 p = expand_env_save(q);
514#endif
515 vim_free(q);
516 if (p == NULL)
517 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000518 if (*p != '*')
519 {
520 bp->dbg_name = fix_fname(p);
521 vim_free(p);
522 }
523 else
524 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000525 }
526
527 if (bp->dbg_name == NULL)
528 return FAIL;
529 return OK;
530}
531
532/*
533 * ":breakadd".
534 */
535 void
536ex_breakadd(eap)
537 exarg_T *eap;
538{
539 struct debuggy *bp;
540 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000541 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542
Bram Moolenaar05159a02005-02-26 23:04:13 +0000543 gap = &dbg_breakp;
544#ifdef FEAT_PROFILE
545 if (eap->cmdidx == CMD_profile)
546 gap = &prof_ga;
547#endif
548
549 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000551 bp = &DEBUGGY(gap, gap->ga_len);
552 bp->dbg_forceit = eap->forceit;
553
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
555 if (pat != NULL)
556 {
557 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
558 vim_free(pat);
559 }
560 if (pat == NULL || bp->dbg_prog == NULL)
561 vim_free(bp->dbg_name);
562 else
563 {
564 if (bp->dbg_lnum == 0) /* default line number is 1 */
565 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000566#ifdef FEAT_PROFILE
567 if (eap->cmdidx != CMD_profile)
568#endif
569 {
570 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
571 ++debug_tick;
572 }
573 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574 }
575 }
576}
577
578/*
579 * ":debuggreedy".
580 */
581 void
582ex_debuggreedy(eap)
583 exarg_T *eap;
584{
585 if (eap->addr_count == 0 || eap->line2 != 0)
586 debug_greedy = TRUE;
587 else
588 debug_greedy = FALSE;
589}
590
591/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000592 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000593 */
594 void
595ex_breakdel(eap)
596 exarg_T *eap;
597{
598 struct debuggy *bp, *bpi;
599 int nr;
600 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000601 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602 int i;
603 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000604 garray_T *gap;
605
606 gap = &dbg_breakp;
607#ifdef FEAT_PROFILE
608 if (eap->cmdidx == CMD_profdel)
609 gap = &prof_ga;
610#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611
612 if (vim_isdigit(*eap->arg))
613 {
614 /* ":breakdel {nr}" */
615 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000616 for (i = 0; i < gap->ga_len; ++i)
617 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618 {
619 todel = i;
620 break;
621 }
622 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000623 else if (*eap->arg == '*')
624 {
625 todel = 0;
626 del_all = TRUE;
627 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628 else
629 {
630 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000631 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000633 bp = &DEBUGGY(gap, gap->ga_len);
634 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000636 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 if (bp->dbg_type == bpi->dbg_type
638 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
639 && (bp->dbg_lnum == bpi->dbg_lnum
640 || (bp->dbg_lnum == 0
641 && (best_lnum == 0
642 || bpi->dbg_lnum < best_lnum))))
643 {
644 todel = i;
645 best_lnum = bpi->dbg_lnum;
646 }
647 }
648 vim_free(bp->dbg_name);
649 }
650
651 if (todel < 0)
652 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
653 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000654 {
655 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000656 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000657 vim_free(DEBUGGY(gap, todel).dbg_name);
658 vim_free(DEBUGGY(gap, todel).dbg_prog);
659 --gap->ga_len;
660 if (todel < gap->ga_len)
661 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
662 (gap->ga_len - todel) * sizeof(struct debuggy));
663#ifdef FEAT_PROFILE
664 if (eap->cmdidx == CMD_breakdel)
665#endif
666 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000667 if (!del_all)
668 break;
669 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000670
671 /* If all breakpoints were removed clear the array. */
672 if (gap->ga_len == 0)
673 ga_clear(gap);
674 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675}
676
677/*
678 * ":breaklist".
679 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680 void
681ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000682 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683{
684 struct debuggy *bp;
685 int i;
686
687 if (dbg_breakp.ga_len == 0)
688 MSG(_("No breakpoints defined"));
689 else
690 for (i = 0; i < dbg_breakp.ga_len; ++i)
691 {
692 bp = &BREAKP(i);
693 smsg((char_u *)_("%3d %s %s line %ld"),
694 bp->dbg_nr,
695 bp->dbg_type == DBG_FUNC ? "func" : "file",
696 bp->dbg_name,
697 (long)bp->dbg_lnum);
698 }
699}
700
701/*
702 * Find a breakpoint for a function or sourced file.
703 * Returns line number at which to break; zero when no matching breakpoint.
704 */
705 linenr_T
706dbg_find_breakpoint(file, fname, after)
707 int file; /* TRUE for a file, FALSE for a function */
708 char_u *fname; /* file or function name */
709 linenr_T after; /* after this line number */
710{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000711 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
712}
713
714#if defined(FEAT_PROFILE) || defined(PROTO)
715/*
716 * Return TRUE if profiling is on for a function or sourced file.
717 */
718 int
719has_profiling(file, fname, fp)
720 int file; /* TRUE for a file, FALSE for a function */
721 char_u *fname; /* file or function name */
722 int *fp; /* return: forceit */
723{
724 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
725 != (linenr_T)0);
726}
727#endif
728
729/*
730 * Common code for dbg_find_breakpoint() and has_profiling().
731 */
732 static linenr_T
733debuggy_find(file, fname, after, gap, fp)
734 int file; /* TRUE for a file, FALSE for a function */
735 char_u *fname; /* file or function name */
736 linenr_T after; /* after this line number */
737 garray_T *gap; /* either &dbg_breakp or &prof_ga */
738 int *fp; /* if not NULL: return forceit */
739{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740 struct debuggy *bp;
741 int i;
742 linenr_T lnum = 0;
743 regmatch_T regmatch;
744 char_u *name = fname;
745 int prev_got_int;
746
Bram Moolenaar05159a02005-02-26 23:04:13 +0000747 /* Return quickly when there are no breakpoints. */
748 if (gap->ga_len == 0)
749 return (linenr_T)0;
750
Bram Moolenaar071d4272004-06-13 20:20:40 +0000751 /* Replace K_SNR in function name with "<SNR>". */
752 if (!file && fname[0] == K_SPECIAL)
753 {
754 name = alloc((unsigned)STRLEN(fname) + 3);
755 if (name == NULL)
756 name = fname;
757 else
758 {
759 STRCPY(name, "<SNR>");
760 STRCPY(name + 5, fname + 3);
761 }
762 }
763
Bram Moolenaar05159a02005-02-26 23:04:13 +0000764 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000766 /* Skip entries that are not useful or are for a line that is beyond
767 * an already found breakpoint. */
768 bp = &DEBUGGY(gap, i);
769 if (((bp->dbg_type == DBG_FILE) == file && (
770#ifdef FEAT_PROFILE
771 gap == &prof_ga ||
772#endif
773 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 {
775 regmatch.regprog = bp->dbg_prog;
776 regmatch.rm_ic = FALSE;
777 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000778 * Save the value of got_int and reset it. We don't want a
779 * previous interruption cancel matching, only hitting CTRL-C
780 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000781 */
782 prev_got_int = got_int;
783 got_int = FALSE;
784 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000785 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000787 if (fp != NULL)
788 *fp = bp->dbg_forceit;
789 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 got_int |= prev_got_int;
791 }
792 }
793 if (name != fname)
794 vim_free(name);
795
796 return lnum;
797}
798
799/*
800 * Called when a breakpoint was encountered.
801 */
802 void
803dbg_breakpoint(name, lnum)
804 char_u *name;
805 linenr_T lnum;
806{
807 /* We need to check if this line is actually executed in do_one_cmd() */
808 debug_breakpoint_name = name;
809 debug_breakpoint_lnum = lnum;
810}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000811
812
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000813# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000814/*
815 * Store the current time in "tm".
816 */
817 void
818profile_start(tm)
819 proftime_T *tm;
820{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000821# ifdef WIN3264
822 QueryPerformanceCounter(tm);
823# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000824 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000825# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000826}
827
828/*
829 * Compute the elapsed time from "tm" till now and store in "tm".
830 */
831 void
832profile_end(tm)
833 proftime_T *tm;
834{
835 proftime_T now;
836
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000837# ifdef WIN3264
838 QueryPerformanceCounter(&now);
839 tm->QuadPart = now.QuadPart - tm->QuadPart;
840# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000841 gettimeofday(&now, NULL);
842 tm->tv_usec = now.tv_usec - tm->tv_usec;
843 tm->tv_sec = now.tv_sec - tm->tv_sec;
844 if (tm->tv_usec < 0)
845 {
846 tm->tv_usec += 1000000;
847 --tm->tv_sec;
848 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000849# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000850}
851
852/*
853 * Subtract the time "tm2" from "tm".
854 */
855 void
856profile_sub(tm, tm2)
857 proftime_T *tm, *tm2;
858{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000859# ifdef WIN3264
860 tm->QuadPart -= tm2->QuadPart;
861# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000862 tm->tv_usec -= tm2->tv_usec;
863 tm->tv_sec -= tm2->tv_sec;
864 if (tm->tv_usec < 0)
865 {
866 tm->tv_usec += 1000000;
867 --tm->tv_sec;
868 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000869# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000870}
871
872/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000873 * Return a string that represents the time in "tm".
874 * Uses a static buffer!
875 */
876 char *
877profile_msg(tm)
878 proftime_T *tm;
879{
880 static char buf[50];
881
882# ifdef WIN3264
883 LARGE_INTEGER fr;
884
885 QueryPerformanceFrequency(&fr);
886 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
887# else
888 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000889# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000890 return buf;
891}
892
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000893/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000894 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000895 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000896 void
897profile_setlimit(msec, tm)
898 long msec;
899 proftime_T *tm;
900{
901 if (msec <= 0) /* no limit */
902 profile_zero(tm);
903 else
904 {
905# ifdef WIN3264
906 LARGE_INTEGER fr;
907
908 QueryPerformanceCounter(tm);
909 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000910 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000911# else
912 long usec;
913
914 gettimeofday(tm, NULL);
915 usec = (long)tm->tv_usec + (long)msec * 1000;
916 tm->tv_usec = usec % 1000000L;
917 tm->tv_sec += usec / 1000000L;
918# endif
919 }
920}
921
922/*
923 * Return TRUE if the current time is past "tm".
924 */
925 int
926profile_passed_limit(tm)
927 proftime_T *tm;
928{
929 proftime_T now;
930
931# ifdef WIN3264
932 if (tm->QuadPart == 0) /* timer was not set */
933 return FALSE;
934 QueryPerformanceCounter(&now);
935 return (now.QuadPart > tm->QuadPart);
936# else
937 if (tm->tv_sec == 0) /* timer was not set */
938 return FALSE;
939 gettimeofday(&now, NULL);
940 return (now.tv_sec > tm->tv_sec
941 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
942# endif
943}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000944
945/*
946 * Set the time in "tm" to zero.
947 */
948 void
949profile_zero(tm)
950 proftime_T *tm;
951{
952# ifdef WIN3264
953 tm->QuadPart = 0;
954# else
955 tm->tv_usec = 0;
956 tm->tv_sec = 0;
957# endif
958}
959
Bram Moolenaar76929292008-01-06 19:07:36 +0000960# endif /* FEAT_PROFILE || FEAT_RELTIME */
961
962# if defined(FEAT_PROFILE) || defined(PROTO)
963/*
964 * Functions for profiling.
965 */
966static void script_do_profile __ARGS((scriptitem_T *si));
967static void script_dump_profile __ARGS((FILE *fd));
968static proftime_T prof_wait_time;
969
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000970/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000971 * Add the time "tm2" to "tm".
972 */
973 void
974profile_add(tm, tm2)
975 proftime_T *tm, *tm2;
976{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000977# ifdef WIN3264
978 tm->QuadPart += tm2->QuadPart;
979# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000980 tm->tv_usec += tm2->tv_usec;
981 tm->tv_sec += tm2->tv_sec;
982 if (tm->tv_usec >= 1000000)
983 {
984 tm->tv_usec -= 1000000;
985 ++tm->tv_sec;
986 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000987# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000988}
989
990/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000991 * Add the "self" time from the total time and the children's time.
992 */
993 void
994profile_self(self, total, children)
995 proftime_T *self, *total, *children;
996{
997 /* Check that the result won't be negative. Can happen with recursive
998 * calls. */
999#ifdef WIN3264
1000 if (total->QuadPart <= children->QuadPart)
1001 return;
1002#else
1003 if (total->tv_sec < children->tv_sec
1004 || (total->tv_sec == children->tv_sec
1005 && total->tv_usec <= children->tv_usec))
1006 return;
1007#endif
1008 profile_add(self, total);
1009 profile_sub(self, children);
1010}
1011
1012/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001013 * Get the current waittime.
1014 */
1015 void
1016profile_get_wait(tm)
1017 proftime_T *tm;
1018{
1019 *tm = prof_wait_time;
1020}
1021
1022/*
1023 * Subtract the passed waittime since "tm" from "tma".
1024 */
1025 void
1026profile_sub_wait(tm, tma)
1027 proftime_T *tm, *tma;
1028{
1029 proftime_T tm3 = prof_wait_time;
1030
1031 profile_sub(&tm3, tm);
1032 profile_sub(tma, &tm3);
1033}
1034
1035/*
1036 * Return TRUE if "tm1" and "tm2" are equal.
1037 */
1038 int
1039profile_equal(tm1, tm2)
1040 proftime_T *tm1, *tm2;
1041{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001042# ifdef WIN3264
1043 return (tm1->QuadPart == tm2->QuadPart);
1044# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001045 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001046# endif
1047}
1048
1049/*
1050 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1051 */
1052 int
1053profile_cmp(tm1, tm2)
1054 proftime_T *tm1, *tm2;
1055{
1056# ifdef WIN3264
1057 return (int)(tm2->QuadPart - tm1->QuadPart);
1058# else
1059 if (tm1->tv_sec == tm2->tv_sec)
1060 return tm2->tv_usec - tm1->tv_usec;
1061 return tm2->tv_sec - tm1->tv_sec;
1062# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001063}
1064
Bram Moolenaar05159a02005-02-26 23:04:13 +00001065static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001066static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001067
1068/*
1069 * ":profile cmd args"
1070 */
1071 void
1072ex_profile(eap)
1073 exarg_T *eap;
1074{
1075 char_u *e;
1076 int len;
1077
1078 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001079 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001080 e = skipwhite(e);
1081
1082 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1083 {
1084 vim_free(profile_fname);
1085 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001086 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001087 profile_zero(&prof_wait_time);
1088 set_vim_var_nr(VV_PROFILING, 1L);
1089 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001090 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001091 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001092 else if (STRCMP(eap->arg, "pause") == 0)
1093 {
1094 if (do_profiling == PROF_YES)
1095 profile_start(&pause_time);
1096 do_profiling = PROF_PAUSED;
1097 }
1098 else if (STRCMP(eap->arg, "continue") == 0)
1099 {
1100 if (do_profiling == PROF_PAUSED)
1101 {
1102 profile_end(&pause_time);
1103 profile_add(&prof_wait_time, &pause_time);
1104 }
1105 do_profiling = PROF_YES;
1106 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001107 else
1108 {
1109 /* The rest is similar to ":breakadd". */
1110 ex_breakadd(eap);
1111 }
1112}
1113
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001114/* Command line expansion for :profile. */
1115static enum
1116{
1117 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001118 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001119} pexpand_what;
1120
1121static char *pexpand_cmds[] = {
1122 "start",
1123#define PROFCMD_START 0
1124 "pause",
1125#define PROFCMD_PAUSE 1
1126 "continue",
1127#define PROFCMD_CONTINUE 2
1128 "func",
1129#define PROFCMD_FUNC 3
1130 "file",
1131#define PROFCMD_FILE 4
1132 NULL
1133#define PROFCMD_LAST 5
1134};
1135
1136/*
1137 * Function given to ExpandGeneric() to obtain the profile command
1138 * specific expansion.
1139 */
1140 char_u *
1141get_profile_name(xp, idx)
1142 expand_T *xp UNUSED;
1143 int idx;
1144{
1145 switch (pexpand_what)
1146 {
1147 case PEXP_SUBCMD:
1148 return (char_u *)pexpand_cmds[idx];
1149 /* case PEXP_FUNC: TODO */
1150 default:
1151 return NULL;
1152 }
1153}
1154
1155/*
1156 * Handle command line completion for :profile command.
1157 */
1158 void
1159set_context_in_profile_cmd(xp, arg)
1160 expand_T *xp;
1161 char_u *arg;
1162{
1163 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001164
1165 /* Default: expand subcommands. */
1166 xp->xp_context = EXPAND_PROFILE;
1167 pexpand_what = PEXP_SUBCMD;
1168 xp->xp_pattern = arg;
1169
1170 end_subcmd = skiptowhite(arg);
1171 if (*end_subcmd == NUL)
1172 return;
1173
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001174 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001175 {
1176 xp->xp_context = EXPAND_FILES;
1177 xp->xp_pattern = skipwhite(end_subcmd);
1178 return;
1179 }
1180
1181 /* TODO: expand function names after "func" */
1182 xp->xp_context = EXPAND_NOTHING;
1183}
1184
Bram Moolenaar05159a02005-02-26 23:04:13 +00001185/*
1186 * Dump the profiling info.
1187 */
1188 void
1189profile_dump()
1190{
1191 FILE *fd;
1192
1193 if (profile_fname != NULL)
1194 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001195 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001196 if (fd == NULL)
1197 EMSG2(_(e_notopen), profile_fname);
1198 else
1199 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001200 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001201 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001202 fclose(fd);
1203 }
1204 }
1205}
1206
1207/*
1208 * Start profiling script "fp".
1209 */
1210 static void
1211script_do_profile(si)
1212 scriptitem_T *si;
1213{
1214 si->sn_pr_count = 0;
1215 profile_zero(&si->sn_pr_total);
1216 profile_zero(&si->sn_pr_self);
1217
1218 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1219 si->sn_prl_idx = -1;
1220 si->sn_prof_on = TRUE;
1221 si->sn_pr_nest = 0;
1222}
1223
1224/*
1225 * save time when starting to invoke another script or function.
1226 */
1227 void
1228script_prof_save(tm)
1229 proftime_T *tm; /* place to store wait time */
1230{
1231 scriptitem_T *si;
1232
1233 if (current_SID > 0 && current_SID <= script_items.ga_len)
1234 {
1235 si = &SCRIPT_ITEM(current_SID);
1236 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1237 profile_start(&si->sn_pr_child);
1238 }
1239 profile_get_wait(tm);
1240}
1241
1242/*
1243 * Count time spent in children after invoking another script or function.
1244 */
1245 void
1246script_prof_restore(tm)
1247 proftime_T *tm;
1248{
1249 scriptitem_T *si;
1250
1251 if (current_SID > 0 && current_SID <= script_items.ga_len)
1252 {
1253 si = &SCRIPT_ITEM(current_SID);
1254 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1255 {
1256 profile_end(&si->sn_pr_child);
1257 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1258 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1259 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1260 }
1261 }
1262}
1263
1264static proftime_T inchar_time;
1265
1266/*
1267 * Called when starting to wait for the user to type a character.
1268 */
1269 void
1270prof_inchar_enter()
1271{
1272 profile_start(&inchar_time);
1273}
1274
1275/*
1276 * Called when finished waiting for the user to type a character.
1277 */
1278 void
1279prof_inchar_exit()
1280{
1281 profile_end(&inchar_time);
1282 profile_add(&prof_wait_time, &inchar_time);
1283}
1284
1285/*
1286 * Dump the profiling results for all scripts in file "fd".
1287 */
1288 static void
1289script_dump_profile(fd)
1290 FILE *fd;
1291{
1292 int id;
1293 scriptitem_T *si;
1294 int i;
1295 FILE *sfd;
1296 sn_prl_T *pp;
1297
1298 for (id = 1; id <= script_items.ga_len; ++id)
1299 {
1300 si = &SCRIPT_ITEM(id);
1301 if (si->sn_prof_on)
1302 {
1303 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1304 if (si->sn_pr_count == 1)
1305 fprintf(fd, "Sourced 1 time\n");
1306 else
1307 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1308 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1309 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1310 fprintf(fd, "\n");
1311 fprintf(fd, "count total (s) self (s)\n");
1312
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001313 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001314 if (sfd == NULL)
1315 fprintf(fd, "Cannot open file!\n");
1316 else
1317 {
1318 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1319 {
1320 if (vim_fgets(IObuff, IOSIZE, sfd))
1321 break;
1322 pp = &PRL_ITEM(si, i);
1323 if (pp->snp_count > 0)
1324 {
1325 fprintf(fd, "%5d ", pp->snp_count);
1326 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1327 fprintf(fd, " ");
1328 else
1329 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1330 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1331 }
1332 else
1333 fprintf(fd, " ");
1334 fprintf(fd, "%s", IObuff);
1335 }
1336 fclose(sfd);
1337 }
1338 fprintf(fd, "\n");
1339 }
1340 }
1341}
1342
1343/*
1344 * Return TRUE when a function defined in the current script should be
1345 * profiled.
1346 */
1347 int
1348prof_def_func()
1349{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001350 if (current_SID > 0)
1351 return SCRIPT_ITEM(current_SID).sn_pr_force;
1352 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001353}
1354
1355# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001356#endif
1357
1358/*
1359 * If 'autowrite' option set, try to write the file.
1360 * Careful: autocommands may make "buf" invalid!
1361 *
1362 * return FAIL for failure, OK otherwise
1363 */
1364 int
1365autowrite(buf, forceit)
1366 buf_T *buf;
1367 int forceit;
1368{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001369 int r;
1370
Bram Moolenaar071d4272004-06-13 20:20:40 +00001371 if (!(p_aw || p_awa) || !p_write
1372#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001373 /* never autowrite a "nofile" or "nowrite" buffer */
1374 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001375#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001376 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001377 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001378 r = buf_write_all(buf, forceit);
1379
1380 /* Writing may succeed but the buffer still changed, e.g., when there is a
1381 * conversion error. We do want to return FAIL then. */
1382 if (buf_valid(buf) && bufIsChanged(buf))
1383 r = FAIL;
1384 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001385}
1386
1387/*
1388 * flush all buffers, except the ones that are readonly
1389 */
1390 void
1391autowrite_all()
1392{
1393 buf_T *buf;
1394
1395 if (!(p_aw || p_awa) || !p_write)
1396 return;
1397 for (buf = firstbuf; buf; buf = buf->b_next)
1398 if (bufIsChanged(buf) && !buf->b_p_ro)
1399 {
1400 (void)buf_write_all(buf, FALSE);
1401#ifdef FEAT_AUTOCMD
1402 /* an autocommand may have deleted the buffer */
1403 if (!buf_valid(buf))
1404 buf = firstbuf;
1405#endif
1406 }
1407}
1408
1409/*
1410 * return TRUE if buffer was changed and cannot be abandoned.
1411 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001412 int
1413check_changed(buf, checkaw, mult_win, forceit, allbuf)
1414 buf_T *buf;
1415 int checkaw; /* do autowrite if buffer was changed */
1416 int mult_win; /* check also when several wins for the buf */
1417 int forceit;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001418 int allbuf UNUSED; /* may write all buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419{
1420 if ( !forceit
1421 && bufIsChanged(buf)
1422 && (mult_win || buf->b_nwindows <= 1)
1423 && (!checkaw || autowrite(buf, forceit) == FAIL))
1424 {
1425#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1426 if ((p_confirm || cmdmod.confirm) && p_write)
1427 {
1428 buf_T *buf2;
1429 int count = 0;
1430
1431 if (allbuf)
1432 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1433 if (bufIsChanged(buf2)
1434 && (buf2->b_ffname != NULL
1435# ifdef FEAT_BROWSE
1436 || cmdmod.browse
1437# endif
1438 ))
1439 ++count;
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 dialog_changed(buf, count > 1);
1446# ifdef FEAT_AUTOCMD
1447 if (!buf_valid(buf))
1448 /* Autocommand deleted buffer, oops! It's not changed now. */
1449 return FALSE;
1450# endif
1451 return bufIsChanged(buf);
1452 }
1453#endif
1454 EMSG(_(e_nowrtmsg));
1455 return TRUE;
1456 }
1457 return FALSE;
1458}
1459
1460#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1461
1462#if defined(FEAT_BROWSE) || defined(PROTO)
1463/*
1464 * When wanting to write a file without a file name, ask the user for a name.
1465 */
1466 void
1467browse_save_fname(buf)
1468 buf_T *buf;
1469{
1470 if (buf->b_fname == NULL)
1471 {
1472 char_u *fname;
1473
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001474 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1475 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476 if (fname != NULL)
1477 {
1478 if (setfname(buf, fname, NULL, TRUE) == OK)
1479 buf->b_flags |= BF_NOTEDITED;
1480 vim_free(fname);
1481 }
1482 }
1483}
1484#endif
1485
1486/*
1487 * Ask the user what to do when abondoning a changed buffer.
1488 * Must check 'write' option first!
1489 */
1490 void
1491dialog_changed(buf, checkall)
1492 buf_T *buf;
1493 int checkall; /* may abandon all changed buffers */
1494{
1495 char_u buff[IOSIZE];
1496 int ret;
1497 buf_T *buf2;
1498
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001499 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001500 (buf->b_fname != NULL) ?
1501 buf->b_fname : (char_u *)_("Untitled"));
1502 if (checkall)
1503 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1504 else
1505 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1506
1507 if (ret == VIM_YES)
1508 {
1509#ifdef FEAT_BROWSE
1510 /* May get file name, when there is none */
1511 browse_save_fname(buf);
1512#endif
1513 if (buf->b_fname != NULL) /* didn't hit Cancel */
1514 (void)buf_write_all(buf, FALSE);
1515 }
1516 else if (ret == VIM_NO)
1517 {
1518 unchanged(buf, TRUE);
1519 }
1520 else if (ret == VIM_ALL)
1521 {
1522 /*
1523 * Write all modified files that can be written.
1524 * Skip readonly buffers, these need to be confirmed
1525 * individually.
1526 */
1527 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1528 {
1529 if (bufIsChanged(buf2)
1530 && (buf2->b_ffname != NULL
1531#ifdef FEAT_BROWSE
1532 || cmdmod.browse
1533#endif
1534 )
1535 && !buf2->b_p_ro)
1536 {
1537#ifdef FEAT_BROWSE
1538 /* May get file name, when there is none */
1539 browse_save_fname(buf2);
1540#endif
1541 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1542 (void)buf_write_all(buf2, FALSE);
1543#ifdef FEAT_AUTOCMD
1544 /* an autocommand may have deleted the buffer */
1545 if (!buf_valid(buf2))
1546 buf2 = firstbuf;
1547#endif
1548 }
1549 }
1550 }
1551 else if (ret == VIM_DISCARDALL)
1552 {
1553 /*
1554 * mark all buffers as unchanged
1555 */
1556 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1557 unchanged(buf2, TRUE);
1558 }
1559}
1560#endif
1561
1562/*
1563 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1564 * hidden, autowriting it or unloading it.
1565 */
1566 int
1567can_abandon(buf, forceit)
1568 buf_T *buf;
1569 int forceit;
1570{
1571 return ( P_HID(buf)
1572 || !bufIsChanged(buf)
1573 || buf->b_nwindows > 1
1574 || autowrite(buf, forceit) == OK
1575 || forceit);
1576}
1577
1578/*
1579 * Return TRUE if any buffer was changed and cannot be abandoned.
1580 * That changed buffer becomes the current buffer.
1581 */
1582 int
1583check_changed_any(hidden)
1584 int hidden; /* Only check hidden buffers */
1585{
1586 buf_T *buf;
1587 int save;
1588#ifdef FEAT_WINDOWS
1589 win_T *wp;
1590#endif
1591
1592 for (;;)
1593 {
1594 /* check curbuf first: if it was changed we can't abandon it */
1595 if (!hidden && curbufIsChanged())
1596 buf = curbuf;
1597 else
1598 {
1599 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1600 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1601 break;
1602 }
1603 if (buf == NULL) /* No buffers changed */
1604 return FALSE;
1605
Bram Moolenaar373154b2007-02-13 05:19:30 +00001606 /* Try auto-writing the buffer. If this fails but the buffer no
1607 * longer exists it's not changed, that's OK. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1609 break; /* didn't save - still changes */
1610 }
1611
1612 exiting = FALSE;
1613#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1614 /*
1615 * When ":confirm" used, don't give an error message.
1616 */
1617 if (!(p_confirm || cmdmod.confirm))
1618#endif
1619 {
1620 /* There must be a wait_return for this message, do_buffer()
1621 * may cause a redraw. But wait_return() is a no-op when vgetc()
1622 * is busy (Quit used from window menu), then make sure we don't
1623 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001624 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001625 {
1626 msg_row = cmdline_row;
1627 msg_col = 0;
1628 msg_didout = FALSE;
1629 }
1630 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1631 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1632 buf->b_fname))
1633 {
1634 save = no_wait_return;
1635 no_wait_return = FALSE;
1636 wait_return(FALSE);
1637 no_wait_return = save;
1638 }
1639 }
1640
1641#ifdef FEAT_WINDOWS
1642 /* Try to find a window that contains the buffer. */
1643 if (buf != curbuf)
1644 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1645 if (wp->w_buffer == buf)
1646 {
1647 win_goto(wp);
1648# ifdef FEAT_AUTOCMD
1649 /* Paranoia: did autocms wipe out the buffer with changes? */
1650 if (!buf_valid(buf))
1651 return TRUE;
1652# endif
1653 break;
1654 }
1655#endif
1656
1657 /* Open the changed buffer in the current window. */
1658 if (buf != curbuf)
1659 set_curbuf(buf, DOBUF_GOTO);
1660
1661 return TRUE;
1662}
1663
1664/*
1665 * return FAIL if there is no file name, OK if there is one
1666 * give error message for FAIL
1667 */
1668 int
1669check_fname()
1670{
1671 if (curbuf->b_ffname == NULL)
1672 {
1673 EMSG(_(e_noname));
1674 return FAIL;
1675 }
1676 return OK;
1677}
1678
1679/*
1680 * flush the contents of a buffer, unless it has no file name
1681 *
1682 * return FAIL for failure, OK otherwise
1683 */
1684 int
1685buf_write_all(buf, forceit)
1686 buf_T *buf;
1687 int forceit;
1688{
1689 int retval;
1690#ifdef FEAT_AUTOCMD
1691 buf_T *old_curbuf = curbuf;
1692#endif
1693
1694 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1695 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1696 FALSE, forceit, TRUE, FALSE));
1697#ifdef FEAT_AUTOCMD
1698 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001699 {
1700 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001701 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001702 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703#endif
1704 return retval;
1705}
1706
1707/*
1708 * Code to handle the argument list.
1709 */
1710
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001711static char_u *do_one_arg __ARGS((char_u *str));
1712static int do_arglist __ARGS((char_u *str, int what, int after));
1713static void alist_check_arg_idx __ARGS((void));
1714static int editing_arg_idx __ARGS((win_T *win));
1715#ifdef FEAT_LISTCMDS
1716static int alist_add_list __ARGS((int count, char_u **files, int after));
1717#endif
1718#define AL_SET 1
1719#define AL_ADD 2
1720#define AL_DEL 3
1721
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001723 * Isolate one argument, taking backticks.
1724 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 * Return a pointer to the start of the next argument.
1726 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001727 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728do_one_arg(str)
1729 char_u *str;
1730{
1731 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732 int inbacktick;
1733
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 inbacktick = FALSE;
1735 for (p = str; *str; ++str)
1736 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001737 /* When the backslash is used for escaping the special meaning of a
1738 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739 if (rem_backslash(str))
1740 {
1741 *p++ = *str++;
1742 *p++ = *str;
1743 }
1744 else
1745 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001746 /* An item ends at a space not in backticks */
1747 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001749 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001751 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752 }
1753 }
1754 str = skipwhite(str);
1755 *p = NUL;
1756
1757 return str;
1758}
1759
Bram Moolenaar86b68352004-12-27 21:59:20 +00001760/*
1761 * Separate the arguments in "str" and return a list of pointers in the
1762 * growarray "gap".
1763 */
1764 int
1765get_arglist(gap, str)
1766 garray_T *gap;
1767 char_u *str;
1768{
1769 ga_init2(gap, (int)sizeof(char_u *), 20);
1770 while (*str != NUL)
1771 {
1772 if (ga_grow(gap, 1) == FAIL)
1773 {
1774 ga_clear(gap);
1775 return FAIL;
1776 }
1777 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1778
1779 /* Isolate one argument, change it in-place, put a NUL after it. */
1780 str = do_one_arg(str);
1781 }
1782 return OK;
1783}
1784
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001785#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001786/*
1787 * Parse a list of arguments (file names), expand them and return in
1788 * "fnames[fcountp]".
1789 * Return FAIL or OK.
1790 */
1791 int
1792get_arglist_exp(str, fcountp, fnamesp)
1793 char_u *str;
1794 int *fcountp;
1795 char_u ***fnamesp;
1796{
1797 garray_T ga;
1798 int i;
1799
1800 if (get_arglist(&ga, str) == FAIL)
1801 return FAIL;
1802 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1803 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1804 ga_clear(&ga);
1805 return i;
1806}
1807#endif
1808
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1810/*
1811 * Redefine the argument list.
1812 */
1813 void
1814set_arglist(str)
1815 char_u *str;
1816{
1817 do_arglist(str, AL_SET, 0);
1818}
1819#endif
1820
1821/*
1822 * "what" == AL_SET: Redefine the argument list to 'str'.
1823 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1824 * "what" == AL_DEL: remove files in 'str' from the argument list.
1825 *
1826 * Return FAIL for failure, OK otherwise.
1827 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828 static int
1829do_arglist(str, what, after)
1830 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001831 int what UNUSED;
1832 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833{
1834 garray_T new_ga;
1835 int exp_count;
1836 char_u **exp_files;
1837 int i;
1838#ifdef FEAT_LISTCMDS
1839 char_u *p;
1840 int match;
1841#endif
1842
1843 /*
1844 * Collect all file name arguments in "new_ga".
1845 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001846 if (get_arglist(&new_ga, str) == FAIL)
1847 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848
1849#ifdef FEAT_LISTCMDS
1850 if (what == AL_DEL)
1851 {
1852 regmatch_T regmatch;
1853 int didone;
1854
1855 /*
1856 * Delete the items: use each item as a regexp and find a match in the
1857 * argument list.
1858 */
1859#ifdef CASE_INSENSITIVE_FILENAME
1860 regmatch.rm_ic = TRUE; /* Always ignore case */
1861#else
1862 regmatch.rm_ic = FALSE; /* Never ignore case */
1863#endif
1864 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1865 {
1866 p = ((char_u **)new_ga.ga_data)[i];
1867 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1868 if (p == NULL)
1869 break;
1870 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1871 if (regmatch.regprog == NULL)
1872 {
1873 vim_free(p);
1874 break;
1875 }
1876
1877 didone = FALSE;
1878 for (match = 0; match < ARGCOUNT; ++match)
1879 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1880 (colnr_T)0))
1881 {
1882 didone = TRUE;
1883 vim_free(ARGLIST[match].ae_fname);
1884 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1885 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1886 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 if (curwin->w_arg_idx > match)
1888 --curwin->w_arg_idx;
1889 --match;
1890 }
1891
1892 vim_free(regmatch.regprog);
1893 vim_free(p);
1894 if (!didone)
1895 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1896 }
1897 ga_clear(&new_ga);
1898 }
1899 else
1900#endif
1901 {
1902 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1903 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1904 ga_clear(&new_ga);
1905 if (i == FAIL)
1906 return FAIL;
1907 if (exp_count == 0)
1908 {
1909 EMSG(_(e_nomatch));
1910 return FAIL;
1911 }
1912
1913#ifdef FEAT_LISTCMDS
1914 if (what == AL_ADD)
1915 {
1916 (void)alist_add_list(exp_count, exp_files, after);
1917 vim_free(exp_files);
1918 }
1919 else /* what == AL_SET */
1920#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001921 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001922 }
1923
1924 alist_check_arg_idx();
1925
1926 return OK;
1927}
1928
1929/*
1930 * Check the validity of the arg_idx for each other window.
1931 */
1932 static void
1933alist_check_arg_idx()
1934{
1935#ifdef FEAT_WINDOWS
1936 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001937 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938
Bram Moolenaarf740b292006-02-16 22:11:02 +00001939 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 if (win->w_alist == curwin->w_alist)
1941 check_arg_idx(win);
1942#else
1943 check_arg_idx(curwin);
1944#endif
1945}
1946
1947/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001948 * Return TRUE if window "win" is editing then file at the current argument
1949 * index.
1950 */
1951 static int
1952editing_arg_idx(win)
1953 win_T *win;
1954{
1955 return !(win->w_arg_idx >= WARGCOUNT(win)
1956 || (win->w_buffer->b_fnum
1957 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1958 && (win->w_buffer->b_ffname == NULL
1959 || !(fullpathcmp(
1960 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1961 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1962}
1963
1964/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 * Check if window "win" is editing the w_arg_idx file in its argument list.
1966 */
1967 void
1968check_arg_idx(win)
1969 win_T *win;
1970{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001971 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001972 {
1973 /* We are not editing the current entry in the argument list.
1974 * Set "arg_had_last" if we are editing the last one. */
1975 win->w_arg_idx_invalid = TRUE;
1976 if (win->w_arg_idx != WARGCOUNT(win) - 1
1977 && arg_had_last == FALSE
1978#ifdef FEAT_WINDOWS
1979 && ALIST(win) == &global_alist
1980#endif
1981 && GARGCOUNT > 0
1982 && win->w_arg_idx < GARGCOUNT
1983 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1984 || (win->w_buffer->b_ffname != NULL
1985 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1986 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1987 arg_had_last = TRUE;
1988 }
1989 else
1990 {
1991 /* We are editing the current entry in the argument list.
1992 * Set "arg_had_last" if it's also the last one */
1993 win->w_arg_idx_invalid = FALSE;
1994 if (win->w_arg_idx == WARGCOUNT(win) - 1
1995#ifdef FEAT_WINDOWS
1996 && win->w_alist == &global_alist
1997#endif
1998 )
1999 arg_had_last = TRUE;
2000 }
2001}
2002
2003/*
2004 * ":args", ":argslocal" and ":argsglobal".
2005 */
2006 void
2007ex_args(eap)
2008 exarg_T *eap;
2009{
2010 int i;
2011
2012 if (eap->cmdidx != CMD_args)
2013 {
2014#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2015 alist_unlink(ALIST(curwin));
2016 if (eap->cmdidx == CMD_argglobal)
2017 ALIST(curwin) = &global_alist;
2018 else /* eap->cmdidx == CMD_arglocal */
2019 alist_new();
2020#else
2021 ex_ni(eap);
2022 return;
2023#endif
2024 }
2025
2026 if (!ends_excmd(*eap->arg))
2027 {
2028 /*
2029 * ":args file ..": define new argument list, handle like ":next"
2030 * Also for ":argslocal file .." and ":argsglobal file ..".
2031 */
2032 ex_next(eap);
2033 }
2034 else
2035#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2036 if (eap->cmdidx == CMD_args)
2037#endif
2038 {
2039 /*
2040 * ":args": list arguments.
2041 */
2042 if (ARGCOUNT > 0)
2043 {
2044 /* Overwrite the command, for a short list there is no scrolling
2045 * required and no wait_return(). */
2046 gotocmdline(TRUE);
2047 for (i = 0; i < ARGCOUNT; ++i)
2048 {
2049 if (i == curwin->w_arg_idx)
2050 msg_putchar('[');
2051 msg_outtrans(alist_name(&ARGLIST[i]));
2052 if (i == curwin->w_arg_idx)
2053 msg_putchar(']');
2054 msg_putchar(' ');
2055 }
2056 }
2057 }
2058#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2059 else if (eap->cmdidx == CMD_arglocal)
2060 {
2061 garray_T *gap = &curwin->w_alist->al_ga;
2062
2063 /*
2064 * ":argslocal": make a local copy of the global argument list.
2065 */
2066 if (ga_grow(gap, GARGCOUNT) == OK)
2067 for (i = 0; i < GARGCOUNT; ++i)
2068 if (GARGLIST[i].ae_fname != NULL)
2069 {
2070 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2071 vim_strsave(GARGLIST[i].ae_fname);
2072 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2073 GARGLIST[i].ae_fnum;
2074 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075 }
2076 }
2077#endif
2078}
2079
2080/*
2081 * ":previous", ":sprevious", ":Next" and ":sNext".
2082 */
2083 void
2084ex_previous(eap)
2085 exarg_T *eap;
2086{
2087 /* If past the last one already, go to the last one. */
2088 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2089 do_argfile(eap, ARGCOUNT - 1);
2090 else
2091 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2092}
2093
2094/*
2095 * ":rewind", ":first", ":sfirst" and ":srewind".
2096 */
2097 void
2098ex_rewind(eap)
2099 exarg_T *eap;
2100{
2101 do_argfile(eap, 0);
2102}
2103
2104/*
2105 * ":last" and ":slast".
2106 */
2107 void
2108ex_last(eap)
2109 exarg_T *eap;
2110{
2111 do_argfile(eap, ARGCOUNT - 1);
2112}
2113
2114/*
2115 * ":argument" and ":sargument".
2116 */
2117 void
2118ex_argument(eap)
2119 exarg_T *eap;
2120{
2121 int i;
2122
2123 if (eap->addr_count > 0)
2124 i = eap->line2 - 1;
2125 else
2126 i = curwin->w_arg_idx;
2127 do_argfile(eap, i);
2128}
2129
2130/*
2131 * Edit file "argn" of the argument lists.
2132 */
2133 void
2134do_argfile(eap, argn)
2135 exarg_T *eap;
2136 int argn;
2137{
2138 int other;
2139 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002140 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002141
2142 if (argn < 0 || argn >= ARGCOUNT)
2143 {
2144 if (ARGCOUNT <= 1)
2145 EMSG(_("E163: There is only one file to edit"));
2146 else if (argn < 0)
2147 EMSG(_("E164: Cannot go before first file"));
2148 else
2149 EMSG(_("E165: Cannot go beyond last file"));
2150 }
2151 else
2152 {
2153 setpcmark();
2154#ifdef FEAT_GUI
2155 need_mouse_correct = TRUE;
2156#endif
2157
2158#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002159 /* split window or create new tab page first */
2160 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002161 {
2162 if (win_split(0, 0) == FAIL)
2163 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002164 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 }
2166 else
2167#endif
2168 {
2169 /*
2170 * if 'hidden' set, only check for changed file when re-editing
2171 * the same buffer
2172 */
2173 other = TRUE;
2174 if (P_HID(curbuf))
2175 {
2176 p = fix_fname(alist_name(&ARGLIST[argn]));
2177 other = otherfile(p);
2178 vim_free(p);
2179 }
2180 if ((!P_HID(curbuf) || !other)
2181 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2182 return;
2183 }
2184
2185 curwin->w_arg_idx = argn;
2186 if (argn == ARGCOUNT - 1
2187#ifdef FEAT_WINDOWS
2188 && curwin->w_alist == &global_alist
2189#endif
2190 )
2191 arg_had_last = TRUE;
2192
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002193 /* Edit the file; always use the last known line number.
2194 * When it fails (e.g. Abort for already edited file) restore the
2195 * argument index. */
2196 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002197 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002198 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2199 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002200 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002201 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002202 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002203 setmark('\'');
2204 }
2205}
2206
2207/*
2208 * ":next", and commands that behave like it.
2209 */
2210 void
2211ex_next(eap)
2212 exarg_T *eap;
2213{
2214 int i;
2215
2216 /*
2217 * check for changed buffer now, if this fails the argument list is not
2218 * redefined.
2219 */
2220 if ( P_HID(curbuf)
2221 || eap->cmdidx == CMD_snext
2222 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2223 {
2224 if (*eap->arg != NUL) /* redefine file list */
2225 {
2226 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2227 return;
2228 i = 0;
2229 }
2230 else
2231 i = curwin->w_arg_idx + (int)eap->line2;
2232 do_argfile(eap, i);
2233 }
2234}
2235
2236#ifdef FEAT_LISTCMDS
2237/*
2238 * ":argedit"
2239 */
2240 void
2241ex_argedit(eap)
2242 exarg_T *eap;
2243{
2244 int fnum;
2245 int i;
2246 char_u *s;
2247
2248 /* Add the argument to the buffer list and get the buffer number. */
2249 fnum = buflist_add(eap->arg, BLN_LISTED);
2250
2251 /* Check if this argument is already in the argument list. */
2252 for (i = 0; i < ARGCOUNT; ++i)
2253 if (ARGLIST[i].ae_fnum == fnum)
2254 break;
2255 if (i == ARGCOUNT)
2256 {
2257 /* Can't find it, add it to the argument list. */
2258 s = vim_strsave(eap->arg);
2259 if (s == NULL)
2260 return;
2261 i = alist_add_list(1, &s,
2262 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2263 if (i < 0)
2264 return;
2265 curwin->w_arg_idx = i;
2266 }
2267
2268 alist_check_arg_idx();
2269
2270 /* Edit the argument. */
2271 do_argfile(eap, i);
2272}
2273
2274/*
2275 * ":argadd"
2276 */
2277 void
2278ex_argadd(eap)
2279 exarg_T *eap;
2280{
2281 do_arglist(eap->arg, AL_ADD,
2282 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2283#ifdef FEAT_TITLE
2284 maketitle();
2285#endif
2286}
2287
2288/*
2289 * ":argdelete"
2290 */
2291 void
2292ex_argdelete(eap)
2293 exarg_T *eap;
2294{
2295 int i;
2296 int n;
2297
2298 if (eap->addr_count > 0)
2299 {
2300 /* ":1,4argdel": Delete all arguments in the range. */
2301 if (eap->line2 > ARGCOUNT)
2302 eap->line2 = ARGCOUNT;
2303 n = eap->line2 - eap->line1 + 1;
2304 if (*eap->arg != NUL || n <= 0)
2305 EMSG(_(e_invarg));
2306 else
2307 {
2308 for (i = eap->line1; i <= eap->line2; ++i)
2309 vim_free(ARGLIST[i - 1].ae_fname);
2310 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2311 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2312 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002313 if (curwin->w_arg_idx >= eap->line2)
2314 curwin->w_arg_idx -= n;
2315 else if (curwin->w_arg_idx > eap->line1)
2316 curwin->w_arg_idx = eap->line1;
2317 }
2318 }
2319 else if (*eap->arg == NUL)
2320 EMSG(_(e_argreq));
2321 else
2322 do_arglist(eap->arg, AL_DEL, 0);
2323#ifdef FEAT_TITLE
2324 maketitle();
2325#endif
2326}
2327
2328/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002329 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002330 */
2331 void
2332ex_listdo(eap)
2333 exarg_T *eap;
2334{
2335 int i;
2336#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002337 win_T *wp;
2338 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339#endif
2340 buf_T *buf;
2341 int next_fnum = 0;
2342#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2343 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002345 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346
2347#ifndef FEAT_WINDOWS
2348 if (eap->cmdidx == CMD_windo)
2349 {
2350 ex_ni(eap);
2351 return;
2352 }
2353#endif
2354
2355#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002356 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002357 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2358 * great speed improvement. */
2359 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360#endif
2361
2362 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002363 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364 || P_HID(curbuf)
2365 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2366 {
2367 /* start at the first argument/window/buffer */
2368 i = 0;
2369#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002370 wp = firstwin;
2371 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372#endif
2373 /* set pcmark now */
2374 if (eap->cmdidx == CMD_bufdo)
2375 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2376 else
2377 setpcmark();
2378 listcmd_busy = TRUE; /* avoids setting pcmark below */
2379
2380 while (!got_int)
2381 {
2382 if (eap->cmdidx == CMD_argdo)
2383 {
2384 /* go to argument "i" */
2385 if (i == ARGCOUNT)
2386 break;
2387 /* Don't call do_argfile() when already there, it will try
2388 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002389 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002390 {
2391 /* Clear 'shm' to avoid that the file message overwrites
2392 * any output from the command. */
2393 p_shm_save = vim_strsave(p_shm);
2394 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002395 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002396 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2397 vim_free(p_shm_save);
2398 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399 if (curwin->w_arg_idx != i)
2400 break;
2401 ++i;
2402 }
2403#ifdef FEAT_WINDOWS
2404 else if (eap->cmdidx == CMD_windo)
2405 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002406 /* go to window "wp" */
2407 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002409 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002410 if (curwin != wp)
2411 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002412 wp = curwin->w_next;
2413 }
2414 else if (eap->cmdidx == CMD_tabdo)
2415 {
2416 /* go to window "tp" */
2417 if (!valid_tabpage(tp))
2418 break;
2419 goto_tabpage_tp(tp);
2420 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421 }
2422#endif
2423 else if (eap->cmdidx == CMD_bufdo)
2424 {
2425 /* Remember the number of the next listed buffer, in case
2426 * ":bwipe" is used or autocommands do something strange. */
2427 next_fnum = -1;
2428 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2429 if (buf->b_p_bl)
2430 {
2431 next_fnum = buf->b_fnum;
2432 break;
2433 }
2434 }
2435
2436 /* execute the command */
2437 do_cmdline(eap->arg, eap->getline, eap->cookie,
2438 DOCMD_VERBOSE + DOCMD_NOWAIT);
2439
2440 if (eap->cmdidx == CMD_bufdo)
2441 {
2442 /* Done? */
2443 if (next_fnum < 0)
2444 break;
2445 /* Check if the buffer still exists. */
2446 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2447 if (buf->b_fnum == next_fnum)
2448 break;
2449 if (buf == NULL)
2450 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002451
2452 /* Go to the next buffer. Clear 'shm' to avoid that the file
2453 * message overwrites any output from the command. */
2454 p_shm_save = vim_strsave(p_shm);
2455 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002457 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2458 vim_free(p_shm_save);
2459
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 /* If autocommands took us elsewhere, quit here */
2461 if (curbuf->b_fnum != next_fnum)
2462 break;
2463 }
2464
2465 if (eap->cmdidx == CMD_windo)
2466 {
2467 validate_cursor(); /* cursor may have moved */
2468#ifdef FEAT_SCROLLBIND
2469 /* required when 'scrollbind' has been set */
2470 if (curwin->w_p_scb)
2471 do_check_scrollbind(TRUE);
2472#endif
2473 }
2474 }
2475 listcmd_busy = FALSE;
2476 }
2477
2478#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002479 if (save_ei != NULL)
2480 {
2481 au_event_restore(save_ei);
2482 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2483 curbuf->b_fname, TRUE, curbuf);
2484 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485#endif
2486}
2487
2488/*
2489 * Add files[count] to the arglist of the current window after arg "after".
2490 * The file names in files[count] must have been allocated and are taken over.
2491 * Files[] itself is not taken over.
2492 * Returns index of first added argument. Returns -1 when failed (out of mem).
2493 */
2494 static int
2495alist_add_list(count, files, after)
2496 int count;
2497 char_u **files;
2498 int after; /* where to add: 0 = before first one */
2499{
2500 int i;
2501
2502 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2503 {
2504 if (after < 0)
2505 after = 0;
2506 if (after > ARGCOUNT)
2507 after = ARGCOUNT;
2508 if (after < ARGCOUNT)
2509 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2510 (ARGCOUNT - after) * sizeof(aentry_T));
2511 for (i = 0; i < count; ++i)
2512 {
2513 ARGLIST[after + i].ae_fname = files[i];
2514 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2515 }
2516 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002517 if (curwin->w_arg_idx >= after)
2518 ++curwin->w_arg_idx;
2519 return after;
2520 }
2521
2522 for (i = 0; i < count; ++i)
2523 vim_free(files[i]);
2524 return -1;
2525}
2526
2527#endif /* FEAT_LISTCMDS */
2528
2529#ifdef FEAT_EVAL
2530/*
2531 * ":compiler[!] {name}"
2532 */
2533 void
2534ex_compiler(eap)
2535 exarg_T *eap;
2536{
2537 char_u *buf;
2538 char_u *old_cur_comp = NULL;
2539 char_u *p;
2540
2541 if (*eap->arg == NUL)
2542 {
2543 /* List all compiler scripts. */
2544 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2545 /* ) keep the indenter happy... */
2546 }
2547 else
2548 {
2549 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2550 if (buf != NULL)
2551 {
2552 if (eap->forceit)
2553 {
2554 /* ":compiler! {name}" sets global options */
2555 do_cmdline_cmd((char_u *)
2556 "command -nargs=* CompilerSet set <args>");
2557 }
2558 else
2559 {
2560 /* ":compiler! {name}" sets local options.
2561 * To remain backwards compatible "current_compiler" is always
2562 * used. A user's compiler plugin may set it, the distributed
2563 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002564 * "b:current_compiler" and restore "current_compiler".
2565 * Explicitly prepend "g:" to make it work in a function. */
2566 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002567 if (old_cur_comp != NULL)
2568 old_cur_comp = vim_strsave(old_cur_comp);
2569 do_cmdline_cmd((char_u *)
2570 "command -nargs=* CompilerSet setlocal <args>");
2571 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002572 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002573 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574
2575 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002576 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2578 vim_free(buf);
2579
2580 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2581
2582 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002583 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 if (p != NULL)
2585 set_internal_string_var((char_u *)"b:current_compiler", p);
2586
2587 /* Restore "current_compiler" for ":compiler {name}". */
2588 if (!eap->forceit)
2589 {
2590 if (old_cur_comp != NULL)
2591 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002592 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593 old_cur_comp);
2594 vim_free(old_cur_comp);
2595 }
2596 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002597 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598 }
2599 }
2600 }
2601}
2602#endif
2603
2604/*
2605 * ":runtime {name}"
2606 */
2607 void
2608ex_runtime(eap)
2609 exarg_T *eap;
2610{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002611 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612}
2613
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002614static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002615
2616 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002617source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002619 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002621 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002622}
2623
2624/*
2625 * Source the file "name" from all directories in 'runtimepath'.
2626 * "name" can contain wildcards.
2627 * When "all" is TRUE, source all files, otherwise only the first one.
2628 * return FAIL when no file could be sourced, OK otherwise.
2629 */
2630 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002631source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632 char_u *name;
2633 int all;
2634{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002635 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636}
2637
2638/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002639 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2640 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2642 * used.
2643 * Returns OK when at least one match found, FAIL otherwise.
2644 */
2645 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002646do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647 char_u *name;
2648 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002649 void (*callback)__ARGS((char_u *fname, void *ck));
2650 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651{
2652 char_u *rtp;
2653 char_u *np;
2654 char_u *buf;
2655 char_u *rtp_copy;
2656 char_u *tail;
2657 int num_files;
2658 char_u **files;
2659 int i;
2660 int did_one = FALSE;
2661#ifdef AMIGA
2662 struct Process *proc = (struct Process *)FindTask(0L);
2663 APTR save_winptr = proc->pr_WindowPtr;
2664
2665 /* Avoid a requester here for a volume that doesn't exist. */
2666 proc->pr_WindowPtr = (APTR)-1L;
2667#endif
2668
2669 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2670 * value. */
2671 rtp_copy = vim_strsave(p_rtp);
2672 buf = alloc(MAXPATHL);
2673 if (buf != NULL && rtp_copy != NULL)
2674 {
2675 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002676 {
2677 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002678 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002680 verbose_leave();
2681 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002682
Bram Moolenaar071d4272004-06-13 20:20:40 +00002683 /* Loop over all entries in 'runtimepath'. */
2684 rtp = rtp_copy;
2685 while (*rtp != NUL && (all || !did_one))
2686 {
2687 /* Copy the path from 'runtimepath' to buf[]. */
2688 copy_option_part(&rtp, buf, MAXPATHL, ",");
2689 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2690 {
2691 add_pathsep(buf);
2692 tail = buf + STRLEN(buf);
2693
2694 /* Loop over all patterns in "name" */
2695 np = name;
2696 while (*np != NUL && (all || !did_one))
2697 {
2698 /* Append the pattern from "name" to buf[]. */
2699 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2700 "\t ");
2701
2702 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002703 {
2704 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002705 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002706 verbose_leave();
2707 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708
2709 /* Expand wildcards, invoke the callback for each match. */
2710 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2711 EW_FILE) == OK)
2712 {
2713 for (i = 0; i < num_files; ++i)
2714 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002715 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716 did_one = TRUE;
2717 if (!all)
2718 break;
2719 }
2720 FreeWild(num_files, files);
2721 }
2722 }
2723 }
2724 }
2725 }
2726 vim_free(buf);
2727 vim_free(rtp_copy);
2728 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002729 {
2730 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002731 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002732 verbose_leave();
2733 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734
2735#ifdef AMIGA
2736 proc->pr_WindowPtr = save_winptr;
2737#endif
2738
2739 return did_one ? OK : FAIL;
2740}
2741
2742#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2743/*
2744 * ":options"
2745 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746 void
2747ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002748 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002749{
2750 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2751}
2752#endif
2753
2754/*
2755 * ":source {fname}"
2756 */
2757 void
2758ex_source(eap)
2759 exarg_T *eap;
2760{
2761#ifdef FEAT_BROWSE
2762 if (cmdmod.browse)
2763 {
2764 char_u *fname = NULL;
2765
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002766 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002767 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2768 if (fname != NULL)
2769 {
2770 cmd_source(fname, eap);
2771 vim_free(fname);
2772 }
2773 }
2774 else
2775#endif
2776 cmd_source(eap->arg, eap);
2777}
2778
2779 static void
2780cmd_source(fname, eap)
2781 char_u *fname;
2782 exarg_T *eap;
2783{
2784 if (*fname == NUL)
2785 EMSG(_(e_argreq));
2786
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002788 /* ":source!": read Normal mdoe commands
2789 * Need to execute the commands directly. This is required at least
2790 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002791 * - ":g" command busy
2792 * - after ":argdo", ":windo" or ":bufdo"
2793 * - another command follows
2794 * - inside a loop
2795 */
2796 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2797#ifdef FEAT_EVAL
2798 || eap->cstack->cs_idx >= 0
2799#endif
2800 );
2801
2802 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002803 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804 EMSG2(_(e_notopen), fname);
2805}
2806
2807/*
2808 * ":source" and associated commands.
2809 */
2810/*
2811 * Structure used to store info for each sourced file.
2812 * It is shared between do_source() and getsourceline().
2813 * This is required, because it needs to be handed to do_cmdline() and
2814 * sourcing can be done recursively.
2815 */
2816struct source_cookie
2817{
2818 FILE *fp; /* opened file for sourcing */
2819 char_u *nextline; /* if not NULL: line that was read ahead */
2820 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002821#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2823 int error; /* TRUE if LF found after CR-LF */
2824#endif
2825#ifdef FEAT_EVAL
2826 linenr_T breakpoint; /* next line with breakpoint or zero */
2827 char_u *fname; /* name of sourced file */
2828 int dbg_tick; /* debug_tick when breakpoint was set */
2829 int level; /* top nesting level of sourced file */
2830#endif
2831#ifdef FEAT_MBYTE
2832 vimconv_T conv; /* type of conversion */
2833#endif
2834};
2835
2836#ifdef FEAT_EVAL
2837/*
2838 * Return the address holding the next breakpoint line for a source cookie.
2839 */
2840 linenr_T *
2841source_breakpoint(cookie)
2842 void *cookie;
2843{
2844 return &((struct source_cookie *)cookie)->breakpoint;
2845}
2846
2847/*
2848 * Return the address holding the debug tick for a source cookie.
2849 */
2850 int *
2851source_dbg_tick(cookie)
2852 void *cookie;
2853{
2854 return &((struct source_cookie *)cookie)->dbg_tick;
2855}
2856
2857/*
2858 * Return the nesting level for a source cookie.
2859 */
2860 int
2861source_level(cookie)
2862 void *cookie;
2863{
2864 return ((struct source_cookie *)cookie)->level;
2865}
2866#endif
2867
2868static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2869
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002870#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2871# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872static FILE *fopen_noinh_readbin __ARGS((char *filename));
2873
2874/*
2875 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002876 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002877 */
2878 static FILE *
2879fopen_noinh_readbin(filename)
2880 char *filename;
2881{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002882# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002883 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2884# else
2885 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002886# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887
2888 if (fd_tmp == -1)
2889 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002890
2891# ifdef HAVE_FD_CLOEXEC
2892 {
2893 int fdflags = fcntl(fd_tmp, F_GETFD);
2894 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
2895 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
2896 }
2897# endif
2898
Bram Moolenaar071d4272004-06-13 20:20:40 +00002899 return fdopen(fd_tmp, READBIN);
2900}
2901#endif
2902
2903
2904/*
2905 * do_source: Read the file "fname" and execute its lines as EX commands.
2906 *
2907 * This function may be called recursively!
2908 *
2909 * return FAIL if file could not be opened, OK otherwise
2910 */
2911 int
2912do_source(fname, check_other, is_vimrc)
2913 char_u *fname;
2914 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002915 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916{
2917 struct source_cookie cookie;
2918 char_u *save_sourcing_name;
2919 linenr_T save_sourcing_lnum;
2920 char_u *p;
2921 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002922 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 int retval = FAIL;
2924#ifdef FEAT_EVAL
2925 scid_T save_current_SID;
2926 static scid_T last_current_SID = 0;
2927 void *save_funccalp;
2928 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002929 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002930# ifdef UNIX
2931 struct stat st;
2932 int stat_ok;
2933# endif
2934#endif
2935#ifdef STARTUPTIME
2936 struct timeval tv_rel;
2937 struct timeval tv_start;
2938#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002939#ifdef FEAT_PROFILE
2940 proftime_T wait_start;
2941#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942
2943#ifdef RISCOS
2944 p = mch_munge_fname(fname);
2945#else
2946 p = expand_env_save(fname);
2947#endif
2948 if (p == NULL)
2949 return retval;
2950 fname_exp = fix_fname(p);
2951 vim_free(p);
2952 if (fname_exp == NULL)
2953 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954 if (mch_isdir(fname_exp))
2955 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002956 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002957 goto theend;
2958 }
2959
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002960#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002961 /* Apply SourceCmd autocommands, they should get the file and source it. */
2962 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2963 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2964 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002965 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002966# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002967 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002968# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002969 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002970# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002971 goto theend;
2972 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002973
2974 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002975 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2976#endif
2977
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002978#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002979 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2980#else
2981 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2982#endif
2983 if (cookie.fp == NULL && check_other)
2984 {
2985 /*
2986 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2987 * and ".exrc" by "_exrc" or vice versa.
2988 */
2989 p = gettail(fname_exp);
2990 if ((*p == '.' || *p == '_')
2991 && (STRICMP(p + 1, "vimrc") == 0
2992 || STRICMP(p + 1, "gvimrc") == 0
2993 || STRICMP(p + 1, "exrc") == 0))
2994 {
2995 if (*p == '_')
2996 *p = '.';
2997 else
2998 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002999#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3001#else
3002 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3003#endif
3004 }
3005 }
3006
3007 if (cookie.fp == NULL)
3008 {
3009 if (p_verbose > 0)
3010 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003011 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003013 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003014 else
3015 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003016 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003017 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 }
3019 goto theend;
3020 }
3021
3022 /*
3023 * The file exists.
3024 * - In verbose mode, give a message.
3025 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3026 */
3027 if (p_verbose > 1)
3028 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003029 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003031 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032 else
3033 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003034 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003035 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003037 if (is_vimrc == DOSO_VIMRC)
3038 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3039 else if (is_vimrc == DOSO_GVIMRC)
3040 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041
3042#ifdef USE_CRNL
3043 /* If no automatic file format: Set default to CR-NL. */
3044 if (*p_ffs == NUL)
3045 cookie.fileformat = EOL_DOS;
3046 else
3047 cookie.fileformat = EOL_UNKNOWN;
3048 cookie.error = FALSE;
3049#endif
3050
3051#ifdef USE_CR
3052 /* If no automatic file format: Set default to CR. */
3053 if (*p_ffs == NUL)
3054 cookie.fileformat = EOL_MAC;
3055 else
3056 cookie.fileformat = EOL_UNKNOWN;
3057 cookie.error = FALSE;
3058#endif
3059
3060 cookie.nextline = NULL;
3061 cookie.finished = FALSE;
3062
3063#ifdef FEAT_EVAL
3064 /*
3065 * Check if this script has a breakpoint.
3066 */
3067 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3068 cookie.fname = fname_exp;
3069 cookie.dbg_tick = debug_tick;
3070
3071 cookie.level = ex_nesting_level;
3072#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073
3074 /*
3075 * Keep the sourcing name/lnum, for recursive calls.
3076 */
3077 save_sourcing_name = sourcing_name;
3078 sourcing_name = fname_exp;
3079 save_sourcing_lnum = sourcing_lnum;
3080 sourcing_lnum = 0;
3081
Bram Moolenaar73881402009-02-04 16:50:47 +00003082#ifdef FEAT_MBYTE
3083 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3084
3085 /* Read the first line so we can check for a UTF-8 BOM. */
3086 firstline = getsourceline(0, (void *)&cookie, 0);
3087 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3088 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3089 {
3090 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3091 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3092 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003093 if (p == NULL)
3094 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003095 if (p != NULL)
3096 {
3097 vim_free(firstline);
3098 firstline = p;
3099 }
3100 }
3101#endif
3102
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003104 if (time_fd != NULL)
3105 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106#endif
3107
3108#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003109# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003110 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003111 prof_child_enter(&wait_start); /* entering a child now */
3112# endif
3113
3114 /* Don't use local function variables, if called from a function.
3115 * Also starts profiling timer for nested script. */
3116 save_funccalp = save_funccal();
3117
Bram Moolenaar071d4272004-06-13 20:20:40 +00003118 /*
3119 * Check if this script was sourced before to finds its SID.
3120 * If it's new, generate a new SID.
3121 */
3122 save_current_SID = current_SID;
3123# ifdef UNIX
3124 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3125# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003126 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3127 {
3128 si = &SCRIPT_ITEM(current_SID);
3129 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 && (
3131# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003132 /* Compare dev/ino when possible, it catches symbolic
3133 * links. Also compare file names, the inode may change
3134 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003135 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003136 && (si->sn_dev == st.st_dev
3137 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003139 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003140 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003141 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142 if (current_SID == 0)
3143 {
3144 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003145 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3146 == FAIL)
3147 goto almosttheend;
3148 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003150 ++script_items.ga_len;
3151 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3152# ifdef FEAT_PROFILE
3153 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003154# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003155 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003156 si = &SCRIPT_ITEM(current_SID);
3157 si->sn_name = fname_exp;
3158 fname_exp = NULL;
3159# ifdef UNIX
3160 if (stat_ok)
3161 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003162 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003163 si->sn_dev = st.st_dev;
3164 si->sn_ino = st.st_ino;
3165 }
3166 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003167 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003168# endif
3169
Bram Moolenaar071d4272004-06-13 20:20:40 +00003170 /* Allocate the local script variables to use for this script. */
3171 new_script_vars(current_SID);
3172 }
3173
Bram Moolenaar05159a02005-02-26 23:04:13 +00003174# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003175 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003176 {
3177 int forceit;
3178
3179 /* Check if we do profiling for this script. */
3180 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3181 {
3182 script_do_profile(si);
3183 si->sn_pr_force = forceit;
3184 }
3185 if (si->sn_prof_on)
3186 {
3187 ++si->sn_pr_count;
3188 profile_start(&si->sn_pr_start);
3189 profile_zero(&si->sn_pr_children);
3190 }
3191 }
3192# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003193#endif
3194
3195 /*
3196 * Call do_cmdline, which will call getsourceline() to get the lines.
3197 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003198 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003199 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003200 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003201
3202#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003203 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003204 {
3205 /* Get "si" again, "script_items" may have been reallocated. */
3206 si = &SCRIPT_ITEM(current_SID);
3207 if (si->sn_prof_on)
3208 {
3209 profile_end(&si->sn_pr_start);
3210 profile_sub_wait(&wait_start, &si->sn_pr_start);
3211 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003212 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3213 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003214 }
3215 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216#endif
3217
3218 if (got_int)
3219 EMSG(_(e_interr));
3220 sourcing_name = save_sourcing_name;
3221 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003222 if (p_verbose > 1)
3223 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003224 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003225 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003227 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003228 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003229 }
3230#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003231 if (time_fd != NULL)
3232 {
3233 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3234 time_msg((char *)IObuff, &tv_start);
3235 time_pop(&tv_rel);
3236 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237#endif
3238
3239#ifdef FEAT_EVAL
3240 /*
3241 * After a "finish" in debug mode, need to break at first command of next
3242 * sourced file.
3243 */
3244 if (save_debug_break_level > ex_nesting_level
3245 && debug_break_level == ex_nesting_level)
3246 ++debug_break_level;
3247#endif
3248
Bram Moolenaar05159a02005-02-26 23:04:13 +00003249#ifdef FEAT_EVAL
3250almosttheend:
3251 current_SID = save_current_SID;
3252 restore_funccal(save_funccalp);
3253# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003254 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003255 prof_child_exit(&wait_start); /* leaving a child now */
3256# endif
3257#endif
3258 fclose(cookie.fp);
3259 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003260 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003261#ifdef FEAT_MBYTE
3262 convert_setup(&cookie.conv, NULL, NULL);
3263#endif
3264
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265theend:
3266 vim_free(fname_exp);
3267 return retval;
3268}
3269
3270#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003271
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272/*
3273 * ":scriptnames"
3274 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003275 void
3276ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003277 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278{
3279 int i;
3280
Bram Moolenaar05159a02005-02-26 23:04:13 +00003281 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3282 if (SCRIPT_ITEM(i).sn_name != NULL)
3283 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284}
3285
3286# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3287/*
3288 * Fix slashes in the list of script names for 'shellslash'.
3289 */
3290 void
3291scriptnames_slash_adjust()
3292{
3293 int i;
3294
Bram Moolenaar05159a02005-02-26 23:04:13 +00003295 for (i = 1; i <= script_items.ga_len; ++i)
3296 if (SCRIPT_ITEM(i).sn_name != NULL)
3297 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298}
3299# endif
3300
3301/*
3302 * Get a pointer to a script name. Used for ":verbose set".
3303 */
3304 char_u *
3305get_scriptname(id)
3306 scid_T id;
3307{
3308 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003309 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003310 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003311 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003313 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003315 return (char_u *)_("environment variable");
3316 if (id == SID_ERROR)
3317 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003318 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003320
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003321# if defined(EXITFREE) || defined(PROTO)
3322 void
3323free_scriptnames()
3324{
3325 int i;
3326
3327 for (i = script_items.ga_len; i > 0; --i)
3328 vim_free(SCRIPT_ITEM(i).sn_name);
3329 ga_clear(&script_items);
3330}
3331# endif
3332
Bram Moolenaar071d4272004-06-13 20:20:40 +00003333#endif
3334
3335#if defined(USE_CR) || defined(PROTO)
3336
3337# if defined(__MSL__) && (__MSL__ >= 22)
3338/*
3339 * Newer version of the Metrowerks library handle DOS and UNIX files
3340 * without help.
3341 * Test with earlier versions, MSL 2.2 is the library supplied with
3342 * Codewarrior Pro 2.
3343 */
3344 char *
3345fgets_cr(s, n, stream)
3346 char *s;
3347 int n;
3348 FILE *stream;
3349{
3350 return fgets(s, n, stream);
3351}
3352# else
3353/*
3354 * Version of fgets() which also works for lines ending in a <CR> only
3355 * (Macintosh format).
3356 * For older versions of the Metrowerks library.
3357 * At least CodeWarrior 9 needed this code.
3358 */
3359 char *
3360fgets_cr(s, n, stream)
3361 char *s;
3362 int n;
3363 FILE *stream;
3364{
3365 int c = 0;
3366 int char_read = 0;
3367
3368 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3369 {
3370 c = fgetc(stream);
3371 s[char_read++] = c;
3372 /* If the file is in DOS format, we need to skip a NL after a CR. I
3373 * thought it was the other way around, but this appears to work... */
3374 if (c == '\n')
3375 {
3376 c = fgetc(stream);
3377 if (c != '\r')
3378 ungetc(c, stream);
3379 }
3380 }
3381
3382 s[char_read] = 0;
3383 if (char_read == 0)
3384 return NULL;
3385
3386 if (feof(stream) && char_read == 1)
3387 return NULL;
3388
3389 return s;
3390}
3391# endif
3392#endif
3393
3394/*
3395 * Get one full line from a sourced file.
3396 * Called by do_cmdline() when it's called from do_source().
3397 *
3398 * Return a pointer to the line in allocated memory.
3399 * Return NULL for end-of-file or some error.
3400 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003401 char_u *
3402getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003403 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003404 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003405 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406{
3407 struct source_cookie *sp = (struct source_cookie *)cookie;
3408 char_u *line;
3409 char_u *p, *s;
3410
3411#ifdef FEAT_EVAL
3412 /* If breakpoints have been added/deleted need to check for it. */
3413 if (sp->dbg_tick < debug_tick)
3414 {
3415 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3416 sp->dbg_tick = debug_tick;
3417 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003418# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003419 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003420 script_line_end();
3421# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003422#endif
3423 /*
3424 * Get current line. If there is a read-ahead line, use it, otherwise get
3425 * one now.
3426 */
3427 if (sp->finished)
3428 line = NULL;
3429 else if (sp->nextline == NULL)
3430 line = get_one_sourceline(sp);
3431 else
3432 {
3433 line = sp->nextline;
3434 sp->nextline = NULL;
3435 ++sourcing_lnum;
3436 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003437#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003438 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003439 script_line_start();
3440#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441
3442 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3443 * contain the 'C' flag. */
3444 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3445 {
3446 /* compensate for the one line read-ahead */
3447 --sourcing_lnum;
3448 for (;;)
3449 {
3450 sp->nextline = get_one_sourceline(sp);
3451 if (sp->nextline == NULL)
3452 break;
3453 p = skipwhite(sp->nextline);
3454 if (*p != '\\')
3455 break;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00003456 s = alloc((unsigned)(STRLEN(line) + STRLEN(p)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003457 if (s == NULL) /* out of memory */
3458 break;
3459 STRCPY(s, line);
3460 STRCAT(s, p + 1);
3461 vim_free(line);
3462 line = s;
3463 vim_free(sp->nextline);
3464 }
3465 }
3466
3467#ifdef FEAT_MBYTE
3468 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3469 {
3470 /* Convert the encoding of the script line. */
3471 s = string_convert(&sp->conv, line, NULL);
3472 if (s != NULL)
3473 {
3474 vim_free(line);
3475 line = s;
3476 }
3477 }
3478#endif
3479
3480#ifdef FEAT_EVAL
3481 /* Did we encounter a breakpoint? */
3482 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3483 {
3484 dbg_breakpoint(sp->fname, sourcing_lnum);
3485 /* Find next breakpoint. */
3486 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3487 sp->dbg_tick = debug_tick;
3488 }
3489#endif
3490
3491 return line;
3492}
3493
3494 static char_u *
3495get_one_sourceline(sp)
3496 struct source_cookie *sp;
3497{
3498 garray_T ga;
3499 int len;
3500 int c;
3501 char_u *buf;
3502#ifdef USE_CRNL
3503 int has_cr; /* CR-LF found */
3504#endif
3505#ifdef USE_CR
3506 char_u *scan;
3507#endif
3508 int have_read = FALSE;
3509
3510 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003511 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003512
3513 /*
3514 * Loop until there is a finished line (or end-of-file).
3515 */
3516 sourcing_lnum++;
3517 for (;;)
3518 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003519 /* make room to read at least 120 (more) characters */
3520 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003521 break;
3522 buf = (char_u *)ga.ga_data;
3523
3524#ifdef USE_CR
3525 if (sp->fileformat == EOL_MAC)
3526 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003527 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3528 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529 break;
3530 }
3531 else
3532#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003533 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3534 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003535 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003536 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537#ifdef USE_CRNL
3538 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3539 * CTRL-Z by its own, or after a NL. */
3540 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3541 && sp->fileformat == EOL_DOS
3542 && buf[len - 1] == Ctrl_Z)
3543 {
3544 buf[len - 1] = NUL;
3545 break;
3546 }
3547#endif
3548
3549#ifdef USE_CR
3550 /* If the read doesn't stop on a new line, and there's
3551 * some CR then we assume a Mac format */
3552 if (sp->fileformat == EOL_UNKNOWN)
3553 {
3554 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3555 sp->fileformat = EOL_MAC;
3556 else
3557 sp->fileformat = EOL_UNIX;
3558 }
3559
3560 if (sp->fileformat == EOL_MAC)
3561 {
3562 scan = vim_strchr(buf, '\r');
3563
3564 if (scan != NULL)
3565 {
3566 *scan = '\n';
3567 if (*(scan + 1) != 0)
3568 {
3569 *(scan + 1) = 0;
3570 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3571 }
3572 }
3573 len = STRLEN(buf);
3574 }
3575#endif
3576
3577 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578 ga.ga_len = len;
3579
3580 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003581 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582 continue;
3583
3584 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3585 {
3586#ifdef USE_CRNL
3587 has_cr = (len >= 2 && buf[len - 2] == '\r');
3588 if (sp->fileformat == EOL_UNKNOWN)
3589 {
3590 if (has_cr)
3591 sp->fileformat = EOL_DOS;
3592 else
3593 sp->fileformat = EOL_UNIX;
3594 }
3595
3596 if (sp->fileformat == EOL_DOS)
3597 {
3598 if (has_cr) /* replace trailing CR */
3599 {
3600 buf[len - 2] = '\n';
3601 --len;
3602 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003603 }
3604 else /* lines like ":map xx yy^M" will have failed */
3605 {
3606 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003607 {
3608 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003609 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003610 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611 sp->error = TRUE;
3612 sp->fileformat = EOL_UNIX;
3613 }
3614 }
3615#endif
3616 /* The '\n' is escaped if there is an odd number of ^V's just
3617 * before it, first set "c" just before the 'V's and then check
3618 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3619 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3620 ;
3621 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3622 {
3623 sourcing_lnum++;
3624 continue;
3625 }
3626
3627 buf[len - 1] = NUL; /* remove the NL */
3628 }
3629
3630 /*
3631 * Check for ^C here now and then, so recursive :so can be broken.
3632 */
3633 line_breakcheck();
3634 break;
3635 }
3636
3637 if (have_read)
3638 return (char_u *)ga.ga_data;
3639
3640 vim_free(ga.ga_data);
3641 return NULL;
3642}
3643
Bram Moolenaar05159a02005-02-26 23:04:13 +00003644#if defined(FEAT_PROFILE) || defined(PROTO)
3645/*
3646 * Called when starting to read a script line.
3647 * "sourcing_lnum" must be correct!
3648 * When skipping lines it may not actually be executed, but we won't find out
3649 * until later and we need to store the time now.
3650 */
3651 void
3652script_line_start()
3653{
3654 scriptitem_T *si;
3655 sn_prl_T *pp;
3656
3657 if (current_SID <= 0 || current_SID > script_items.ga_len)
3658 return;
3659 si = &SCRIPT_ITEM(current_SID);
3660 if (si->sn_prof_on && sourcing_lnum >= 1)
3661 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003662 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003663 * here isn't counted. */
3664 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3665 si->sn_prl_idx = sourcing_lnum - 1;
3666 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3667 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3668 {
3669 /* Zero counters for a line that was not used before. */
3670 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3671 pp->snp_count = 0;
3672 profile_zero(&pp->sn_prl_total);
3673 profile_zero(&pp->sn_prl_self);
3674 ++si->sn_prl_ga.ga_len;
3675 }
3676 si->sn_prl_execed = FALSE;
3677 profile_start(&si->sn_prl_start);
3678 profile_zero(&si->sn_prl_children);
3679 profile_get_wait(&si->sn_prl_wait);
3680 }
3681}
3682
3683/*
3684 * Called when actually executing a function line.
3685 */
3686 void
3687script_line_exec()
3688{
3689 scriptitem_T *si;
3690
3691 if (current_SID <= 0 || current_SID > script_items.ga_len)
3692 return;
3693 si = &SCRIPT_ITEM(current_SID);
3694 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3695 si->sn_prl_execed = TRUE;
3696}
3697
3698/*
3699 * Called when done with a function line.
3700 */
3701 void
3702script_line_end()
3703{
3704 scriptitem_T *si;
3705 sn_prl_T *pp;
3706
3707 if (current_SID <= 0 || current_SID > script_items.ga_len)
3708 return;
3709 si = &SCRIPT_ITEM(current_SID);
3710 if (si->sn_prof_on && si->sn_prl_idx >= 0
3711 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3712 {
3713 if (si->sn_prl_execed)
3714 {
3715 pp = &PRL_ITEM(si, si->sn_prl_idx);
3716 ++pp->snp_count;
3717 profile_end(&si->sn_prl_start);
3718 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003719 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003720 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3721 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003722 }
3723 si->sn_prl_idx = -1;
3724 }
3725}
3726#endif
3727
Bram Moolenaar071d4272004-06-13 20:20:40 +00003728/*
3729 * ":scriptencoding": Set encoding conversion for a sourced script.
3730 * Without the multi-byte feature it's simply ignored.
3731 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732 void
3733ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003734 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735{
3736#ifdef FEAT_MBYTE
3737 struct source_cookie *sp;
3738 char_u *name;
3739
3740 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3741 {
3742 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3743 return;
3744 }
3745
3746 if (*eap->arg != NUL)
3747 {
3748 name = enc_canonize(eap->arg);
3749 if (name == NULL) /* out of memory */
3750 return;
3751 }
3752 else
3753 name = eap->arg;
3754
3755 /* Setup for conversion from the specified encoding to 'encoding'. */
3756 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3757 convert_setup(&sp->conv, name, p_enc);
3758
3759 if (name != eap->arg)
3760 vim_free(name);
3761#endif
3762}
3763
3764#if defined(FEAT_EVAL) || defined(PROTO)
3765/*
3766 * ":finish": Mark a sourced file as finished.
3767 */
3768 void
3769ex_finish(eap)
3770 exarg_T *eap;
3771{
3772 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3773 do_finish(eap, FALSE);
3774 else
3775 EMSG(_("E168: :finish used outside of a sourced file"));
3776}
3777
3778/*
3779 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3780 * Also called for a pending finish at the ":endtry" or after returning from
3781 * an extra do_cmdline(). "reanimate" is used in the latter case.
3782 */
3783 void
3784do_finish(eap, reanimate)
3785 exarg_T *eap;
3786 int reanimate;
3787{
3788 int idx;
3789
3790 if (reanimate)
3791 ((struct source_cookie *)getline_cookie(eap->getline,
3792 eap->cookie))->finished = FALSE;
3793
3794 /*
3795 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3796 * not in its finally clause (which then is to be executed next) is found.
3797 * In this case, make the ":finish" pending for execution at the ":endtry".
3798 * Otherwise, finish normally.
3799 */
3800 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3801 if (idx >= 0)
3802 {
3803 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3804 report_make_pending(CSTP_FINISH, NULL);
3805 }
3806 else
3807 ((struct source_cookie *)getline_cookie(eap->getline,
3808 eap->cookie))->finished = TRUE;
3809}
3810
3811
3812/*
3813 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3814 * message for missing ":endif".
3815 * Return FALSE when not sourcing a file.
3816 */
3817 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003818source_finished(fgetline, cookie)
3819 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 void *cookie;
3821{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003822 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003823 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003824 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825}
3826#endif
3827
3828#if defined(FEAT_LISTCMDS) || defined(PROTO)
3829/*
3830 * ":checktime [buffer]"
3831 */
3832 void
3833ex_checktime(eap)
3834 exarg_T *eap;
3835{
3836 buf_T *buf;
3837 int save_no_check_timestamps = no_check_timestamps;
3838
3839 no_check_timestamps = 0;
3840 if (eap->addr_count == 0) /* default is all buffers */
3841 check_timestamps(FALSE);
3842 else
3843 {
3844 buf = buflist_findnr((int)eap->line2);
3845 if (buf != NULL) /* cannot happen? */
3846 (void)buf_check_timestamp(buf, FALSE);
3847 }
3848 no_check_timestamps = save_no_check_timestamps;
3849}
3850#endif
3851
Bram Moolenaar071d4272004-06-13 20:20:40 +00003852#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3853 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003854# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003855static char *get_locale_val __ARGS((int what));
3856
3857 static char *
3858get_locale_val(what)
3859 int what;
3860{
3861 char *loc;
3862
3863 /* Obtain the locale value from the libraries. For DJGPP this is
3864 * redefined and it doesn't use the arguments. */
3865 loc = setlocale(what, NULL);
3866
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003867# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868 if (loc != NULL)
3869 {
3870 char_u *p;
3871
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003872 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3873 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 p = vim_strchr(loc, '=');
3875 if (p != NULL)
3876 {
3877 loc = ++p;
3878 while (*p != NUL) /* remove trailing newline */
3879 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003880 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 {
3882 *p = NUL;
3883 break;
3884 }
3885 ++p;
3886 }
3887 }
3888 }
3889# endif
3890
3891 return loc;
3892}
3893#endif
3894
3895
3896#ifdef WIN32
3897/*
3898 * On MS-Windows locale names are strings like "German_Germany.1252", but
3899 * gettext expects "de". Try to translate one into another here for a few
3900 * supported languages.
3901 */
3902 static char_u *
3903gettext_lang(char_u *name)
3904{
3905 int i;
3906 static char *(mtable[]) = {
3907 "afrikaans", "af",
3908 "czech", "cs",
3909 "dutch", "nl",
3910 "german", "de",
3911 "english_united kingdom", "en_GB",
3912 "spanish", "es",
3913 "french", "fr",
3914 "italian", "it",
3915 "japanese", "ja",
3916 "korean", "ko",
3917 "norwegian", "no",
3918 "polish", "pl",
3919 "russian", "ru",
3920 "slovak", "sk",
3921 "swedish", "sv",
3922 "ukrainian", "uk",
3923 "chinese_china", "zh_CN",
3924 "chinese_taiwan", "zh_TW",
3925 NULL};
3926
3927 for (i = 0; mtable[i] != NULL; i += 2)
3928 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3929 return mtable[i + 1];
3930 return name;
3931}
3932#endif
3933
3934#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3935/*
3936 * Obtain the current messages language. Used to set the default for
3937 * 'helplang'. May return NULL or an empty string.
3938 */
3939 char_u *
3940get_mess_lang()
3941{
3942 char_u *p;
3943
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003944# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003945# if defined(LC_MESSAGES)
3946 p = (char_u *)get_locale_val(LC_MESSAGES);
3947# else
3948 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003949 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3950 * and LC_MONETARY may be set differently for a Japanese working in the
3951 * US. */
3952 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003953# endif
3954# else
3955 p = mch_getenv((char_u *)"LC_ALL");
3956 if (p == NULL || *p == NUL)
3957 {
3958 p = mch_getenv((char_u *)"LC_MESSAGES");
3959 if (p == NULL || *p == NUL)
3960 p = mch_getenv((char_u *)"LANG");
3961 }
3962# endif
3963# ifdef WIN32
3964 p = gettext_lang(p);
3965# endif
3966 return p;
3967}
3968#endif
3969
Bram Moolenaardef9e822004-12-31 20:58:58 +00003970/* Complicated #if; matches with where get_mess_env() is used below. */
3971#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3972 && defined(LC_MESSAGES))) \
3973 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3974 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3975 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003976static char_u *get_mess_env __ARGS((void));
3977
3978/*
3979 * Get the language used for messages from the environment.
3980 */
3981 static char_u *
3982get_mess_env()
3983{
3984 char_u *p;
3985
3986 p = mch_getenv((char_u *)"LC_ALL");
3987 if (p == NULL || *p == NUL)
3988 {
3989 p = mch_getenv((char_u *)"LC_MESSAGES");
3990 if (p == NULL || *p == NUL)
3991 {
3992 p = mch_getenv((char_u *)"LANG");
3993 if (p != NULL && VIM_ISDIGIT(*p))
3994 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003995# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003996 if (p == NULL || *p == NUL)
3997 p = (char_u *)get_locale_val(LC_CTYPE);
3998# endif
3999 }
4000 }
4001 return p;
4002}
4003#endif
4004
4005#if defined(FEAT_EVAL) || defined(PROTO)
4006
4007/*
4008 * Set the "v:lang" variable according to the current locale setting.
4009 * Also do "v:lc_time"and "v:ctype".
4010 */
4011 void
4012set_lang_var()
4013{
4014 char_u *loc;
4015
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004016# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004017 loc = (char_u *)get_locale_val(LC_CTYPE);
4018# else
4019 /* setlocale() not supported: use the default value */
4020 loc = (char_u *)"C";
4021# endif
4022 set_vim_var_string(VV_CTYPE, loc, -1);
4023
4024 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4025 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004026# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027 loc = (char_u *)get_locale_val(LC_MESSAGES);
4028# else
4029 loc = get_mess_env();
4030# endif
4031 set_vim_var_string(VV_LANG, loc, -1);
4032
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004033# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004034 loc = (char_u *)get_locale_val(LC_TIME);
4035# endif
4036 set_vim_var_string(VV_LC_TIME, loc, -1);
4037}
4038#endif
4039
4040#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4041 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4042/*
4043 * ":language": Set the language (locale).
4044 */
4045 void
4046ex_language(eap)
4047 exarg_T *eap;
4048{
4049 char *loc;
4050 char_u *p;
4051 char_u *name;
4052 int what = LC_ALL;
4053 char *whatstr = "";
4054#ifdef LC_MESSAGES
4055# define VIM_LC_MESSAGES LC_MESSAGES
4056#else
4057# define VIM_LC_MESSAGES 6789
4058#endif
4059
4060 name = eap->arg;
4061
4062 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4063 * Allow abbreviation, but require at least 3 characters to avoid
4064 * confusion with a two letter language name "me" or "ct". */
4065 p = skiptowhite(eap->arg);
4066 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4067 {
4068 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4069 {
4070 what = VIM_LC_MESSAGES;
4071 name = skipwhite(p);
4072 whatstr = "messages ";
4073 }
4074 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4075 {
4076 what = LC_CTYPE;
4077 name = skipwhite(p);
4078 whatstr = "ctype ";
4079 }
4080 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4081 {
4082 what = LC_TIME;
4083 name = skipwhite(p);
4084 whatstr = "time ";
4085 }
4086 }
4087
4088 if (*name == NUL)
4089 {
4090#ifndef LC_MESSAGES
4091 if (what == VIM_LC_MESSAGES)
4092 p = get_mess_env();
4093 else
4094#endif
4095 p = (char_u *)setlocale(what, NULL);
4096 if (p == NULL || *p == NUL)
4097 p = (char_u *)"Unknown";
4098 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4099 }
4100 else
4101 {
4102#ifndef LC_MESSAGES
4103 if (what == VIM_LC_MESSAGES)
4104 loc = "";
4105 else
4106#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004107 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004109#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4110 /* Make sure strtod() uses a decimal point, not a comma. */
4111 setlocale(LC_NUMERIC, "C");
4112#endif
4113 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 if (loc == NULL)
4115 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4116 else
4117 {
4118#ifdef HAVE_NL_MSG_CAT_CNTR
4119 /* Need to do this for GNU gettext, otherwise cached translations
4120 * will be used again. */
4121 extern int _nl_msg_cat_cntr;
4122
4123 ++_nl_msg_cat_cntr;
4124#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004125 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4127
4128 if (what != LC_TIME)
4129 {
4130 /* Tell gettext() what to translate to. It apparently doesn't
4131 * use the currently effective locale. Also do this when
4132 * FEAT_GETTEXT isn't defined, so that shell commands use this
4133 * value. */
4134 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004135 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004136 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004137# ifdef WIN32
4138 /* Apparently MS-Windows printf() may cause a crash when
4139 * we give it 8-bit text while it's expecting text in the
4140 * current locale. This call avoids that. */
4141 setlocale(LC_CTYPE, "C");
4142# endif
4143 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004144 if (what != LC_CTYPE)
4145 {
4146 char_u *mname;
4147#ifdef WIN32
4148 mname = gettext_lang(name);
4149#else
4150 mname = name;
4151#endif
4152 vim_setenv((char_u *)"LC_MESSAGES", mname);
4153#ifdef FEAT_MULTI_LANG
4154 set_helplang_default(mname);
4155#endif
4156 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004157 }
4158
4159# ifdef FEAT_EVAL
4160 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4161 set_lang_var();
4162# endif
4163 }
4164 }
4165}
4166
4167# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4168/*
4169 * Function given to ExpandGeneric() to obtain the possible arguments of the
4170 * ":language" command.
4171 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172 char_u *
4173get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004174 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 int idx;
4176{
4177 if (idx == 0)
4178 return (char_u *)"messages";
4179 if (idx == 1)
4180 return (char_u *)"ctype";
4181 if (idx == 2)
4182 return (char_u *)"time";
4183 return NULL;
4184}
4185# endif
4186
4187#endif