blob: 0fe9b32f6c4a120ff74f5b639263f2f085686ce3 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
17static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
18
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
71
72/*
73 * do_debug(): Debug mode.
74 * Repeatedly get Ex commands, until told to continue normal execution.
75 */
76 void
77do_debug(cmd)
78 char_u *cmd;
79{
80 int save_msg_scroll = msg_scroll;
81 int save_State = State;
82 int save_did_emsg = did_emsg;
83 int save_cmd_silent = cmd_silent;
84 int save_msg_silent = msg_silent;
85 int save_emsg_silent = emsg_silent;
86 int save_redir_off = redir_off;
87 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000088 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000089 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000090# ifdef FEAT_EX_EXTRA
91 int save_ex_normal_busy;
92# endif
93 int n;
94 char_u *cmdline = NULL;
95 char_u *p;
96 char *tail = NULL;
97 static int last_cmd = 0;
98#define CMD_CONT 1
99#define CMD_NEXT 2
100#define CMD_STEP 3
101#define CMD_FINISH 4
102#define CMD_QUIT 5
103#define CMD_INTERRUPT 6
104
105#ifdef ALWAYS_USE_GUI
106 /* Can't do this when there is no terminal for input/output. */
107 if (!gui.in_use)
108 {
109 /* Break as soon as possible. */
110 debug_break_level = 9999;
111 return;
112 }
113#endif
114
115 /* Make sure we are in raw mode and start termcap mode. Might have side
116 * effects... */
117 settmode(TMODE_RAW);
118 starttermcap();
119
120 ++RedrawingDisabled; /* don't redisplay the window */
121 ++no_wait_return; /* don't wait for return */
122 did_emsg = FALSE; /* don't use error from debugged stuff */
123 cmd_silent = FALSE; /* display commands */
124 msg_silent = FALSE; /* display messages */
125 emsg_silent = FALSE; /* display error messages */
126 redir_off = TRUE; /* don't redirect debug commands */
127
128 State = NORMAL;
129#ifdef FEAT_SNIFF
130 want_sniff_request = 0; /* No K_SNIFF wanted */
131#endif
132
133 if (!debug_did_msg)
134 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
135 if (sourcing_name != NULL)
136 msg(sourcing_name);
137 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000138 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141
142 /*
143 * Repeat getting a command and executing it.
144 */
145 for (;;)
146 {
147 msg_scroll = TRUE;
148 need_wait_return = FALSE;
149#ifdef FEAT_SNIFF
150 ProcessSniffRequests();
151#endif
152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157# ifdef FEAT_EX_EXTRA
158 save_ex_normal_busy = ex_normal_busy;
159 ex_normal_busy = 0;
160# endif
161 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000164 typeahead_saved = TRUE;
165 save_ignore_script = ignore_script;
166 ignore_script = TRUE;
167 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000169 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000171 if (typeahead_saved)
172 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000174 ignore_script = save_ignore_script;
175 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176# ifdef FEAT_EX_EXTRA
177 ex_normal_busy = save_ex_normal_busy;
178# endif
179
180 cmdline_row = msg_row;
181 if (cmdline != NULL)
182 {
183 /* If this is a debug command, set "last_cmd".
184 * If not, reset "last_cmd".
185 * For a blank line use previous command. */
186 p = skipwhite(cmdline);
187 if (*p != NUL)
188 {
189 switch (*p)
190 {
191 case 'c': last_cmd = CMD_CONT;
192 tail = "ont";
193 break;
194 case 'n': last_cmd = CMD_NEXT;
195 tail = "ext";
196 break;
197 case 's': last_cmd = CMD_STEP;
198 tail = "tep";
199 break;
200 case 'f': last_cmd = CMD_FINISH;
201 tail = "inish";
202 break;
203 case 'q': last_cmd = CMD_QUIT;
204 tail = "uit";
205 break;
206 case 'i': last_cmd = CMD_INTERRUPT;
207 tail = "nterrupt";
208 break;
209 default: last_cmd = 0;
210 }
211 if (last_cmd != 0)
212 {
213 /* Check that the tail matches. */
214 ++p;
215 while (*p != NUL && *p == *tail)
216 {
217 ++p;
218 ++tail;
219 }
220 if (ASCII_ISALPHA(*p))
221 last_cmd = 0;
222 }
223 }
224
225 if (last_cmd != 0)
226 {
227 /* Execute debug command: decided where to break next and
228 * return. */
229 switch (last_cmd)
230 {
231 case CMD_CONT:
232 debug_break_level = -1;
233 break;
234 case CMD_NEXT:
235 debug_break_level = ex_nesting_level;
236 break;
237 case CMD_STEP:
238 debug_break_level = 9999;
239 break;
240 case CMD_FINISH:
241 debug_break_level = ex_nesting_level - 1;
242 break;
243 case CMD_QUIT:
244 got_int = TRUE;
245 debug_break_level = -1;
246 break;
247 case CMD_INTERRUPT:
248 got_int = TRUE;
249 debug_break_level = 9999;
250 /* Do not repeat ">interrupt" cmd, continue stepping. */
251 last_cmd = CMD_STEP;
252 break;
253 }
254 break;
255 }
256
257 /* don't debug this command */
258 n = debug_break_level;
259 debug_break_level = -1;
260 (void)do_cmdline(cmdline, getexline, NULL,
261 DOCMD_VERBOSE|DOCMD_EXCRESET);
262 debug_break_level = n;
263
264 vim_free(cmdline);
265 }
266 lines_left = Rows - 1;
267 }
268 vim_free(cmdline);
269
270 --RedrawingDisabled;
271 --no_wait_return;
272 redraw_all_later(NOT_VALID);
273 need_wait_return = FALSE;
274 msg_scroll = save_msg_scroll;
275 lines_left = Rows - 1;
276 State = save_State;
277 did_emsg = save_did_emsg;
278 cmd_silent = save_cmd_silent;
279 msg_silent = save_msg_silent;
280 emsg_silent = save_emsg_silent;
281 redir_off = save_redir_off;
282
283 /* Only print the message again when typing a command before coming back
284 * here. */
285 debug_did_msg = TRUE;
286}
287
288/*
289 * ":debug".
290 */
291 void
292ex_debug(eap)
293 exarg_T *eap;
294{
295 int debug_break_level_save = debug_break_level;
296
297 debug_break_level = 9999;
298 do_cmdline_cmd(eap->arg);
299 debug_break_level = debug_break_level_save;
300}
301
302static char_u *debug_breakpoint_name = NULL;
303static linenr_T debug_breakpoint_lnum;
304
305/*
306 * When debugging or a breakpoint is set on a skipped command, no debug prompt
307 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
308 * debug_skipped_name is then set to the source name in the breakpoint case. If
309 * a skipped command decides itself that a debug prompt should be displayed, it
310 * can do so by calling dbg_check_skipped().
311 */
312static int debug_skipped;
313static char_u *debug_skipped_name;
314
315/*
316 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
317 * at or below the break level. But only when the line is actually
318 * executed. Return TRUE and set breakpoint_name for skipped commands that
319 * decide to execute something themselves.
320 * Called from do_one_cmd() before executing a command.
321 */
322 void
323dbg_check_breakpoint(eap)
324 exarg_T *eap;
325{
326 char_u *p;
327
328 debug_skipped = FALSE;
329 if (debug_breakpoint_name != NULL)
330 {
331 if (!eap->skip)
332 {
333 /* replace K_SNR with "<SNR>" */
334 if (debug_breakpoint_name[0] == K_SPECIAL
335 && debug_breakpoint_name[1] == KS_EXTRA
336 && debug_breakpoint_name[2] == (int)KE_SNR)
337 p = (char_u *)"<SNR>";
338 else
339 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000340 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
341 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 debug_breakpoint_name + (*p == NUL ? 0 : 3),
343 (long)debug_breakpoint_lnum);
344 debug_breakpoint_name = NULL;
345 do_debug(eap->cmd);
346 }
347 else
348 {
349 debug_skipped = TRUE;
350 debug_skipped_name = debug_breakpoint_name;
351 debug_breakpoint_name = NULL;
352 }
353 }
354 else if (ex_nesting_level <= debug_break_level)
355 {
356 if (!eap->skip)
357 do_debug(eap->cmd);
358 else
359 {
360 debug_skipped = TRUE;
361 debug_skipped_name = NULL;
362 }
363 }
364}
365
366/*
367 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
368 * set. Return TRUE when the debug mode is entered this time.
369 */
370 int
371dbg_check_skipped(eap)
372 exarg_T *eap;
373{
374 int prev_got_int;
375
376 if (debug_skipped)
377 {
378 /*
379 * Save the value of got_int and reset it. We don't want a previous
380 * interruption cause flushing the input buffer.
381 */
382 prev_got_int = got_int;
383 got_int = FALSE;
384 debug_breakpoint_name = debug_skipped_name;
385 /* eap->skip is TRUE */
386 eap->skip = FALSE;
387 (void)dbg_check_breakpoint(eap);
388 eap->skip = TRUE;
389 got_int |= prev_got_int;
390 return TRUE;
391 }
392 return FALSE;
393}
394
395/*
396 * The list of breakpoints: dbg_breakp.
397 * This is a grow-array of structs.
398 */
399struct debuggy
400{
401 int dbg_nr; /* breakpoint number */
402 int dbg_type; /* DBG_FUNC or DBG_FILE */
403 char_u *dbg_name; /* function or file name */
404 regprog_T *dbg_prog; /* regexp program */
405 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000406 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407};
408
409static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000410#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
411#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412static int last_breakp = 0; /* nr of last defined breakpoint */
413
Bram Moolenaar05159a02005-02-26 23:04:13 +0000414#ifdef FEAT_PROFILE
415/* Profiling uses file and func names similar to breakpoints. */
416static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
417#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418#define DBG_FUNC 1
419#define DBG_FILE 2
420
Bram Moolenaar05159a02005-02-26 23:04:13 +0000421static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
422static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, garray_T *gap, int *fp));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423
424/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000425 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
426 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
427 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428 * Returns FAIL for failure.
429 */
430 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000431dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000433 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000434{
435 char_u *p = arg;
436 char_u *q;
437 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000438 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439
Bram Moolenaar05159a02005-02-26 23:04:13 +0000440 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000442 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443
444 /* Find "func" or "file". */
445 if (STRNCMP(p, "func", 4) == 0)
446 bp->dbg_type = DBG_FUNC;
447 else if (STRNCMP(p, "file", 4) == 0)
448 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000449 else if (
450#ifdef FEAT_PROFILE
451 gap != &prof_ga &&
452#endif
453 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000454 {
455 if (curbuf->b_ffname == NULL)
456 {
457 EMSG(_(e_noname));
458 return FAIL;
459 }
460 bp->dbg_type = DBG_FILE;
461 here = TRUE;
462 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463 else
464 {
465 EMSG2(_(e_invarg2), p);
466 return FAIL;
467 }
468 p = skipwhite(p + 4);
469
470 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000471 if (here)
472 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000473 else if (
474#ifdef FEAT_PROFILE
475 gap != &prof_ga &&
476#endif
477 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000478 {
479 bp->dbg_lnum = getdigits(&p);
480 p = skipwhite(p);
481 }
482 else
483 bp->dbg_lnum = 0;
484
485 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000486 if ((!here && *p == NUL)
487 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
489 {
490 EMSG2(_(e_invarg2), arg);
491 return FAIL;
492 }
493
494 if (bp->dbg_type == DBG_FUNC)
495 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000496 else if (here)
497 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 else
499 {
500 /* Expand the file name in the same way as do_source(). This means
501 * doing it twice, so that $DIR/file gets expanded when $DIR is
502 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 if (q == NULL)
505 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507 vim_free(q);
508 if (p == NULL)
509 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000510 if (*p != '*')
511 {
512 bp->dbg_name = fix_fname(p);
513 vim_free(p);
514 }
515 else
516 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517 }
518
519 if (bp->dbg_name == NULL)
520 return FAIL;
521 return OK;
522}
523
524/*
525 * ":breakadd".
526 */
527 void
528ex_breakadd(eap)
529 exarg_T *eap;
530{
531 struct debuggy *bp;
532 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534
Bram Moolenaar05159a02005-02-26 23:04:13 +0000535 gap = &dbg_breakp;
536#ifdef FEAT_PROFILE
537 if (eap->cmdidx == CMD_profile)
538 gap = &prof_ga;
539#endif
540
541 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000543 bp = &DEBUGGY(gap, gap->ga_len);
544 bp->dbg_forceit = eap->forceit;
545
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
547 if (pat != NULL)
548 {
549 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
550 vim_free(pat);
551 }
552 if (pat == NULL || bp->dbg_prog == NULL)
553 vim_free(bp->dbg_name);
554 else
555 {
556 if (bp->dbg_lnum == 0) /* default line number is 1 */
557 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000558#ifdef FEAT_PROFILE
559 if (eap->cmdidx != CMD_profile)
560#endif
561 {
562 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
563 ++debug_tick;
564 }
565 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 }
567 }
568}
569
570/*
571 * ":debuggreedy".
572 */
573 void
574ex_debuggreedy(eap)
575 exarg_T *eap;
576{
577 if (eap->addr_count == 0 || eap->line2 != 0)
578 debug_greedy = TRUE;
579 else
580 debug_greedy = FALSE;
581}
582
583/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000584 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585 */
586 void
587ex_breakdel(eap)
588 exarg_T *eap;
589{
590 struct debuggy *bp, *bpi;
591 int nr;
592 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000593 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 int i;
595 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000596 garray_T *gap;
597
598 gap = &dbg_breakp;
599#ifdef FEAT_PROFILE
600 if (eap->cmdidx == CMD_profdel)
601 gap = &prof_ga;
602#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603
604 if (vim_isdigit(*eap->arg))
605 {
606 /* ":breakdel {nr}" */
607 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000608 for (i = 0; i < gap->ga_len; ++i)
609 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610 {
611 todel = i;
612 break;
613 }
614 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000615 else if (*eap->arg == '*')
616 {
617 todel = 0;
618 del_all = TRUE;
619 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620 else
621 {
622 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000623 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000625 bp = &DEBUGGY(gap, gap->ga_len);
626 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000628 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629 if (bp->dbg_type == bpi->dbg_type
630 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
631 && (bp->dbg_lnum == bpi->dbg_lnum
632 || (bp->dbg_lnum == 0
633 && (best_lnum == 0
634 || bpi->dbg_lnum < best_lnum))))
635 {
636 todel = i;
637 best_lnum = bpi->dbg_lnum;
638 }
639 }
640 vim_free(bp->dbg_name);
641 }
642
643 if (todel < 0)
644 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
645 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000646 {
647 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000648 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000649 vim_free(DEBUGGY(gap, todel).dbg_name);
650 vim_free(DEBUGGY(gap, todel).dbg_prog);
651 --gap->ga_len;
652 if (todel < gap->ga_len)
653 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
654 (gap->ga_len - todel) * sizeof(struct debuggy));
655#ifdef FEAT_PROFILE
656 if (eap->cmdidx == CMD_breakdel)
657#endif
658 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000659 if (!del_all)
660 break;
661 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000662
663 /* If all breakpoints were removed clear the array. */
664 if (gap->ga_len == 0)
665 ga_clear(gap);
666 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667}
668
669/*
670 * ":breaklist".
671 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 void
673ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000674 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675{
676 struct debuggy *bp;
677 int i;
678
679 if (dbg_breakp.ga_len == 0)
680 MSG(_("No breakpoints defined"));
681 else
682 for (i = 0; i < dbg_breakp.ga_len; ++i)
683 {
684 bp = &BREAKP(i);
685 smsg((char_u *)_("%3d %s %s line %ld"),
686 bp->dbg_nr,
687 bp->dbg_type == DBG_FUNC ? "func" : "file",
688 bp->dbg_name,
689 (long)bp->dbg_lnum);
690 }
691}
692
693/*
694 * Find a breakpoint for a function or sourced file.
695 * Returns line number at which to break; zero when no matching breakpoint.
696 */
697 linenr_T
698dbg_find_breakpoint(file, fname, after)
699 int file; /* TRUE for a file, FALSE for a function */
700 char_u *fname; /* file or function name */
701 linenr_T after; /* after this line number */
702{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000703 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
704}
705
706#if defined(FEAT_PROFILE) || defined(PROTO)
707/*
708 * Return TRUE if profiling is on for a function or sourced file.
709 */
710 int
711has_profiling(file, fname, fp)
712 int file; /* TRUE for a file, FALSE for a function */
713 char_u *fname; /* file or function name */
714 int *fp; /* return: forceit */
715{
716 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
717 != (linenr_T)0);
718}
719#endif
720
721/*
722 * Common code for dbg_find_breakpoint() and has_profiling().
723 */
724 static linenr_T
725debuggy_find(file, fname, after, gap, fp)
726 int file; /* TRUE for a file, FALSE for a function */
727 char_u *fname; /* file or function name */
728 linenr_T after; /* after this line number */
729 garray_T *gap; /* either &dbg_breakp or &prof_ga */
730 int *fp; /* if not NULL: return forceit */
731{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732 struct debuggy *bp;
733 int i;
734 linenr_T lnum = 0;
735 regmatch_T regmatch;
736 char_u *name = fname;
737 int prev_got_int;
738
Bram Moolenaar05159a02005-02-26 23:04:13 +0000739 /* Return quickly when there are no breakpoints. */
740 if (gap->ga_len == 0)
741 return (linenr_T)0;
742
Bram Moolenaar071d4272004-06-13 20:20:40 +0000743 /* Replace K_SNR in function name with "<SNR>". */
744 if (!file && fname[0] == K_SPECIAL)
745 {
746 name = alloc((unsigned)STRLEN(fname) + 3);
747 if (name == NULL)
748 name = fname;
749 else
750 {
751 STRCPY(name, "<SNR>");
752 STRCPY(name + 5, fname + 3);
753 }
754 }
755
Bram Moolenaar05159a02005-02-26 23:04:13 +0000756 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000758 /* Skip entries that are not useful or are for a line that is beyond
759 * an already found breakpoint. */
760 bp = &DEBUGGY(gap, i);
761 if (((bp->dbg_type == DBG_FILE) == file && (
762#ifdef FEAT_PROFILE
763 gap == &prof_ga ||
764#endif
765 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766 {
767 regmatch.regprog = bp->dbg_prog;
768 regmatch.rm_ic = FALSE;
769 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000770 * Save the value of got_int and reset it. We don't want a
771 * previous interruption cancel matching, only hitting CTRL-C
772 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 */
774 prev_got_int = got_int;
775 got_int = FALSE;
776 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000777 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000779 if (fp != NULL)
780 *fp = bp->dbg_forceit;
781 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 got_int |= prev_got_int;
783 }
784 }
785 if (name != fname)
786 vim_free(name);
787
788 return lnum;
789}
790
791/*
792 * Called when a breakpoint was encountered.
793 */
794 void
795dbg_breakpoint(name, lnum)
796 char_u *name;
797 linenr_T lnum;
798{
799 /* We need to check if this line is actually executed in do_one_cmd() */
800 debug_breakpoint_name = name;
801 debug_breakpoint_lnum = lnum;
802}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000803
804
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000805# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000806/*
807 * Store the current time in "tm".
808 */
809 void
810profile_start(tm)
811 proftime_T *tm;
812{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000813# ifdef WIN3264
814 QueryPerformanceCounter(tm);
815# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000816 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000817# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000818}
819
820/*
821 * Compute the elapsed time from "tm" till now and store in "tm".
822 */
823 void
824profile_end(tm)
825 proftime_T *tm;
826{
827 proftime_T now;
828
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000829# ifdef WIN3264
830 QueryPerformanceCounter(&now);
831 tm->QuadPart = now.QuadPart - tm->QuadPart;
832# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000833 gettimeofday(&now, NULL);
834 tm->tv_usec = now.tv_usec - tm->tv_usec;
835 tm->tv_sec = now.tv_sec - tm->tv_sec;
836 if (tm->tv_usec < 0)
837 {
838 tm->tv_usec += 1000000;
839 --tm->tv_sec;
840 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000841# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000842}
843
844/*
845 * Subtract the time "tm2" from "tm".
846 */
847 void
848profile_sub(tm, tm2)
849 proftime_T *tm, *tm2;
850{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000851# ifdef WIN3264
852 tm->QuadPart -= tm2->QuadPart;
853# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000854 tm->tv_usec -= tm2->tv_usec;
855 tm->tv_sec -= tm2->tv_sec;
856 if (tm->tv_usec < 0)
857 {
858 tm->tv_usec += 1000000;
859 --tm->tv_sec;
860 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000861# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000862}
863
864/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000865 * Return a string that represents the time in "tm".
866 * Uses a static buffer!
867 */
868 char *
869profile_msg(tm)
870 proftime_T *tm;
871{
872 static char buf[50];
873
874# ifdef WIN3264
875 LARGE_INTEGER fr;
876
877 QueryPerformanceFrequency(&fr);
878 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
879# else
880 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000881# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000882 return buf;
883}
884
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000885/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000886 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000887 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000888 void
889profile_setlimit(msec, tm)
890 long msec;
891 proftime_T *tm;
892{
893 if (msec <= 0) /* no limit */
894 profile_zero(tm);
895 else
896 {
897# ifdef WIN3264
898 LARGE_INTEGER fr;
899
900 QueryPerformanceCounter(tm);
901 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000902 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000903# else
904 long usec;
905
906 gettimeofday(tm, NULL);
907 usec = (long)tm->tv_usec + (long)msec * 1000;
908 tm->tv_usec = usec % 1000000L;
909 tm->tv_sec += usec / 1000000L;
910# endif
911 }
912}
913
914/*
915 * Return TRUE if the current time is past "tm".
916 */
917 int
918profile_passed_limit(tm)
919 proftime_T *tm;
920{
921 proftime_T now;
922
923# ifdef WIN3264
924 if (tm->QuadPart == 0) /* timer was not set */
925 return FALSE;
926 QueryPerformanceCounter(&now);
927 return (now.QuadPart > tm->QuadPart);
928# else
929 if (tm->tv_sec == 0) /* timer was not set */
930 return FALSE;
931 gettimeofday(&now, NULL);
932 return (now.tv_sec > tm->tv_sec
933 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
934# endif
935}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000936
937/*
938 * Set the time in "tm" to zero.
939 */
940 void
941profile_zero(tm)
942 proftime_T *tm;
943{
944# ifdef WIN3264
945 tm->QuadPart = 0;
946# else
947 tm->tv_usec = 0;
948 tm->tv_sec = 0;
949# endif
950}
951
Bram Moolenaar76929292008-01-06 19:07:36 +0000952# endif /* FEAT_PROFILE || FEAT_RELTIME */
953
954# if defined(FEAT_PROFILE) || defined(PROTO)
955/*
956 * Functions for profiling.
957 */
958static void script_do_profile __ARGS((scriptitem_T *si));
959static void script_dump_profile __ARGS((FILE *fd));
960static proftime_T prof_wait_time;
961
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000962/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000963 * Add the time "tm2" to "tm".
964 */
965 void
966profile_add(tm, tm2)
967 proftime_T *tm, *tm2;
968{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000969# ifdef WIN3264
970 tm->QuadPart += tm2->QuadPart;
971# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000972 tm->tv_usec += tm2->tv_usec;
973 tm->tv_sec += tm2->tv_sec;
974 if (tm->tv_usec >= 1000000)
975 {
976 tm->tv_usec -= 1000000;
977 ++tm->tv_sec;
978 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000979# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000980}
981
982/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000983 * Add the "self" time from the total time and the children's time.
984 */
985 void
986profile_self(self, total, children)
987 proftime_T *self, *total, *children;
988{
989 /* Check that the result won't be negative. Can happen with recursive
990 * calls. */
991#ifdef WIN3264
992 if (total->QuadPart <= children->QuadPart)
993 return;
994#else
995 if (total->tv_sec < children->tv_sec
996 || (total->tv_sec == children->tv_sec
997 && total->tv_usec <= children->tv_usec))
998 return;
999#endif
1000 profile_add(self, total);
1001 profile_sub(self, children);
1002}
1003
1004/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001005 * Get the current waittime.
1006 */
1007 void
1008profile_get_wait(tm)
1009 proftime_T *tm;
1010{
1011 *tm = prof_wait_time;
1012}
1013
1014/*
1015 * Subtract the passed waittime since "tm" from "tma".
1016 */
1017 void
1018profile_sub_wait(tm, tma)
1019 proftime_T *tm, *tma;
1020{
1021 proftime_T tm3 = prof_wait_time;
1022
1023 profile_sub(&tm3, tm);
1024 profile_sub(tma, &tm3);
1025}
1026
1027/*
1028 * Return TRUE if "tm1" and "tm2" are equal.
1029 */
1030 int
1031profile_equal(tm1, tm2)
1032 proftime_T *tm1, *tm2;
1033{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001034# ifdef WIN3264
1035 return (tm1->QuadPart == tm2->QuadPart);
1036# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001037 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001038# endif
1039}
1040
1041/*
1042 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1043 */
1044 int
1045profile_cmp(tm1, tm2)
1046 proftime_T *tm1, *tm2;
1047{
1048# ifdef WIN3264
1049 return (int)(tm2->QuadPart - tm1->QuadPart);
1050# else
1051 if (tm1->tv_sec == tm2->tv_sec)
1052 return tm2->tv_usec - tm1->tv_usec;
1053 return tm2->tv_sec - tm1->tv_sec;
1054# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001055}
1056
Bram Moolenaar05159a02005-02-26 23:04:13 +00001057static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001058static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001059
1060/*
1061 * ":profile cmd args"
1062 */
1063 void
1064ex_profile(eap)
1065 exarg_T *eap;
1066{
1067 char_u *e;
1068 int len;
1069
1070 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001071 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001072 e = skipwhite(e);
1073
1074 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1075 {
1076 vim_free(profile_fname);
1077 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001078 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001079 profile_zero(&prof_wait_time);
1080 set_vim_var_nr(VV_PROFILING, 1L);
1081 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001082 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001083 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001084 else if (STRCMP(eap->arg, "pause") == 0)
1085 {
1086 if (do_profiling == PROF_YES)
1087 profile_start(&pause_time);
1088 do_profiling = PROF_PAUSED;
1089 }
1090 else if (STRCMP(eap->arg, "continue") == 0)
1091 {
1092 if (do_profiling == PROF_PAUSED)
1093 {
1094 profile_end(&pause_time);
1095 profile_add(&prof_wait_time, &pause_time);
1096 }
1097 do_profiling = PROF_YES;
1098 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001099 else
1100 {
1101 /* The rest is similar to ":breakadd". */
1102 ex_breakadd(eap);
1103 }
1104}
1105
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001106/* Command line expansion for :profile. */
1107static enum
1108{
1109 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001110 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001111} pexpand_what;
1112
1113static char *pexpand_cmds[] = {
1114 "start",
1115#define PROFCMD_START 0
1116 "pause",
1117#define PROFCMD_PAUSE 1
1118 "continue",
1119#define PROFCMD_CONTINUE 2
1120 "func",
1121#define PROFCMD_FUNC 3
1122 "file",
1123#define PROFCMD_FILE 4
1124 NULL
1125#define PROFCMD_LAST 5
1126};
1127
1128/*
1129 * Function given to ExpandGeneric() to obtain the profile command
1130 * specific expansion.
1131 */
1132 char_u *
1133get_profile_name(xp, idx)
1134 expand_T *xp UNUSED;
1135 int idx;
1136{
1137 switch (pexpand_what)
1138 {
1139 case PEXP_SUBCMD:
1140 return (char_u *)pexpand_cmds[idx];
1141 /* case PEXP_FUNC: TODO */
1142 default:
1143 return NULL;
1144 }
1145}
1146
1147/*
1148 * Handle command line completion for :profile command.
1149 */
1150 void
1151set_context_in_profile_cmd(xp, arg)
1152 expand_T *xp;
1153 char_u *arg;
1154{
1155 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001156
1157 /* Default: expand subcommands. */
1158 xp->xp_context = EXPAND_PROFILE;
1159 pexpand_what = PEXP_SUBCMD;
1160 xp->xp_pattern = arg;
1161
1162 end_subcmd = skiptowhite(arg);
1163 if (*end_subcmd == NUL)
1164 return;
1165
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001166 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001167 {
1168 xp->xp_context = EXPAND_FILES;
1169 xp->xp_pattern = skipwhite(end_subcmd);
1170 return;
1171 }
1172
1173 /* TODO: expand function names after "func" */
1174 xp->xp_context = EXPAND_NOTHING;
1175}
1176
Bram Moolenaar05159a02005-02-26 23:04:13 +00001177/*
1178 * Dump the profiling info.
1179 */
1180 void
1181profile_dump()
1182{
1183 FILE *fd;
1184
1185 if (profile_fname != NULL)
1186 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001187 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001188 if (fd == NULL)
1189 EMSG2(_(e_notopen), profile_fname);
1190 else
1191 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001192 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001193 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001194 fclose(fd);
1195 }
1196 }
1197}
1198
1199/*
1200 * Start profiling script "fp".
1201 */
1202 static void
1203script_do_profile(si)
1204 scriptitem_T *si;
1205{
1206 si->sn_pr_count = 0;
1207 profile_zero(&si->sn_pr_total);
1208 profile_zero(&si->sn_pr_self);
1209
1210 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1211 si->sn_prl_idx = -1;
1212 si->sn_prof_on = TRUE;
1213 si->sn_pr_nest = 0;
1214}
1215
1216/*
1217 * save time when starting to invoke another script or function.
1218 */
1219 void
1220script_prof_save(tm)
1221 proftime_T *tm; /* place to store wait time */
1222{
1223 scriptitem_T *si;
1224
1225 if (current_SID > 0 && current_SID <= script_items.ga_len)
1226 {
1227 si = &SCRIPT_ITEM(current_SID);
1228 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1229 profile_start(&si->sn_pr_child);
1230 }
1231 profile_get_wait(tm);
1232}
1233
1234/*
1235 * Count time spent in children after invoking another script or function.
1236 */
1237 void
1238script_prof_restore(tm)
1239 proftime_T *tm;
1240{
1241 scriptitem_T *si;
1242
1243 if (current_SID > 0 && current_SID <= script_items.ga_len)
1244 {
1245 si = &SCRIPT_ITEM(current_SID);
1246 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1247 {
1248 profile_end(&si->sn_pr_child);
1249 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1250 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1251 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1252 }
1253 }
1254}
1255
1256static proftime_T inchar_time;
1257
1258/*
1259 * Called when starting to wait for the user to type a character.
1260 */
1261 void
1262prof_inchar_enter()
1263{
1264 profile_start(&inchar_time);
1265}
1266
1267/*
1268 * Called when finished waiting for the user to type a character.
1269 */
1270 void
1271prof_inchar_exit()
1272{
1273 profile_end(&inchar_time);
1274 profile_add(&prof_wait_time, &inchar_time);
1275}
1276
1277/*
1278 * Dump the profiling results for all scripts in file "fd".
1279 */
1280 static void
1281script_dump_profile(fd)
1282 FILE *fd;
1283{
1284 int id;
1285 scriptitem_T *si;
1286 int i;
1287 FILE *sfd;
1288 sn_prl_T *pp;
1289
1290 for (id = 1; id <= script_items.ga_len; ++id)
1291 {
1292 si = &SCRIPT_ITEM(id);
1293 if (si->sn_prof_on)
1294 {
1295 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1296 if (si->sn_pr_count == 1)
1297 fprintf(fd, "Sourced 1 time\n");
1298 else
1299 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1300 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1301 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1302 fprintf(fd, "\n");
1303 fprintf(fd, "count total (s) self (s)\n");
1304
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001305 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001306 if (sfd == NULL)
1307 fprintf(fd, "Cannot open file!\n");
1308 else
1309 {
1310 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1311 {
1312 if (vim_fgets(IObuff, IOSIZE, sfd))
1313 break;
1314 pp = &PRL_ITEM(si, i);
1315 if (pp->snp_count > 0)
1316 {
1317 fprintf(fd, "%5d ", pp->snp_count);
1318 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1319 fprintf(fd, " ");
1320 else
1321 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1322 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1323 }
1324 else
1325 fprintf(fd, " ");
1326 fprintf(fd, "%s", IObuff);
1327 }
1328 fclose(sfd);
1329 }
1330 fprintf(fd, "\n");
1331 }
1332 }
1333}
1334
1335/*
1336 * Return TRUE when a function defined in the current script should be
1337 * profiled.
1338 */
1339 int
1340prof_def_func()
1341{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001342 if (current_SID > 0)
1343 return SCRIPT_ITEM(current_SID).sn_pr_force;
1344 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001345}
1346
1347# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001348#endif
1349
1350/*
1351 * If 'autowrite' option set, try to write the file.
1352 * Careful: autocommands may make "buf" invalid!
1353 *
1354 * return FAIL for failure, OK otherwise
1355 */
1356 int
1357autowrite(buf, forceit)
1358 buf_T *buf;
1359 int forceit;
1360{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001361 int r;
1362
Bram Moolenaar071d4272004-06-13 20:20:40 +00001363 if (!(p_aw || p_awa) || !p_write
1364#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001365 /* never autowrite a "nofile" or "nowrite" buffer */
1366 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001367#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001368 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001369 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001370 r = buf_write_all(buf, forceit);
1371
1372 /* Writing may succeed but the buffer still changed, e.g., when there is a
1373 * conversion error. We do want to return FAIL then. */
1374 if (buf_valid(buf) && bufIsChanged(buf))
1375 r = FAIL;
1376 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001377}
1378
1379/*
1380 * flush all buffers, except the ones that are readonly
1381 */
1382 void
1383autowrite_all()
1384{
1385 buf_T *buf;
1386
1387 if (!(p_aw || p_awa) || !p_write)
1388 return;
1389 for (buf = firstbuf; buf; buf = buf->b_next)
1390 if (bufIsChanged(buf) && !buf->b_p_ro)
1391 {
1392 (void)buf_write_all(buf, FALSE);
1393#ifdef FEAT_AUTOCMD
1394 /* an autocommand may have deleted the buffer */
1395 if (!buf_valid(buf))
1396 buf = firstbuf;
1397#endif
1398 }
1399}
1400
1401/*
1402 * return TRUE if buffer was changed and cannot be abandoned.
1403 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001404 int
1405check_changed(buf, checkaw, mult_win, forceit, allbuf)
1406 buf_T *buf;
1407 int checkaw; /* do autowrite if buffer was changed */
1408 int mult_win; /* check also when several wins for the buf */
1409 int forceit;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001410 int allbuf UNUSED; /* may write all buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001411{
1412 if ( !forceit
1413 && bufIsChanged(buf)
1414 && (mult_win || buf->b_nwindows <= 1)
1415 && (!checkaw || autowrite(buf, forceit) == FAIL))
1416 {
1417#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1418 if ((p_confirm || cmdmod.confirm) && p_write)
1419 {
1420 buf_T *buf2;
1421 int count = 0;
1422
1423 if (allbuf)
1424 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1425 if (bufIsChanged(buf2)
1426 && (buf2->b_ffname != NULL
1427# ifdef FEAT_BROWSE
1428 || cmdmod.browse
1429# endif
1430 ))
1431 ++count;
1432# ifdef FEAT_AUTOCMD
1433 if (!buf_valid(buf))
1434 /* Autocommand deleted buffer, oops! It's not changed now. */
1435 return FALSE;
1436# endif
1437 dialog_changed(buf, count > 1);
1438# ifdef FEAT_AUTOCMD
1439 if (!buf_valid(buf))
1440 /* Autocommand deleted buffer, oops! It's not changed now. */
1441 return FALSE;
1442# endif
1443 return bufIsChanged(buf);
1444 }
1445#endif
1446 EMSG(_(e_nowrtmsg));
1447 return TRUE;
1448 }
1449 return FALSE;
1450}
1451
1452#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1453
1454#if defined(FEAT_BROWSE) || defined(PROTO)
1455/*
1456 * When wanting to write a file without a file name, ask the user for a name.
1457 */
1458 void
1459browse_save_fname(buf)
1460 buf_T *buf;
1461{
1462 if (buf->b_fname == NULL)
1463 {
1464 char_u *fname;
1465
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001466 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1467 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001468 if (fname != NULL)
1469 {
1470 if (setfname(buf, fname, NULL, TRUE) == OK)
1471 buf->b_flags |= BF_NOTEDITED;
1472 vim_free(fname);
1473 }
1474 }
1475}
1476#endif
1477
1478/*
1479 * Ask the user what to do when abondoning a changed buffer.
1480 * Must check 'write' option first!
1481 */
1482 void
1483dialog_changed(buf, checkall)
1484 buf_T *buf;
1485 int checkall; /* may abandon all changed buffers */
1486{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001487 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001488 int ret;
1489 buf_T *buf2;
1490
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001491 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001492 (buf->b_fname != NULL) ?
1493 buf->b_fname : (char_u *)_("Untitled"));
1494 if (checkall)
1495 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1496 else
1497 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1498
1499 if (ret == VIM_YES)
1500 {
1501#ifdef FEAT_BROWSE
1502 /* May get file name, when there is none */
1503 browse_save_fname(buf);
1504#endif
1505 if (buf->b_fname != NULL) /* didn't hit Cancel */
1506 (void)buf_write_all(buf, FALSE);
1507 }
1508 else if (ret == VIM_NO)
1509 {
1510 unchanged(buf, TRUE);
1511 }
1512 else if (ret == VIM_ALL)
1513 {
1514 /*
1515 * Write all modified files that can be written.
1516 * Skip readonly buffers, these need to be confirmed
1517 * individually.
1518 */
1519 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1520 {
1521 if (bufIsChanged(buf2)
1522 && (buf2->b_ffname != NULL
1523#ifdef FEAT_BROWSE
1524 || cmdmod.browse
1525#endif
1526 )
1527 && !buf2->b_p_ro)
1528 {
1529#ifdef FEAT_BROWSE
1530 /* May get file name, when there is none */
1531 browse_save_fname(buf2);
1532#endif
1533 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1534 (void)buf_write_all(buf2, FALSE);
1535#ifdef FEAT_AUTOCMD
1536 /* an autocommand may have deleted the buffer */
1537 if (!buf_valid(buf2))
1538 buf2 = firstbuf;
1539#endif
1540 }
1541 }
1542 }
1543 else if (ret == VIM_DISCARDALL)
1544 {
1545 /*
1546 * mark all buffers as unchanged
1547 */
1548 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1549 unchanged(buf2, TRUE);
1550 }
1551}
1552#endif
1553
1554/*
1555 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1556 * hidden, autowriting it or unloading it.
1557 */
1558 int
1559can_abandon(buf, forceit)
1560 buf_T *buf;
1561 int forceit;
1562{
1563 return ( P_HID(buf)
1564 || !bufIsChanged(buf)
1565 || buf->b_nwindows > 1
1566 || autowrite(buf, forceit) == OK
1567 || forceit);
1568}
1569
1570/*
1571 * Return TRUE if any buffer was changed and cannot be abandoned.
1572 * That changed buffer becomes the current buffer.
1573 */
1574 int
1575check_changed_any(hidden)
1576 int hidden; /* Only check hidden buffers */
1577{
1578 buf_T *buf;
1579 int save;
1580#ifdef FEAT_WINDOWS
1581 win_T *wp;
1582#endif
1583
1584 for (;;)
1585 {
1586 /* check curbuf first: if it was changed we can't abandon it */
1587 if (!hidden && curbufIsChanged())
1588 buf = curbuf;
1589 else
1590 {
1591 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1592 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1593 break;
1594 }
1595 if (buf == NULL) /* No buffers changed */
1596 return FALSE;
1597
Bram Moolenaar373154b2007-02-13 05:19:30 +00001598 /* Try auto-writing the buffer. If this fails but the buffer no
1599 * longer exists it's not changed, that's OK. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001600 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1601 break; /* didn't save - still changes */
1602 }
1603
1604 exiting = FALSE;
1605#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1606 /*
1607 * When ":confirm" used, don't give an error message.
1608 */
1609 if (!(p_confirm || cmdmod.confirm))
1610#endif
1611 {
1612 /* There must be a wait_return for this message, do_buffer()
1613 * may cause a redraw. But wait_return() is a no-op when vgetc()
1614 * is busy (Quit used from window menu), then make sure we don't
1615 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001616 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617 {
1618 msg_row = cmdline_row;
1619 msg_col = 0;
1620 msg_didout = FALSE;
1621 }
1622 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1623 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1624 buf->b_fname))
1625 {
1626 save = no_wait_return;
1627 no_wait_return = FALSE;
1628 wait_return(FALSE);
1629 no_wait_return = save;
1630 }
1631 }
1632
1633#ifdef FEAT_WINDOWS
1634 /* Try to find a window that contains the buffer. */
1635 if (buf != curbuf)
1636 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1637 if (wp->w_buffer == buf)
1638 {
1639 win_goto(wp);
1640# ifdef FEAT_AUTOCMD
1641 /* Paranoia: did autocms wipe out the buffer with changes? */
1642 if (!buf_valid(buf))
1643 return TRUE;
1644# endif
1645 break;
1646 }
1647#endif
1648
1649 /* Open the changed buffer in the current window. */
1650 if (buf != curbuf)
1651 set_curbuf(buf, DOBUF_GOTO);
1652
1653 return TRUE;
1654}
1655
1656/*
1657 * return FAIL if there is no file name, OK if there is one
1658 * give error message for FAIL
1659 */
1660 int
1661check_fname()
1662{
1663 if (curbuf->b_ffname == NULL)
1664 {
1665 EMSG(_(e_noname));
1666 return FAIL;
1667 }
1668 return OK;
1669}
1670
1671/*
1672 * flush the contents of a buffer, unless it has no file name
1673 *
1674 * return FAIL for failure, OK otherwise
1675 */
1676 int
1677buf_write_all(buf, forceit)
1678 buf_T *buf;
1679 int forceit;
1680{
1681 int retval;
1682#ifdef FEAT_AUTOCMD
1683 buf_T *old_curbuf = curbuf;
1684#endif
1685
1686 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1687 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1688 FALSE, forceit, TRUE, FALSE));
1689#ifdef FEAT_AUTOCMD
1690 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001691 {
1692 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001694 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001695#endif
1696 return retval;
1697}
1698
1699/*
1700 * Code to handle the argument list.
1701 */
1702
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001703static char_u *do_one_arg __ARGS((char_u *str));
1704static int do_arglist __ARGS((char_u *str, int what, int after));
1705static void alist_check_arg_idx __ARGS((void));
1706static int editing_arg_idx __ARGS((win_T *win));
1707#ifdef FEAT_LISTCMDS
1708static int alist_add_list __ARGS((int count, char_u **files, int after));
1709#endif
1710#define AL_SET 1
1711#define AL_ADD 2
1712#define AL_DEL 3
1713
Bram Moolenaar071d4272004-06-13 20:20:40 +00001714/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001715 * Isolate one argument, taking backticks.
1716 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001717 * Return a pointer to the start of the next argument.
1718 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001719 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720do_one_arg(str)
1721 char_u *str;
1722{
1723 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 int inbacktick;
1725
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726 inbacktick = FALSE;
1727 for (p = str; *str; ++str)
1728 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001729 /* When the backslash is used for escaping the special meaning of a
1730 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001731 if (rem_backslash(str))
1732 {
1733 *p++ = *str++;
1734 *p++ = *str;
1735 }
1736 else
1737 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001738 /* An item ends at a space not in backticks */
1739 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001741 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001743 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744 }
1745 }
1746 str = skipwhite(str);
1747 *p = NUL;
1748
1749 return str;
1750}
1751
Bram Moolenaar86b68352004-12-27 21:59:20 +00001752/*
1753 * Separate the arguments in "str" and return a list of pointers in the
1754 * growarray "gap".
1755 */
1756 int
1757get_arglist(gap, str)
1758 garray_T *gap;
1759 char_u *str;
1760{
1761 ga_init2(gap, (int)sizeof(char_u *), 20);
1762 while (*str != NUL)
1763 {
1764 if (ga_grow(gap, 1) == FAIL)
1765 {
1766 ga_clear(gap);
1767 return FAIL;
1768 }
1769 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1770
1771 /* Isolate one argument, change it in-place, put a NUL after it. */
1772 str = do_one_arg(str);
1773 }
1774 return OK;
1775}
1776
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001777#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001778/*
1779 * Parse a list of arguments (file names), expand them and return in
1780 * "fnames[fcountp]".
1781 * Return FAIL or OK.
1782 */
1783 int
1784get_arglist_exp(str, fcountp, fnamesp)
1785 char_u *str;
1786 int *fcountp;
1787 char_u ***fnamesp;
1788{
1789 garray_T ga;
1790 int i;
1791
1792 if (get_arglist(&ga, str) == FAIL)
1793 return FAIL;
1794 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1795 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1796 ga_clear(&ga);
1797 return i;
1798}
1799#endif
1800
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1802/*
1803 * Redefine the argument list.
1804 */
1805 void
1806set_arglist(str)
1807 char_u *str;
1808{
1809 do_arglist(str, AL_SET, 0);
1810}
1811#endif
1812
1813/*
1814 * "what" == AL_SET: Redefine the argument list to 'str'.
1815 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1816 * "what" == AL_DEL: remove files in 'str' from the argument list.
1817 *
1818 * Return FAIL for failure, OK otherwise.
1819 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820 static int
1821do_arglist(str, what, after)
1822 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001823 int what UNUSED;
1824 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001825{
1826 garray_T new_ga;
1827 int exp_count;
1828 char_u **exp_files;
1829 int i;
1830#ifdef FEAT_LISTCMDS
1831 char_u *p;
1832 int match;
1833#endif
1834
1835 /*
1836 * Collect all file name arguments in "new_ga".
1837 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001838 if (get_arglist(&new_ga, str) == FAIL)
1839 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001840
1841#ifdef FEAT_LISTCMDS
1842 if (what == AL_DEL)
1843 {
1844 regmatch_T regmatch;
1845 int didone;
1846
1847 /*
1848 * Delete the items: use each item as a regexp and find a match in the
1849 * argument list.
1850 */
1851#ifdef CASE_INSENSITIVE_FILENAME
1852 regmatch.rm_ic = TRUE; /* Always ignore case */
1853#else
1854 regmatch.rm_ic = FALSE; /* Never ignore case */
1855#endif
1856 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1857 {
1858 p = ((char_u **)new_ga.ga_data)[i];
1859 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1860 if (p == NULL)
1861 break;
1862 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1863 if (regmatch.regprog == NULL)
1864 {
1865 vim_free(p);
1866 break;
1867 }
1868
1869 didone = FALSE;
1870 for (match = 0; match < ARGCOUNT; ++match)
1871 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1872 (colnr_T)0))
1873 {
1874 didone = TRUE;
1875 vim_free(ARGLIST[match].ae_fname);
1876 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1877 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1878 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879 if (curwin->w_arg_idx > match)
1880 --curwin->w_arg_idx;
1881 --match;
1882 }
1883
1884 vim_free(regmatch.regprog);
1885 vim_free(p);
1886 if (!didone)
1887 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1888 }
1889 ga_clear(&new_ga);
1890 }
1891 else
1892#endif
1893 {
1894 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1895 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1896 ga_clear(&new_ga);
1897 if (i == FAIL)
1898 return FAIL;
1899 if (exp_count == 0)
1900 {
1901 EMSG(_(e_nomatch));
1902 return FAIL;
1903 }
1904
1905#ifdef FEAT_LISTCMDS
1906 if (what == AL_ADD)
1907 {
1908 (void)alist_add_list(exp_count, exp_files, after);
1909 vim_free(exp_files);
1910 }
1911 else /* what == AL_SET */
1912#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001913 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914 }
1915
1916 alist_check_arg_idx();
1917
1918 return OK;
1919}
1920
1921/*
1922 * Check the validity of the arg_idx for each other window.
1923 */
1924 static void
1925alist_check_arg_idx()
1926{
1927#ifdef FEAT_WINDOWS
1928 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001929 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930
Bram Moolenaarf740b292006-02-16 22:11:02 +00001931 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 if (win->w_alist == curwin->w_alist)
1933 check_arg_idx(win);
1934#else
1935 check_arg_idx(curwin);
1936#endif
1937}
1938
1939/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001940 * Return TRUE if window "win" is editing then file at the current argument
1941 * index.
1942 */
1943 static int
1944editing_arg_idx(win)
1945 win_T *win;
1946{
1947 return !(win->w_arg_idx >= WARGCOUNT(win)
1948 || (win->w_buffer->b_fnum
1949 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1950 && (win->w_buffer->b_ffname == NULL
1951 || !(fullpathcmp(
1952 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1953 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1954}
1955
1956/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957 * Check if window "win" is editing the w_arg_idx file in its argument list.
1958 */
1959 void
1960check_arg_idx(win)
1961 win_T *win;
1962{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001963 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001964 {
1965 /* We are not editing the current entry in the argument list.
1966 * Set "arg_had_last" if we are editing the last one. */
1967 win->w_arg_idx_invalid = TRUE;
1968 if (win->w_arg_idx != WARGCOUNT(win) - 1
1969 && arg_had_last == FALSE
1970#ifdef FEAT_WINDOWS
1971 && ALIST(win) == &global_alist
1972#endif
1973 && GARGCOUNT > 0
1974 && win->w_arg_idx < GARGCOUNT
1975 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1976 || (win->w_buffer->b_ffname != NULL
1977 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1978 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1979 arg_had_last = TRUE;
1980 }
1981 else
1982 {
1983 /* We are editing the current entry in the argument list.
1984 * Set "arg_had_last" if it's also the last one */
1985 win->w_arg_idx_invalid = FALSE;
1986 if (win->w_arg_idx == WARGCOUNT(win) - 1
1987#ifdef FEAT_WINDOWS
1988 && win->w_alist == &global_alist
1989#endif
1990 )
1991 arg_had_last = TRUE;
1992 }
1993}
1994
1995/*
1996 * ":args", ":argslocal" and ":argsglobal".
1997 */
1998 void
1999ex_args(eap)
2000 exarg_T *eap;
2001{
2002 int i;
2003
2004 if (eap->cmdidx != CMD_args)
2005 {
2006#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2007 alist_unlink(ALIST(curwin));
2008 if (eap->cmdidx == CMD_argglobal)
2009 ALIST(curwin) = &global_alist;
2010 else /* eap->cmdidx == CMD_arglocal */
2011 alist_new();
2012#else
2013 ex_ni(eap);
2014 return;
2015#endif
2016 }
2017
2018 if (!ends_excmd(*eap->arg))
2019 {
2020 /*
2021 * ":args file ..": define new argument list, handle like ":next"
2022 * Also for ":argslocal file .." and ":argsglobal file ..".
2023 */
2024 ex_next(eap);
2025 }
2026 else
2027#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2028 if (eap->cmdidx == CMD_args)
2029#endif
2030 {
2031 /*
2032 * ":args": list arguments.
2033 */
2034 if (ARGCOUNT > 0)
2035 {
2036 /* Overwrite the command, for a short list there is no scrolling
2037 * required and no wait_return(). */
2038 gotocmdline(TRUE);
2039 for (i = 0; i < ARGCOUNT; ++i)
2040 {
2041 if (i == curwin->w_arg_idx)
2042 msg_putchar('[');
2043 msg_outtrans(alist_name(&ARGLIST[i]));
2044 if (i == curwin->w_arg_idx)
2045 msg_putchar(']');
2046 msg_putchar(' ');
2047 }
2048 }
2049 }
2050#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2051 else if (eap->cmdidx == CMD_arglocal)
2052 {
2053 garray_T *gap = &curwin->w_alist->al_ga;
2054
2055 /*
2056 * ":argslocal": make a local copy of the global argument list.
2057 */
2058 if (ga_grow(gap, GARGCOUNT) == OK)
2059 for (i = 0; i < GARGCOUNT; ++i)
2060 if (GARGLIST[i].ae_fname != NULL)
2061 {
2062 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2063 vim_strsave(GARGLIST[i].ae_fname);
2064 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2065 GARGLIST[i].ae_fnum;
2066 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002067 }
2068 }
2069#endif
2070}
2071
2072/*
2073 * ":previous", ":sprevious", ":Next" and ":sNext".
2074 */
2075 void
2076ex_previous(eap)
2077 exarg_T *eap;
2078{
2079 /* If past the last one already, go to the last one. */
2080 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2081 do_argfile(eap, ARGCOUNT - 1);
2082 else
2083 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2084}
2085
2086/*
2087 * ":rewind", ":first", ":sfirst" and ":srewind".
2088 */
2089 void
2090ex_rewind(eap)
2091 exarg_T *eap;
2092{
2093 do_argfile(eap, 0);
2094}
2095
2096/*
2097 * ":last" and ":slast".
2098 */
2099 void
2100ex_last(eap)
2101 exarg_T *eap;
2102{
2103 do_argfile(eap, ARGCOUNT - 1);
2104}
2105
2106/*
2107 * ":argument" and ":sargument".
2108 */
2109 void
2110ex_argument(eap)
2111 exarg_T *eap;
2112{
2113 int i;
2114
2115 if (eap->addr_count > 0)
2116 i = eap->line2 - 1;
2117 else
2118 i = curwin->w_arg_idx;
2119 do_argfile(eap, i);
2120}
2121
2122/*
2123 * Edit file "argn" of the argument lists.
2124 */
2125 void
2126do_argfile(eap, argn)
2127 exarg_T *eap;
2128 int argn;
2129{
2130 int other;
2131 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002132 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002133
2134 if (argn < 0 || argn >= ARGCOUNT)
2135 {
2136 if (ARGCOUNT <= 1)
2137 EMSG(_("E163: There is only one file to edit"));
2138 else if (argn < 0)
2139 EMSG(_("E164: Cannot go before first file"));
2140 else
2141 EMSG(_("E165: Cannot go beyond last file"));
2142 }
2143 else
2144 {
2145 setpcmark();
2146#ifdef FEAT_GUI
2147 need_mouse_correct = TRUE;
2148#endif
2149
2150#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002151 /* split window or create new tab page first */
2152 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002153 {
2154 if (win_split(0, 0) == FAIL)
2155 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002156 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002157 }
2158 else
2159#endif
2160 {
2161 /*
2162 * if 'hidden' set, only check for changed file when re-editing
2163 * the same buffer
2164 */
2165 other = TRUE;
2166 if (P_HID(curbuf))
2167 {
2168 p = fix_fname(alist_name(&ARGLIST[argn]));
2169 other = otherfile(p);
2170 vim_free(p);
2171 }
2172 if ((!P_HID(curbuf) || !other)
2173 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2174 return;
2175 }
2176
2177 curwin->w_arg_idx = argn;
2178 if (argn == ARGCOUNT - 1
2179#ifdef FEAT_WINDOWS
2180 && curwin->w_alist == &global_alist
2181#endif
2182 )
2183 arg_had_last = TRUE;
2184
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002185 /* Edit the file; always use the last known line number.
2186 * When it fails (e.g. Abort for already edited file) restore the
2187 * argument index. */
2188 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002189 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002190 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2191 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002192 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002193 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002194 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195 setmark('\'');
2196 }
2197}
2198
2199/*
2200 * ":next", and commands that behave like it.
2201 */
2202 void
2203ex_next(eap)
2204 exarg_T *eap;
2205{
2206 int i;
2207
2208 /*
2209 * check for changed buffer now, if this fails the argument list is not
2210 * redefined.
2211 */
2212 if ( P_HID(curbuf)
2213 || eap->cmdidx == CMD_snext
2214 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2215 {
2216 if (*eap->arg != NUL) /* redefine file list */
2217 {
2218 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2219 return;
2220 i = 0;
2221 }
2222 else
2223 i = curwin->w_arg_idx + (int)eap->line2;
2224 do_argfile(eap, i);
2225 }
2226}
2227
2228#ifdef FEAT_LISTCMDS
2229/*
2230 * ":argedit"
2231 */
2232 void
2233ex_argedit(eap)
2234 exarg_T *eap;
2235{
2236 int fnum;
2237 int i;
2238 char_u *s;
2239
2240 /* Add the argument to the buffer list and get the buffer number. */
2241 fnum = buflist_add(eap->arg, BLN_LISTED);
2242
2243 /* Check if this argument is already in the argument list. */
2244 for (i = 0; i < ARGCOUNT; ++i)
2245 if (ARGLIST[i].ae_fnum == fnum)
2246 break;
2247 if (i == ARGCOUNT)
2248 {
2249 /* Can't find it, add it to the argument list. */
2250 s = vim_strsave(eap->arg);
2251 if (s == NULL)
2252 return;
2253 i = alist_add_list(1, &s,
2254 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2255 if (i < 0)
2256 return;
2257 curwin->w_arg_idx = i;
2258 }
2259
2260 alist_check_arg_idx();
2261
2262 /* Edit the argument. */
2263 do_argfile(eap, i);
2264}
2265
2266/*
2267 * ":argadd"
2268 */
2269 void
2270ex_argadd(eap)
2271 exarg_T *eap;
2272{
2273 do_arglist(eap->arg, AL_ADD,
2274 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2275#ifdef FEAT_TITLE
2276 maketitle();
2277#endif
2278}
2279
2280/*
2281 * ":argdelete"
2282 */
2283 void
2284ex_argdelete(eap)
2285 exarg_T *eap;
2286{
2287 int i;
2288 int n;
2289
2290 if (eap->addr_count > 0)
2291 {
2292 /* ":1,4argdel": Delete all arguments in the range. */
2293 if (eap->line2 > ARGCOUNT)
2294 eap->line2 = ARGCOUNT;
2295 n = eap->line2 - eap->line1 + 1;
2296 if (*eap->arg != NUL || n <= 0)
2297 EMSG(_(e_invarg));
2298 else
2299 {
2300 for (i = eap->line1; i <= eap->line2; ++i)
2301 vim_free(ARGLIST[i - 1].ae_fname);
2302 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2303 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2304 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305 if (curwin->w_arg_idx >= eap->line2)
2306 curwin->w_arg_idx -= n;
2307 else if (curwin->w_arg_idx > eap->line1)
2308 curwin->w_arg_idx = eap->line1;
2309 }
2310 }
2311 else if (*eap->arg == NUL)
2312 EMSG(_(e_argreq));
2313 else
2314 do_arglist(eap->arg, AL_DEL, 0);
2315#ifdef FEAT_TITLE
2316 maketitle();
2317#endif
2318}
2319
2320/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002321 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322 */
2323 void
2324ex_listdo(eap)
2325 exarg_T *eap;
2326{
2327 int i;
2328#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002329 win_T *wp;
2330 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331#endif
2332 buf_T *buf;
2333 int next_fnum = 0;
2334#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2335 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002337 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002338
2339#ifndef FEAT_WINDOWS
2340 if (eap->cmdidx == CMD_windo)
2341 {
2342 ex_ni(eap);
2343 return;
2344 }
2345#endif
2346
2347#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002348 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002349 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2350 * great speed improvement. */
2351 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352#endif
2353
2354 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002355 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356 || P_HID(curbuf)
2357 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2358 {
2359 /* start at the first argument/window/buffer */
2360 i = 0;
2361#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002362 wp = firstwin;
2363 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364#endif
2365 /* set pcmark now */
2366 if (eap->cmdidx == CMD_bufdo)
2367 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2368 else
2369 setpcmark();
2370 listcmd_busy = TRUE; /* avoids setting pcmark below */
2371
2372 while (!got_int)
2373 {
2374 if (eap->cmdidx == CMD_argdo)
2375 {
2376 /* go to argument "i" */
2377 if (i == ARGCOUNT)
2378 break;
2379 /* Don't call do_argfile() when already there, it will try
2380 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002381 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002382 {
2383 /* Clear 'shm' to avoid that the file message overwrites
2384 * any output from the command. */
2385 p_shm_save = vim_strsave(p_shm);
2386 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002387 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002388 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2389 vim_free(p_shm_save);
2390 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002391 if (curwin->w_arg_idx != i)
2392 break;
2393 ++i;
2394 }
2395#ifdef FEAT_WINDOWS
2396 else if (eap->cmdidx == CMD_windo)
2397 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002398 /* go to window "wp" */
2399 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002400 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002401 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002402 if (curwin != wp)
2403 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002404 wp = curwin->w_next;
2405 }
2406 else if (eap->cmdidx == CMD_tabdo)
2407 {
2408 /* go to window "tp" */
2409 if (!valid_tabpage(tp))
2410 break;
2411 goto_tabpage_tp(tp);
2412 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002413 }
2414#endif
2415 else if (eap->cmdidx == CMD_bufdo)
2416 {
2417 /* Remember the number of the next listed buffer, in case
2418 * ":bwipe" is used or autocommands do something strange. */
2419 next_fnum = -1;
2420 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2421 if (buf->b_p_bl)
2422 {
2423 next_fnum = buf->b_fnum;
2424 break;
2425 }
2426 }
2427
2428 /* execute the command */
2429 do_cmdline(eap->arg, eap->getline, eap->cookie,
2430 DOCMD_VERBOSE + DOCMD_NOWAIT);
2431
2432 if (eap->cmdidx == CMD_bufdo)
2433 {
2434 /* Done? */
2435 if (next_fnum < 0)
2436 break;
2437 /* Check if the buffer still exists. */
2438 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2439 if (buf->b_fnum == next_fnum)
2440 break;
2441 if (buf == NULL)
2442 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002443
2444 /* Go to the next buffer. Clear 'shm' to avoid that the file
2445 * message overwrites any output from the command. */
2446 p_shm_save = vim_strsave(p_shm);
2447 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002448 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002449 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2450 vim_free(p_shm_save);
2451
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452 /* If autocommands took us elsewhere, quit here */
2453 if (curbuf->b_fnum != next_fnum)
2454 break;
2455 }
2456
2457 if (eap->cmdidx == CMD_windo)
2458 {
2459 validate_cursor(); /* cursor may have moved */
2460#ifdef FEAT_SCROLLBIND
2461 /* required when 'scrollbind' has been set */
2462 if (curwin->w_p_scb)
2463 do_check_scrollbind(TRUE);
2464#endif
2465 }
2466 }
2467 listcmd_busy = FALSE;
2468 }
2469
2470#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002471 if (save_ei != NULL)
2472 {
2473 au_event_restore(save_ei);
2474 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2475 curbuf->b_fname, TRUE, curbuf);
2476 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477#endif
2478}
2479
2480/*
2481 * Add files[count] to the arglist of the current window after arg "after".
2482 * The file names in files[count] must have been allocated and are taken over.
2483 * Files[] itself is not taken over.
2484 * Returns index of first added argument. Returns -1 when failed (out of mem).
2485 */
2486 static int
2487alist_add_list(count, files, after)
2488 int count;
2489 char_u **files;
2490 int after; /* where to add: 0 = before first one */
2491{
2492 int i;
2493
2494 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2495 {
2496 if (after < 0)
2497 after = 0;
2498 if (after > ARGCOUNT)
2499 after = ARGCOUNT;
2500 if (after < ARGCOUNT)
2501 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2502 (ARGCOUNT - after) * sizeof(aentry_T));
2503 for (i = 0; i < count; ++i)
2504 {
2505 ARGLIST[after + i].ae_fname = files[i];
2506 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2507 }
2508 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509 if (curwin->w_arg_idx >= after)
2510 ++curwin->w_arg_idx;
2511 return after;
2512 }
2513
2514 for (i = 0; i < count; ++i)
2515 vim_free(files[i]);
2516 return -1;
2517}
2518
2519#endif /* FEAT_LISTCMDS */
2520
2521#ifdef FEAT_EVAL
2522/*
2523 * ":compiler[!] {name}"
2524 */
2525 void
2526ex_compiler(eap)
2527 exarg_T *eap;
2528{
2529 char_u *buf;
2530 char_u *old_cur_comp = NULL;
2531 char_u *p;
2532
2533 if (*eap->arg == NUL)
2534 {
2535 /* List all compiler scripts. */
2536 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2537 /* ) keep the indenter happy... */
2538 }
2539 else
2540 {
2541 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2542 if (buf != NULL)
2543 {
2544 if (eap->forceit)
2545 {
2546 /* ":compiler! {name}" sets global options */
2547 do_cmdline_cmd((char_u *)
2548 "command -nargs=* CompilerSet set <args>");
2549 }
2550 else
2551 {
2552 /* ":compiler! {name}" sets local options.
2553 * To remain backwards compatible "current_compiler" is always
2554 * used. A user's compiler plugin may set it, the distributed
2555 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002556 * "b:current_compiler" and restore "current_compiler".
2557 * Explicitly prepend "g:" to make it work in a function. */
2558 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559 if (old_cur_comp != NULL)
2560 old_cur_comp = vim_strsave(old_cur_comp);
2561 do_cmdline_cmd((char_u *)
2562 "command -nargs=* CompilerSet setlocal <args>");
2563 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002564 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002565 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002566
2567 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002568 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002569 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2570 vim_free(buf);
2571
2572 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2573
2574 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002575 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576 if (p != NULL)
2577 set_internal_string_var((char_u *)"b:current_compiler", p);
2578
2579 /* Restore "current_compiler" for ":compiler {name}". */
2580 if (!eap->forceit)
2581 {
2582 if (old_cur_comp != NULL)
2583 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002584 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002585 old_cur_comp);
2586 vim_free(old_cur_comp);
2587 }
2588 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002589 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002590 }
2591 }
2592 }
2593}
2594#endif
2595
2596/*
2597 * ":runtime {name}"
2598 */
2599 void
2600ex_runtime(eap)
2601 exarg_T *eap;
2602{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002603 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002604}
2605
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002606static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607
2608 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002609source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002611 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002613 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614}
2615
2616/*
2617 * Source the file "name" from all directories in 'runtimepath'.
2618 * "name" can contain wildcards.
2619 * When "all" is TRUE, source all files, otherwise only the first one.
2620 * return FAIL when no file could be sourced, OK otherwise.
2621 */
2622 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002623source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624 char_u *name;
2625 int all;
2626{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002627 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628}
2629
2630/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002631 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2632 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2634 * used.
2635 * Returns OK when at least one match found, FAIL otherwise.
2636 */
2637 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002638do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002639 char_u *name;
2640 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002641 void (*callback)__ARGS((char_u *fname, void *ck));
2642 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643{
2644 char_u *rtp;
2645 char_u *np;
2646 char_u *buf;
2647 char_u *rtp_copy;
2648 char_u *tail;
2649 int num_files;
2650 char_u **files;
2651 int i;
2652 int did_one = FALSE;
2653#ifdef AMIGA
2654 struct Process *proc = (struct Process *)FindTask(0L);
2655 APTR save_winptr = proc->pr_WindowPtr;
2656
2657 /* Avoid a requester here for a volume that doesn't exist. */
2658 proc->pr_WindowPtr = (APTR)-1L;
2659#endif
2660
2661 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2662 * value. */
2663 rtp_copy = vim_strsave(p_rtp);
2664 buf = alloc(MAXPATHL);
2665 if (buf != NULL && rtp_copy != NULL)
2666 {
2667 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002668 {
2669 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002670 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002671 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002672 verbose_leave();
2673 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002674
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675 /* Loop over all entries in 'runtimepath'. */
2676 rtp = rtp_copy;
2677 while (*rtp != NUL && (all || !did_one))
2678 {
2679 /* Copy the path from 'runtimepath' to buf[]. */
2680 copy_option_part(&rtp, buf, MAXPATHL, ",");
2681 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2682 {
2683 add_pathsep(buf);
2684 tail = buf + STRLEN(buf);
2685
2686 /* Loop over all patterns in "name" */
2687 np = name;
2688 while (*np != NUL && (all || !did_one))
2689 {
2690 /* Append the pattern from "name" to buf[]. */
2691 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2692 "\t ");
2693
2694 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002695 {
2696 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002697 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002698 verbose_leave();
2699 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700
2701 /* Expand wildcards, invoke the callback for each match. */
2702 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2703 EW_FILE) == OK)
2704 {
2705 for (i = 0; i < num_files; ++i)
2706 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002707 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 did_one = TRUE;
2709 if (!all)
2710 break;
2711 }
2712 FreeWild(num_files, files);
2713 }
2714 }
2715 }
2716 }
2717 }
2718 vim_free(buf);
2719 vim_free(rtp_copy);
2720 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002721 {
2722 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002723 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002724 verbose_leave();
2725 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726
2727#ifdef AMIGA
2728 proc->pr_WindowPtr = save_winptr;
2729#endif
2730
2731 return did_one ? OK : FAIL;
2732}
2733
2734#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2735/*
2736 * ":options"
2737 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002738 void
2739ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002740 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002741{
2742 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2743}
2744#endif
2745
2746/*
2747 * ":source {fname}"
2748 */
2749 void
2750ex_source(eap)
2751 exarg_T *eap;
2752{
2753#ifdef FEAT_BROWSE
2754 if (cmdmod.browse)
2755 {
2756 char_u *fname = NULL;
2757
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002758 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2760 if (fname != NULL)
2761 {
2762 cmd_source(fname, eap);
2763 vim_free(fname);
2764 }
2765 }
2766 else
2767#endif
2768 cmd_source(eap->arg, eap);
2769}
2770
2771 static void
2772cmd_source(fname, eap)
2773 char_u *fname;
2774 exarg_T *eap;
2775{
2776 if (*fname == NUL)
2777 EMSG(_(e_argreq));
2778
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002780 /* ":source!": read Normal mdoe commands
2781 * Need to execute the commands directly. This is required at least
2782 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783 * - ":g" command busy
2784 * - after ":argdo", ":windo" or ":bufdo"
2785 * - another command follows
2786 * - inside a loop
2787 */
2788 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2789#ifdef FEAT_EVAL
2790 || eap->cstack->cs_idx >= 0
2791#endif
2792 );
2793
2794 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002795 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796 EMSG2(_(e_notopen), fname);
2797}
2798
2799/*
2800 * ":source" and associated commands.
2801 */
2802/*
2803 * Structure used to store info for each sourced file.
2804 * It is shared between do_source() and getsourceline().
2805 * This is required, because it needs to be handed to do_cmdline() and
2806 * sourcing can be done recursively.
2807 */
2808struct source_cookie
2809{
2810 FILE *fp; /* opened file for sourcing */
2811 char_u *nextline; /* if not NULL: line that was read ahead */
2812 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002813#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2815 int error; /* TRUE if LF found after CR-LF */
2816#endif
2817#ifdef FEAT_EVAL
2818 linenr_T breakpoint; /* next line with breakpoint or zero */
2819 char_u *fname; /* name of sourced file */
2820 int dbg_tick; /* debug_tick when breakpoint was set */
2821 int level; /* top nesting level of sourced file */
2822#endif
2823#ifdef FEAT_MBYTE
2824 vimconv_T conv; /* type of conversion */
2825#endif
2826};
2827
2828#ifdef FEAT_EVAL
2829/*
2830 * Return the address holding the next breakpoint line for a source cookie.
2831 */
2832 linenr_T *
2833source_breakpoint(cookie)
2834 void *cookie;
2835{
2836 return &((struct source_cookie *)cookie)->breakpoint;
2837}
2838
2839/*
2840 * Return the address holding the debug tick for a source cookie.
2841 */
2842 int *
2843source_dbg_tick(cookie)
2844 void *cookie;
2845{
2846 return &((struct source_cookie *)cookie)->dbg_tick;
2847}
2848
2849/*
2850 * Return the nesting level for a source cookie.
2851 */
2852 int
2853source_level(cookie)
2854 void *cookie;
2855{
2856 return ((struct source_cookie *)cookie)->level;
2857}
2858#endif
2859
2860static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2861
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002862#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2863# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002864static FILE *fopen_noinh_readbin __ARGS((char *filename));
2865
2866/*
2867 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002868 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869 */
2870 static FILE *
2871fopen_noinh_readbin(filename)
2872 char *filename;
2873{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002874# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002875 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2876# else
2877 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002878# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879
2880 if (fd_tmp == -1)
2881 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002882
2883# ifdef HAVE_FD_CLOEXEC
2884 {
2885 int fdflags = fcntl(fd_tmp, F_GETFD);
2886 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
2887 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
2888 }
2889# endif
2890
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891 return fdopen(fd_tmp, READBIN);
2892}
2893#endif
2894
2895
2896/*
2897 * do_source: Read the file "fname" and execute its lines as EX commands.
2898 *
2899 * This function may be called recursively!
2900 *
2901 * return FAIL if file could not be opened, OK otherwise
2902 */
2903 int
2904do_source(fname, check_other, is_vimrc)
2905 char_u *fname;
2906 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002907 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908{
2909 struct source_cookie cookie;
2910 char_u *save_sourcing_name;
2911 linenr_T save_sourcing_lnum;
2912 char_u *p;
2913 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002914 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915 int retval = FAIL;
2916#ifdef FEAT_EVAL
2917 scid_T save_current_SID;
2918 static scid_T last_current_SID = 0;
2919 void *save_funccalp;
2920 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002921 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002922# ifdef UNIX
2923 struct stat st;
2924 int stat_ok;
2925# endif
2926#endif
2927#ifdef STARTUPTIME
2928 struct timeval tv_rel;
2929 struct timeval tv_start;
2930#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002931#ifdef FEAT_PROFILE
2932 proftime_T wait_start;
2933#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936 if (p == NULL)
2937 return retval;
2938 fname_exp = fix_fname(p);
2939 vim_free(p);
2940 if (fname_exp == NULL)
2941 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 if (mch_isdir(fname_exp))
2943 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002944 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945 goto theend;
2946 }
2947
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002948#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002949 /* Apply SourceCmd autocommands, they should get the file and source it. */
2950 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2951 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2952 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002953 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002954# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002955 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002956# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002957 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002958# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002959 goto theend;
2960 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002961
2962 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002963 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2964#endif
2965
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002966#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2968#else
2969 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2970#endif
2971 if (cookie.fp == NULL && check_other)
2972 {
2973 /*
2974 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2975 * and ".exrc" by "_exrc" or vice versa.
2976 */
2977 p = gettail(fname_exp);
2978 if ((*p == '.' || *p == '_')
2979 && (STRICMP(p + 1, "vimrc") == 0
2980 || STRICMP(p + 1, "gvimrc") == 0
2981 || STRICMP(p + 1, "exrc") == 0))
2982 {
2983 if (*p == '_')
2984 *p = '.';
2985 else
2986 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002987#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002988 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2989#else
2990 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2991#endif
2992 }
2993 }
2994
2995 if (cookie.fp == NULL)
2996 {
2997 if (p_verbose > 0)
2998 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002999 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003001 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003002 else
3003 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003004 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003005 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003006 }
3007 goto theend;
3008 }
3009
3010 /*
3011 * The file exists.
3012 * - In verbose mode, give a message.
3013 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3014 */
3015 if (p_verbose > 1)
3016 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003017 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003019 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020 else
3021 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003022 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003023 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003024 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003025 if (is_vimrc == DOSO_VIMRC)
3026 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3027 else if (is_vimrc == DOSO_GVIMRC)
3028 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003029
3030#ifdef USE_CRNL
3031 /* If no automatic file format: Set default to CR-NL. */
3032 if (*p_ffs == NUL)
3033 cookie.fileformat = EOL_DOS;
3034 else
3035 cookie.fileformat = EOL_UNKNOWN;
3036 cookie.error = FALSE;
3037#endif
3038
3039#ifdef USE_CR
3040 /* If no automatic file format: Set default to CR. */
3041 if (*p_ffs == NUL)
3042 cookie.fileformat = EOL_MAC;
3043 else
3044 cookie.fileformat = EOL_UNKNOWN;
3045 cookie.error = FALSE;
3046#endif
3047
3048 cookie.nextline = NULL;
3049 cookie.finished = FALSE;
3050
3051#ifdef FEAT_EVAL
3052 /*
3053 * Check if this script has a breakpoint.
3054 */
3055 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3056 cookie.fname = fname_exp;
3057 cookie.dbg_tick = debug_tick;
3058
3059 cookie.level = ex_nesting_level;
3060#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061
3062 /*
3063 * Keep the sourcing name/lnum, for recursive calls.
3064 */
3065 save_sourcing_name = sourcing_name;
3066 sourcing_name = fname_exp;
3067 save_sourcing_lnum = sourcing_lnum;
3068 sourcing_lnum = 0;
3069
Bram Moolenaar73881402009-02-04 16:50:47 +00003070#ifdef FEAT_MBYTE
3071 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3072
3073 /* Read the first line so we can check for a UTF-8 BOM. */
3074 firstline = getsourceline(0, (void *)&cookie, 0);
3075 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3076 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3077 {
3078 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3079 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3080 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003081 if (p == NULL)
3082 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003083 if (p != NULL)
3084 {
3085 vim_free(firstline);
3086 firstline = p;
3087 }
3088 }
3089#endif
3090
Bram Moolenaar071d4272004-06-13 20:20:40 +00003091#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003092 if (time_fd != NULL)
3093 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094#endif
3095
3096#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003097# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003098 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003099 prof_child_enter(&wait_start); /* entering a child now */
3100# endif
3101
3102 /* Don't use local function variables, if called from a function.
3103 * Also starts profiling timer for nested script. */
3104 save_funccalp = save_funccal();
3105
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106 /*
3107 * Check if this script was sourced before to finds its SID.
3108 * If it's new, generate a new SID.
3109 */
3110 save_current_SID = current_SID;
3111# ifdef UNIX
3112 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3113# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003114 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3115 {
3116 si = &SCRIPT_ITEM(current_SID);
3117 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003118 && (
3119# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003120 /* Compare dev/ino when possible, it catches symbolic
3121 * links. Also compare file names, the inode may change
3122 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003123 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003124 && (si->sn_dev == st.st_dev
3125 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003127 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003129 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 if (current_SID == 0)
3131 {
3132 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003133 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3134 == FAIL)
3135 goto almosttheend;
3136 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003137 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003138 ++script_items.ga_len;
3139 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3140# ifdef FEAT_PROFILE
3141 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003144 si = &SCRIPT_ITEM(current_SID);
3145 si->sn_name = fname_exp;
3146 fname_exp = NULL;
3147# ifdef UNIX
3148 if (stat_ok)
3149 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003150 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003151 si->sn_dev = st.st_dev;
3152 si->sn_ino = st.st_ino;
3153 }
3154 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003155 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003156# endif
3157
Bram Moolenaar071d4272004-06-13 20:20:40 +00003158 /* Allocate the local script variables to use for this script. */
3159 new_script_vars(current_SID);
3160 }
3161
Bram Moolenaar05159a02005-02-26 23:04:13 +00003162# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003163 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003164 {
3165 int forceit;
3166
3167 /* Check if we do profiling for this script. */
3168 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3169 {
3170 script_do_profile(si);
3171 si->sn_pr_force = forceit;
3172 }
3173 if (si->sn_prof_on)
3174 {
3175 ++si->sn_pr_count;
3176 profile_start(&si->sn_pr_start);
3177 profile_zero(&si->sn_pr_children);
3178 }
3179 }
3180# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003181#endif
3182
3183 /*
3184 * Call do_cmdline, which will call getsourceline() to get the lines.
3185 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003186 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003188 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003189
3190#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003191 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003192 {
3193 /* Get "si" again, "script_items" may have been reallocated. */
3194 si = &SCRIPT_ITEM(current_SID);
3195 if (si->sn_prof_on)
3196 {
3197 profile_end(&si->sn_pr_start);
3198 profile_sub_wait(&wait_start, &si->sn_pr_start);
3199 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003200 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3201 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003202 }
3203 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204#endif
3205
3206 if (got_int)
3207 EMSG(_(e_interr));
3208 sourcing_name = save_sourcing_name;
3209 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210 if (p_verbose > 1)
3211 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003212 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003213 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003215 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003216 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003217 }
3218#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003219 if (time_fd != NULL)
3220 {
3221 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3222 time_msg((char *)IObuff, &tv_start);
3223 time_pop(&tv_rel);
3224 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225#endif
3226
3227#ifdef FEAT_EVAL
3228 /*
3229 * After a "finish" in debug mode, need to break at first command of next
3230 * sourced file.
3231 */
3232 if (save_debug_break_level > ex_nesting_level
3233 && debug_break_level == ex_nesting_level)
3234 ++debug_break_level;
3235#endif
3236
Bram Moolenaar05159a02005-02-26 23:04:13 +00003237#ifdef FEAT_EVAL
3238almosttheend:
3239 current_SID = save_current_SID;
3240 restore_funccal(save_funccalp);
3241# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003242 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003243 prof_child_exit(&wait_start); /* leaving a child now */
3244# endif
3245#endif
3246 fclose(cookie.fp);
3247 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003248 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003249#ifdef FEAT_MBYTE
3250 convert_setup(&cookie.conv, NULL, NULL);
3251#endif
3252
Bram Moolenaar071d4272004-06-13 20:20:40 +00003253theend:
3254 vim_free(fname_exp);
3255 return retval;
3256}
3257
3258#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003259
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260/*
3261 * ":scriptnames"
3262 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003263 void
3264ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003265 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266{
3267 int i;
3268
Bram Moolenaar05159a02005-02-26 23:04:13 +00003269 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3270 if (SCRIPT_ITEM(i).sn_name != NULL)
3271 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272}
3273
3274# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3275/*
3276 * Fix slashes in the list of script names for 'shellslash'.
3277 */
3278 void
3279scriptnames_slash_adjust()
3280{
3281 int i;
3282
Bram Moolenaar05159a02005-02-26 23:04:13 +00003283 for (i = 1; i <= script_items.ga_len; ++i)
3284 if (SCRIPT_ITEM(i).sn_name != NULL)
3285 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003286}
3287# endif
3288
3289/*
3290 * Get a pointer to a script name. Used for ":verbose set".
3291 */
3292 char_u *
3293get_scriptname(id)
3294 scid_T id;
3295{
3296 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003297 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003299 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003301 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003303 return (char_u *)_("environment variable");
3304 if (id == SID_ERROR)
3305 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003306 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003308
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003309# if defined(EXITFREE) || defined(PROTO)
3310 void
3311free_scriptnames()
3312{
3313 int i;
3314
3315 for (i = script_items.ga_len; i > 0; --i)
3316 vim_free(SCRIPT_ITEM(i).sn_name);
3317 ga_clear(&script_items);
3318}
3319# endif
3320
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321#endif
3322
3323#if defined(USE_CR) || defined(PROTO)
3324
3325# if defined(__MSL__) && (__MSL__ >= 22)
3326/*
3327 * Newer version of the Metrowerks library handle DOS and UNIX files
3328 * without help.
3329 * Test with earlier versions, MSL 2.2 is the library supplied with
3330 * Codewarrior Pro 2.
3331 */
3332 char *
3333fgets_cr(s, n, stream)
3334 char *s;
3335 int n;
3336 FILE *stream;
3337{
3338 return fgets(s, n, stream);
3339}
3340# else
3341/*
3342 * Version of fgets() which also works for lines ending in a <CR> only
3343 * (Macintosh format).
3344 * For older versions of the Metrowerks library.
3345 * At least CodeWarrior 9 needed this code.
3346 */
3347 char *
3348fgets_cr(s, n, stream)
3349 char *s;
3350 int n;
3351 FILE *stream;
3352{
3353 int c = 0;
3354 int char_read = 0;
3355
3356 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3357 {
3358 c = fgetc(stream);
3359 s[char_read++] = c;
3360 /* If the file is in DOS format, we need to skip a NL after a CR. I
3361 * thought it was the other way around, but this appears to work... */
3362 if (c == '\n')
3363 {
3364 c = fgetc(stream);
3365 if (c != '\r')
3366 ungetc(c, stream);
3367 }
3368 }
3369
3370 s[char_read] = 0;
3371 if (char_read == 0)
3372 return NULL;
3373
3374 if (feof(stream) && char_read == 1)
3375 return NULL;
3376
3377 return s;
3378}
3379# endif
3380#endif
3381
3382/*
3383 * Get one full line from a sourced file.
3384 * Called by do_cmdline() when it's called from do_source().
3385 *
3386 * Return a pointer to the line in allocated memory.
3387 * Return NULL for end-of-file or some error.
3388 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003389 char_u *
3390getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003391 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003393 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394{
3395 struct source_cookie *sp = (struct source_cookie *)cookie;
3396 char_u *line;
3397 char_u *p, *s;
3398
3399#ifdef FEAT_EVAL
3400 /* If breakpoints have been added/deleted need to check for it. */
3401 if (sp->dbg_tick < debug_tick)
3402 {
3403 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3404 sp->dbg_tick = debug_tick;
3405 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003406# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003407 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003408 script_line_end();
3409# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003410#endif
3411 /*
3412 * Get current line. If there is a read-ahead line, use it, otherwise get
3413 * one now.
3414 */
3415 if (sp->finished)
3416 line = NULL;
3417 else if (sp->nextline == NULL)
3418 line = get_one_sourceline(sp);
3419 else
3420 {
3421 line = sp->nextline;
3422 sp->nextline = NULL;
3423 ++sourcing_lnum;
3424 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003425#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003426 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003427 script_line_start();
3428#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429
3430 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3431 * contain the 'C' flag. */
3432 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3433 {
3434 /* compensate for the one line read-ahead */
3435 --sourcing_lnum;
3436 for (;;)
3437 {
3438 sp->nextline = get_one_sourceline(sp);
3439 if (sp->nextline == NULL)
3440 break;
3441 p = skipwhite(sp->nextline);
3442 if (*p != '\\')
3443 break;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00003444 s = alloc((unsigned)(STRLEN(line) + STRLEN(p)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445 if (s == NULL) /* out of memory */
3446 break;
3447 STRCPY(s, line);
3448 STRCAT(s, p + 1);
3449 vim_free(line);
3450 line = s;
3451 vim_free(sp->nextline);
3452 }
3453 }
3454
3455#ifdef FEAT_MBYTE
3456 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3457 {
3458 /* Convert the encoding of the script line. */
3459 s = string_convert(&sp->conv, line, NULL);
3460 if (s != NULL)
3461 {
3462 vim_free(line);
3463 line = s;
3464 }
3465 }
3466#endif
3467
3468#ifdef FEAT_EVAL
3469 /* Did we encounter a breakpoint? */
3470 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3471 {
3472 dbg_breakpoint(sp->fname, sourcing_lnum);
3473 /* Find next breakpoint. */
3474 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3475 sp->dbg_tick = debug_tick;
3476 }
3477#endif
3478
3479 return line;
3480}
3481
3482 static char_u *
3483get_one_sourceline(sp)
3484 struct source_cookie *sp;
3485{
3486 garray_T ga;
3487 int len;
3488 int c;
3489 char_u *buf;
3490#ifdef USE_CRNL
3491 int has_cr; /* CR-LF found */
3492#endif
3493#ifdef USE_CR
3494 char_u *scan;
3495#endif
3496 int have_read = FALSE;
3497
3498 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003499 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003500
3501 /*
3502 * Loop until there is a finished line (or end-of-file).
3503 */
3504 sourcing_lnum++;
3505 for (;;)
3506 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003507 /* make room to read at least 120 (more) characters */
3508 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003509 break;
3510 buf = (char_u *)ga.ga_data;
3511
3512#ifdef USE_CR
3513 if (sp->fileformat == EOL_MAC)
3514 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003515 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3516 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003517 break;
3518 }
3519 else
3520#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003521 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3522 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003523 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003524 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525#ifdef USE_CRNL
3526 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3527 * CTRL-Z by its own, or after a NL. */
3528 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3529 && sp->fileformat == EOL_DOS
3530 && buf[len - 1] == Ctrl_Z)
3531 {
3532 buf[len - 1] = NUL;
3533 break;
3534 }
3535#endif
3536
3537#ifdef USE_CR
3538 /* If the read doesn't stop on a new line, and there's
3539 * some CR then we assume a Mac format */
3540 if (sp->fileformat == EOL_UNKNOWN)
3541 {
3542 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3543 sp->fileformat = EOL_MAC;
3544 else
3545 sp->fileformat = EOL_UNIX;
3546 }
3547
3548 if (sp->fileformat == EOL_MAC)
3549 {
3550 scan = vim_strchr(buf, '\r');
3551
3552 if (scan != NULL)
3553 {
3554 *scan = '\n';
3555 if (*(scan + 1) != 0)
3556 {
3557 *(scan + 1) = 0;
3558 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3559 }
3560 }
3561 len = STRLEN(buf);
3562 }
3563#endif
3564
3565 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003566 ga.ga_len = len;
3567
3568 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003569 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003570 continue;
3571
3572 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3573 {
3574#ifdef USE_CRNL
3575 has_cr = (len >= 2 && buf[len - 2] == '\r');
3576 if (sp->fileformat == EOL_UNKNOWN)
3577 {
3578 if (has_cr)
3579 sp->fileformat = EOL_DOS;
3580 else
3581 sp->fileformat = EOL_UNIX;
3582 }
3583
3584 if (sp->fileformat == EOL_DOS)
3585 {
3586 if (has_cr) /* replace trailing CR */
3587 {
3588 buf[len - 2] = '\n';
3589 --len;
3590 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003591 }
3592 else /* lines like ":map xx yy^M" will have failed */
3593 {
3594 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003595 {
3596 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003598 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003599 sp->error = TRUE;
3600 sp->fileformat = EOL_UNIX;
3601 }
3602 }
3603#endif
3604 /* The '\n' is escaped if there is an odd number of ^V's just
3605 * before it, first set "c" just before the 'V's and then check
3606 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3607 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3608 ;
3609 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3610 {
3611 sourcing_lnum++;
3612 continue;
3613 }
3614
3615 buf[len - 1] = NUL; /* remove the NL */
3616 }
3617
3618 /*
3619 * Check for ^C here now and then, so recursive :so can be broken.
3620 */
3621 line_breakcheck();
3622 break;
3623 }
3624
3625 if (have_read)
3626 return (char_u *)ga.ga_data;
3627
3628 vim_free(ga.ga_data);
3629 return NULL;
3630}
3631
Bram Moolenaar05159a02005-02-26 23:04:13 +00003632#if defined(FEAT_PROFILE) || defined(PROTO)
3633/*
3634 * Called when starting to read a script line.
3635 * "sourcing_lnum" must be correct!
3636 * When skipping lines it may not actually be executed, but we won't find out
3637 * until later and we need to store the time now.
3638 */
3639 void
3640script_line_start()
3641{
3642 scriptitem_T *si;
3643 sn_prl_T *pp;
3644
3645 if (current_SID <= 0 || current_SID > script_items.ga_len)
3646 return;
3647 si = &SCRIPT_ITEM(current_SID);
3648 if (si->sn_prof_on && sourcing_lnum >= 1)
3649 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003650 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003651 * here isn't counted. */
3652 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3653 si->sn_prl_idx = sourcing_lnum - 1;
3654 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3655 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3656 {
3657 /* Zero counters for a line that was not used before. */
3658 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3659 pp->snp_count = 0;
3660 profile_zero(&pp->sn_prl_total);
3661 profile_zero(&pp->sn_prl_self);
3662 ++si->sn_prl_ga.ga_len;
3663 }
3664 si->sn_prl_execed = FALSE;
3665 profile_start(&si->sn_prl_start);
3666 profile_zero(&si->sn_prl_children);
3667 profile_get_wait(&si->sn_prl_wait);
3668 }
3669}
3670
3671/*
3672 * Called when actually executing a function line.
3673 */
3674 void
3675script_line_exec()
3676{
3677 scriptitem_T *si;
3678
3679 if (current_SID <= 0 || current_SID > script_items.ga_len)
3680 return;
3681 si = &SCRIPT_ITEM(current_SID);
3682 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3683 si->sn_prl_execed = TRUE;
3684}
3685
3686/*
3687 * Called when done with a function line.
3688 */
3689 void
3690script_line_end()
3691{
3692 scriptitem_T *si;
3693 sn_prl_T *pp;
3694
3695 if (current_SID <= 0 || current_SID > script_items.ga_len)
3696 return;
3697 si = &SCRIPT_ITEM(current_SID);
3698 if (si->sn_prof_on && si->sn_prl_idx >= 0
3699 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3700 {
3701 if (si->sn_prl_execed)
3702 {
3703 pp = &PRL_ITEM(si, si->sn_prl_idx);
3704 ++pp->snp_count;
3705 profile_end(&si->sn_prl_start);
3706 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003707 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003708 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3709 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003710 }
3711 si->sn_prl_idx = -1;
3712 }
3713}
3714#endif
3715
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716/*
3717 * ":scriptencoding": Set encoding conversion for a sourced script.
3718 * Without the multi-byte feature it's simply ignored.
3719 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720 void
3721ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003722 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723{
3724#ifdef FEAT_MBYTE
3725 struct source_cookie *sp;
3726 char_u *name;
3727
3728 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3729 {
3730 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3731 return;
3732 }
3733
3734 if (*eap->arg != NUL)
3735 {
3736 name = enc_canonize(eap->arg);
3737 if (name == NULL) /* out of memory */
3738 return;
3739 }
3740 else
3741 name = eap->arg;
3742
3743 /* Setup for conversion from the specified encoding to 'encoding'. */
3744 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3745 convert_setup(&sp->conv, name, p_enc);
3746
3747 if (name != eap->arg)
3748 vim_free(name);
3749#endif
3750}
3751
3752#if defined(FEAT_EVAL) || defined(PROTO)
3753/*
3754 * ":finish": Mark a sourced file as finished.
3755 */
3756 void
3757ex_finish(eap)
3758 exarg_T *eap;
3759{
3760 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3761 do_finish(eap, FALSE);
3762 else
3763 EMSG(_("E168: :finish used outside of a sourced file"));
3764}
3765
3766/*
3767 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3768 * Also called for a pending finish at the ":endtry" or after returning from
3769 * an extra do_cmdline(). "reanimate" is used in the latter case.
3770 */
3771 void
3772do_finish(eap, reanimate)
3773 exarg_T *eap;
3774 int reanimate;
3775{
3776 int idx;
3777
3778 if (reanimate)
3779 ((struct source_cookie *)getline_cookie(eap->getline,
3780 eap->cookie))->finished = FALSE;
3781
3782 /*
3783 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3784 * not in its finally clause (which then is to be executed next) is found.
3785 * In this case, make the ":finish" pending for execution at the ":endtry".
3786 * Otherwise, finish normally.
3787 */
3788 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3789 if (idx >= 0)
3790 {
3791 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3792 report_make_pending(CSTP_FINISH, NULL);
3793 }
3794 else
3795 ((struct source_cookie *)getline_cookie(eap->getline,
3796 eap->cookie))->finished = TRUE;
3797}
3798
3799
3800/*
3801 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3802 * message for missing ":endif".
3803 * Return FALSE when not sourcing a file.
3804 */
3805 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003806source_finished(fgetline, cookie)
3807 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 void *cookie;
3809{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003810 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003811 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003812 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813}
3814#endif
3815
3816#if defined(FEAT_LISTCMDS) || defined(PROTO)
3817/*
3818 * ":checktime [buffer]"
3819 */
3820 void
3821ex_checktime(eap)
3822 exarg_T *eap;
3823{
3824 buf_T *buf;
3825 int save_no_check_timestamps = no_check_timestamps;
3826
3827 no_check_timestamps = 0;
3828 if (eap->addr_count == 0) /* default is all buffers */
3829 check_timestamps(FALSE);
3830 else
3831 {
3832 buf = buflist_findnr((int)eap->line2);
3833 if (buf != NULL) /* cannot happen? */
3834 (void)buf_check_timestamp(buf, FALSE);
3835 }
3836 no_check_timestamps = save_no_check_timestamps;
3837}
3838#endif
3839
Bram Moolenaar071d4272004-06-13 20:20:40 +00003840#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3841 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003842# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003843static char *get_locale_val __ARGS((int what));
3844
3845 static char *
3846get_locale_val(what)
3847 int what;
3848{
3849 char *loc;
3850
3851 /* Obtain the locale value from the libraries. For DJGPP this is
3852 * redefined and it doesn't use the arguments. */
3853 loc = setlocale(what, NULL);
3854
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003855# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856 if (loc != NULL)
3857 {
3858 char_u *p;
3859
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003860 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3861 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003862 p = vim_strchr(loc, '=');
3863 if (p != NULL)
3864 {
3865 loc = ++p;
3866 while (*p != NUL) /* remove trailing newline */
3867 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003868 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003869 {
3870 *p = NUL;
3871 break;
3872 }
3873 ++p;
3874 }
3875 }
3876 }
3877# endif
3878
3879 return loc;
3880}
3881#endif
3882
3883
3884#ifdef WIN32
3885/*
3886 * On MS-Windows locale names are strings like "German_Germany.1252", but
3887 * gettext expects "de". Try to translate one into another here for a few
3888 * supported languages.
3889 */
3890 static char_u *
3891gettext_lang(char_u *name)
3892{
3893 int i;
3894 static char *(mtable[]) = {
3895 "afrikaans", "af",
3896 "czech", "cs",
3897 "dutch", "nl",
3898 "german", "de",
3899 "english_united kingdom", "en_GB",
3900 "spanish", "es",
3901 "french", "fr",
3902 "italian", "it",
3903 "japanese", "ja",
3904 "korean", "ko",
3905 "norwegian", "no",
3906 "polish", "pl",
3907 "russian", "ru",
3908 "slovak", "sk",
3909 "swedish", "sv",
3910 "ukrainian", "uk",
3911 "chinese_china", "zh_CN",
3912 "chinese_taiwan", "zh_TW",
3913 NULL};
3914
3915 for (i = 0; mtable[i] != NULL; i += 2)
3916 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3917 return mtable[i + 1];
3918 return name;
3919}
3920#endif
3921
3922#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3923/*
3924 * Obtain the current messages language. Used to set the default for
3925 * 'helplang'. May return NULL or an empty string.
3926 */
3927 char_u *
3928get_mess_lang()
3929{
3930 char_u *p;
3931
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003932# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933# if defined(LC_MESSAGES)
3934 p = (char_u *)get_locale_val(LC_MESSAGES);
3935# else
3936 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003937 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3938 * and LC_MONETARY may be set differently for a Japanese working in the
3939 * US. */
3940 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003941# endif
3942# else
3943 p = mch_getenv((char_u *)"LC_ALL");
3944 if (p == NULL || *p == NUL)
3945 {
3946 p = mch_getenv((char_u *)"LC_MESSAGES");
3947 if (p == NULL || *p == NUL)
3948 p = mch_getenv((char_u *)"LANG");
3949 }
3950# endif
3951# ifdef WIN32
3952 p = gettext_lang(p);
3953# endif
3954 return p;
3955}
3956#endif
3957
Bram Moolenaardef9e822004-12-31 20:58:58 +00003958/* Complicated #if; matches with where get_mess_env() is used below. */
3959#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3960 && defined(LC_MESSAGES))) \
3961 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3962 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3963 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003964static char_u *get_mess_env __ARGS((void));
3965
3966/*
3967 * Get the language used for messages from the environment.
3968 */
3969 static char_u *
3970get_mess_env()
3971{
3972 char_u *p;
3973
3974 p = mch_getenv((char_u *)"LC_ALL");
3975 if (p == NULL || *p == NUL)
3976 {
3977 p = mch_getenv((char_u *)"LC_MESSAGES");
3978 if (p == NULL || *p == NUL)
3979 {
3980 p = mch_getenv((char_u *)"LANG");
3981 if (p != NULL && VIM_ISDIGIT(*p))
3982 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003983# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003984 if (p == NULL || *p == NUL)
3985 p = (char_u *)get_locale_val(LC_CTYPE);
3986# endif
3987 }
3988 }
3989 return p;
3990}
3991#endif
3992
3993#if defined(FEAT_EVAL) || defined(PROTO)
3994
3995/*
3996 * Set the "v:lang" variable according to the current locale setting.
3997 * Also do "v:lc_time"and "v:ctype".
3998 */
3999 void
4000set_lang_var()
4001{
4002 char_u *loc;
4003
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004004# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004005 loc = (char_u *)get_locale_val(LC_CTYPE);
4006# else
4007 /* setlocale() not supported: use the default value */
4008 loc = (char_u *)"C";
4009# endif
4010 set_vim_var_string(VV_CTYPE, loc, -1);
4011
4012 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4013 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004014# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015 loc = (char_u *)get_locale_val(LC_MESSAGES);
4016# else
4017 loc = get_mess_env();
4018# endif
4019 set_vim_var_string(VV_LANG, loc, -1);
4020
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004021# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 loc = (char_u *)get_locale_val(LC_TIME);
4023# endif
4024 set_vim_var_string(VV_LC_TIME, loc, -1);
4025}
4026#endif
4027
4028#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4029 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4030/*
4031 * ":language": Set the language (locale).
4032 */
4033 void
4034ex_language(eap)
4035 exarg_T *eap;
4036{
4037 char *loc;
4038 char_u *p;
4039 char_u *name;
4040 int what = LC_ALL;
4041 char *whatstr = "";
4042#ifdef LC_MESSAGES
4043# define VIM_LC_MESSAGES LC_MESSAGES
4044#else
4045# define VIM_LC_MESSAGES 6789
4046#endif
4047
4048 name = eap->arg;
4049
4050 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4051 * Allow abbreviation, but require at least 3 characters to avoid
4052 * confusion with a two letter language name "me" or "ct". */
4053 p = skiptowhite(eap->arg);
4054 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4055 {
4056 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4057 {
4058 what = VIM_LC_MESSAGES;
4059 name = skipwhite(p);
4060 whatstr = "messages ";
4061 }
4062 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4063 {
4064 what = LC_CTYPE;
4065 name = skipwhite(p);
4066 whatstr = "ctype ";
4067 }
4068 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4069 {
4070 what = LC_TIME;
4071 name = skipwhite(p);
4072 whatstr = "time ";
4073 }
4074 }
4075
4076 if (*name == NUL)
4077 {
4078#ifndef LC_MESSAGES
4079 if (what == VIM_LC_MESSAGES)
4080 p = get_mess_env();
4081 else
4082#endif
4083 p = (char_u *)setlocale(what, NULL);
4084 if (p == NULL || *p == NUL)
4085 p = (char_u *)"Unknown";
4086 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4087 }
4088 else
4089 {
4090#ifndef LC_MESSAGES
4091 if (what == VIM_LC_MESSAGES)
4092 loc = "";
4093 else
4094#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004095 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004097#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4098 /* Make sure strtod() uses a decimal point, not a comma. */
4099 setlocale(LC_NUMERIC, "C");
4100#endif
4101 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004102 if (loc == NULL)
4103 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4104 else
4105 {
4106#ifdef HAVE_NL_MSG_CAT_CNTR
4107 /* Need to do this for GNU gettext, otherwise cached translations
4108 * will be used again. */
4109 extern int _nl_msg_cat_cntr;
4110
4111 ++_nl_msg_cat_cntr;
4112#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004113 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4115
4116 if (what != LC_TIME)
4117 {
4118 /* Tell gettext() what to translate to. It apparently doesn't
4119 * use the currently effective locale. Also do this when
4120 * FEAT_GETTEXT isn't defined, so that shell commands use this
4121 * value. */
4122 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004123 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004124 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004125# ifdef WIN32
4126 /* Apparently MS-Windows printf() may cause a crash when
4127 * we give it 8-bit text while it's expecting text in the
4128 * current locale. This call avoids that. */
4129 setlocale(LC_CTYPE, "C");
4130# endif
4131 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004132 if (what != LC_CTYPE)
4133 {
4134 char_u *mname;
4135#ifdef WIN32
4136 mname = gettext_lang(name);
4137#else
4138 mname = name;
4139#endif
4140 vim_setenv((char_u *)"LC_MESSAGES", mname);
4141#ifdef FEAT_MULTI_LANG
4142 set_helplang_default(mname);
4143#endif
4144 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004145 }
4146
4147# ifdef FEAT_EVAL
4148 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4149 set_lang_var();
4150# endif
4151 }
4152 }
4153}
4154
4155# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4156/*
4157 * Function given to ExpandGeneric() to obtain the possible arguments of the
4158 * ":language" command.
4159 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004160 char_u *
4161get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004162 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163 int idx;
4164{
4165 if (idx == 0)
4166 return (char_u *)"messages";
4167 if (idx == 1)
4168 return (char_u *)"ctype";
4169 if (idx == 2)
4170 return (char_u *)"time";
4171 return NULL;
4172}
4173# endif
4174
4175#endif