blob: 4a860ca885d9b6d3c3343f5c877ee12b3ddc10cb [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;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000599 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200600 {
601#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000602 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200603#else
604 ex_ni(eap);
605 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000606#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200607 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608
609 if (vim_isdigit(*eap->arg))
610 {
611 /* ":breakdel {nr}" */
612 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000613 for (i = 0; i < gap->ga_len; ++i)
614 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 {
616 todel = i;
617 break;
618 }
619 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000620 else if (*eap->arg == '*')
621 {
622 todel = 0;
623 del_all = TRUE;
624 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 else
626 {
627 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000628 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000630 bp = &DEBUGGY(gap, gap->ga_len);
631 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000633 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 if (bp->dbg_type == bpi->dbg_type
635 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
636 && (bp->dbg_lnum == bpi->dbg_lnum
637 || (bp->dbg_lnum == 0
638 && (best_lnum == 0
639 || bpi->dbg_lnum < best_lnum))))
640 {
641 todel = i;
642 best_lnum = bpi->dbg_lnum;
643 }
644 }
645 vim_free(bp->dbg_name);
646 }
647
648 if (todel < 0)
649 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
650 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000651 {
652 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000653 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000654 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200655 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000656 --gap->ga_len;
657 if (todel < gap->ga_len)
658 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
659 (gap->ga_len - todel) * sizeof(struct debuggy));
660#ifdef FEAT_PROFILE
661 if (eap->cmdidx == CMD_breakdel)
662#endif
663 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000664 if (!del_all)
665 break;
666 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000667
668 /* If all breakpoints were removed clear the array. */
669 if (gap->ga_len == 0)
670 ga_clear(gap);
671 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672}
673
674/*
675 * ":breaklist".
676 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677 void
678ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000679 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680{
681 struct debuggy *bp;
682 int i;
683
684 if (dbg_breakp.ga_len == 0)
685 MSG(_("No breakpoints defined"));
686 else
687 for (i = 0; i < dbg_breakp.ga_len; ++i)
688 {
689 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200690 if (bp->dbg_type == DBG_FILE)
691 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 smsg((char_u *)_("%3d %s %s line %ld"),
693 bp->dbg_nr,
694 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200695 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 (long)bp->dbg_lnum);
697 }
698}
699
700/*
701 * Find a breakpoint for a function or sourced file.
702 * Returns line number at which to break; zero when no matching breakpoint.
703 */
704 linenr_T
705dbg_find_breakpoint(file, fname, after)
706 int file; /* TRUE for a file, FALSE for a function */
707 char_u *fname; /* file or function name */
708 linenr_T after; /* after this line number */
709{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000710 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
711}
712
713#if defined(FEAT_PROFILE) || defined(PROTO)
714/*
715 * Return TRUE if profiling is on for a function or sourced file.
716 */
717 int
718has_profiling(file, fname, fp)
719 int file; /* TRUE for a file, FALSE for a function */
720 char_u *fname; /* file or function name */
721 int *fp; /* return: forceit */
722{
723 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
724 != (linenr_T)0);
725}
726#endif
727
728/*
729 * Common code for dbg_find_breakpoint() and has_profiling().
730 */
731 static linenr_T
732debuggy_find(file, fname, after, gap, fp)
733 int file; /* TRUE for a file, FALSE for a function */
734 char_u *fname; /* file or function name */
735 linenr_T after; /* after this line number */
736 garray_T *gap; /* either &dbg_breakp or &prof_ga */
737 int *fp; /* if not NULL: return forceit */
738{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 struct debuggy *bp;
740 int i;
741 linenr_T lnum = 0;
742 regmatch_T regmatch;
743 char_u *name = fname;
744 int prev_got_int;
745
Bram Moolenaar05159a02005-02-26 23:04:13 +0000746 /* Return quickly when there are no breakpoints. */
747 if (gap->ga_len == 0)
748 return (linenr_T)0;
749
Bram Moolenaar071d4272004-06-13 20:20:40 +0000750 /* Replace K_SNR in function name with "<SNR>". */
751 if (!file && fname[0] == K_SPECIAL)
752 {
753 name = alloc((unsigned)STRLEN(fname) + 3);
754 if (name == NULL)
755 name = fname;
756 else
757 {
758 STRCPY(name, "<SNR>");
759 STRCPY(name + 5, fname + 3);
760 }
761 }
762
Bram Moolenaar05159a02005-02-26 23:04:13 +0000763 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000765 /* Skip entries that are not useful or are for a line that is beyond
766 * an already found breakpoint. */
767 bp = &DEBUGGY(gap, i);
768 if (((bp->dbg_type == DBG_FILE) == file && (
769#ifdef FEAT_PROFILE
770 gap == &prof_ga ||
771#endif
772 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 {
774 regmatch.regprog = bp->dbg_prog;
775 regmatch.rm_ic = FALSE;
776 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000777 * Save the value of got_int and reset it. We don't want a
778 * previous interruption cancel matching, only hitting CTRL-C
779 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 */
781 prev_got_int = got_int;
782 got_int = FALSE;
783 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000784 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000786 if (fp != NULL)
787 *fp = bp->dbg_forceit;
788 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789 got_int |= prev_got_int;
790 }
791 }
792 if (name != fname)
793 vim_free(name);
794
795 return lnum;
796}
797
798/*
799 * Called when a breakpoint was encountered.
800 */
801 void
802dbg_breakpoint(name, lnum)
803 char_u *name;
804 linenr_T lnum;
805{
806 /* We need to check if this line is actually executed in do_one_cmd() */
807 debug_breakpoint_name = name;
808 debug_breakpoint_lnum = lnum;
809}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000810
811
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000812# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000813/*
814 * Store the current time in "tm".
815 */
816 void
817profile_start(tm)
818 proftime_T *tm;
819{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000820# ifdef WIN3264
821 QueryPerformanceCounter(tm);
822# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000823 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000824# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000825}
826
827/*
828 * Compute the elapsed time from "tm" till now and store in "tm".
829 */
830 void
831profile_end(tm)
832 proftime_T *tm;
833{
834 proftime_T now;
835
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000836# ifdef WIN3264
837 QueryPerformanceCounter(&now);
838 tm->QuadPart = now.QuadPart - tm->QuadPart;
839# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000840 gettimeofday(&now, NULL);
841 tm->tv_usec = now.tv_usec - tm->tv_usec;
842 tm->tv_sec = now.tv_sec - tm->tv_sec;
843 if (tm->tv_usec < 0)
844 {
845 tm->tv_usec += 1000000;
846 --tm->tv_sec;
847 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000848# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000849}
850
851/*
852 * Subtract the time "tm2" from "tm".
853 */
854 void
855profile_sub(tm, tm2)
856 proftime_T *tm, *tm2;
857{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000858# ifdef WIN3264
859 tm->QuadPart -= tm2->QuadPart;
860# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861 tm->tv_usec -= tm2->tv_usec;
862 tm->tv_sec -= tm2->tv_sec;
863 if (tm->tv_usec < 0)
864 {
865 tm->tv_usec += 1000000;
866 --tm->tv_sec;
867 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000868# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000869}
870
871/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000872 * Return a string that represents the time in "tm".
873 * Uses a static buffer!
874 */
875 char *
876profile_msg(tm)
877 proftime_T *tm;
878{
879 static char buf[50];
880
881# ifdef WIN3264
882 LARGE_INTEGER fr;
883
884 QueryPerformanceFrequency(&fr);
885 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
886# else
887 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000888# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000889 return buf;
890}
891
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000892/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000893 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000894 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000895 void
896profile_setlimit(msec, tm)
897 long msec;
898 proftime_T *tm;
899{
900 if (msec <= 0) /* no limit */
901 profile_zero(tm);
902 else
903 {
904# ifdef WIN3264
905 LARGE_INTEGER fr;
906
907 QueryPerformanceCounter(tm);
908 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000909 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000910# else
911 long usec;
912
913 gettimeofday(tm, NULL);
914 usec = (long)tm->tv_usec + (long)msec * 1000;
915 tm->tv_usec = usec % 1000000L;
916 tm->tv_sec += usec / 1000000L;
917# endif
918 }
919}
920
921/*
922 * Return TRUE if the current time is past "tm".
923 */
924 int
925profile_passed_limit(tm)
926 proftime_T *tm;
927{
928 proftime_T now;
929
930# ifdef WIN3264
931 if (tm->QuadPart == 0) /* timer was not set */
932 return FALSE;
933 QueryPerformanceCounter(&now);
934 return (now.QuadPart > tm->QuadPart);
935# else
936 if (tm->tv_sec == 0) /* timer was not set */
937 return FALSE;
938 gettimeofday(&now, NULL);
939 return (now.tv_sec > tm->tv_sec
940 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
941# endif
942}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000943
944/*
945 * Set the time in "tm" to zero.
946 */
947 void
948profile_zero(tm)
949 proftime_T *tm;
950{
951# ifdef WIN3264
952 tm->QuadPart = 0;
953# else
954 tm->tv_usec = 0;
955 tm->tv_sec = 0;
956# endif
957}
958
Bram Moolenaar76929292008-01-06 19:07:36 +0000959# endif /* FEAT_PROFILE || FEAT_RELTIME */
960
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200961#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
962# if defined(HAVE_MATH_H)
963# include <math.h>
964# endif
965
966/*
967 * Divide the time "tm" by "count" and store in "tm2".
968 */
969 void
970profile_divide(tm, count, tm2)
971 proftime_T *tm;
972 proftime_T *tm2;
973 int count;
974{
975 if (count == 0)
976 profile_zero(tm2);
977 else
978 {
979# ifdef WIN3264
980 tm2->QuadPart = tm->QuadPart / count;
981# else
982 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
983
984 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +0200985 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200986# endif
987 }
988}
989#endif
990
Bram Moolenaar76929292008-01-06 19:07:36 +0000991# if defined(FEAT_PROFILE) || defined(PROTO)
992/*
993 * Functions for profiling.
994 */
995static void script_do_profile __ARGS((scriptitem_T *si));
996static void script_dump_profile __ARGS((FILE *fd));
997static proftime_T prof_wait_time;
998
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000999/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001000 * Add the time "tm2" to "tm".
1001 */
1002 void
1003profile_add(tm, tm2)
1004 proftime_T *tm, *tm2;
1005{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001006# ifdef WIN3264
1007 tm->QuadPart += tm2->QuadPart;
1008# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001009 tm->tv_usec += tm2->tv_usec;
1010 tm->tv_sec += tm2->tv_sec;
1011 if (tm->tv_usec >= 1000000)
1012 {
1013 tm->tv_usec -= 1000000;
1014 ++tm->tv_sec;
1015 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001016# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001017}
1018
1019/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001020 * Add the "self" time from the total time and the children's time.
1021 */
1022 void
1023profile_self(self, total, children)
1024 proftime_T *self, *total, *children;
1025{
1026 /* Check that the result won't be negative. Can happen with recursive
1027 * calls. */
1028#ifdef WIN3264
1029 if (total->QuadPart <= children->QuadPart)
1030 return;
1031#else
1032 if (total->tv_sec < children->tv_sec
1033 || (total->tv_sec == children->tv_sec
1034 && total->tv_usec <= children->tv_usec))
1035 return;
1036#endif
1037 profile_add(self, total);
1038 profile_sub(self, children);
1039}
1040
1041/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001042 * Get the current waittime.
1043 */
1044 void
1045profile_get_wait(tm)
1046 proftime_T *tm;
1047{
1048 *tm = prof_wait_time;
1049}
1050
1051/*
1052 * Subtract the passed waittime since "tm" from "tma".
1053 */
1054 void
1055profile_sub_wait(tm, tma)
1056 proftime_T *tm, *tma;
1057{
1058 proftime_T tm3 = prof_wait_time;
1059
1060 profile_sub(&tm3, tm);
1061 profile_sub(tma, &tm3);
1062}
1063
1064/*
1065 * Return TRUE if "tm1" and "tm2" are equal.
1066 */
1067 int
1068profile_equal(tm1, tm2)
1069 proftime_T *tm1, *tm2;
1070{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001071# ifdef WIN3264
1072 return (tm1->QuadPart == tm2->QuadPart);
1073# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001074 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001075# endif
1076}
1077
1078/*
1079 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1080 */
1081 int
1082profile_cmp(tm1, tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001083 const proftime_T *tm1, *tm2;
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001084{
1085# ifdef WIN3264
1086 return (int)(tm2->QuadPart - tm1->QuadPart);
1087# else
1088 if (tm1->tv_sec == tm2->tv_sec)
1089 return tm2->tv_usec - tm1->tv_usec;
1090 return tm2->tv_sec - tm1->tv_sec;
1091# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001092}
1093
Bram Moolenaar05159a02005-02-26 23:04:13 +00001094static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001095static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001096
1097/*
1098 * ":profile cmd args"
1099 */
1100 void
1101ex_profile(eap)
1102 exarg_T *eap;
1103{
1104 char_u *e;
1105 int len;
1106
1107 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001108 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001109 e = skipwhite(e);
1110
1111 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1112 {
1113 vim_free(profile_fname);
1114 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001115 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001116 profile_zero(&prof_wait_time);
1117 set_vim_var_nr(VV_PROFILING, 1L);
1118 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001119 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001120 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001121 else if (STRCMP(eap->arg, "pause") == 0)
1122 {
1123 if (do_profiling == PROF_YES)
1124 profile_start(&pause_time);
1125 do_profiling = PROF_PAUSED;
1126 }
1127 else if (STRCMP(eap->arg, "continue") == 0)
1128 {
1129 if (do_profiling == PROF_PAUSED)
1130 {
1131 profile_end(&pause_time);
1132 profile_add(&prof_wait_time, &pause_time);
1133 }
1134 do_profiling = PROF_YES;
1135 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001136 else
1137 {
1138 /* The rest is similar to ":breakadd". */
1139 ex_breakadd(eap);
1140 }
1141}
1142
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001143/* Command line expansion for :profile. */
1144static enum
1145{
1146 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001147 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001148} pexpand_what;
1149
1150static char *pexpand_cmds[] = {
1151 "start",
1152#define PROFCMD_START 0
1153 "pause",
1154#define PROFCMD_PAUSE 1
1155 "continue",
1156#define PROFCMD_CONTINUE 2
1157 "func",
1158#define PROFCMD_FUNC 3
1159 "file",
1160#define PROFCMD_FILE 4
1161 NULL
1162#define PROFCMD_LAST 5
1163};
1164
1165/*
1166 * Function given to ExpandGeneric() to obtain the profile command
1167 * specific expansion.
1168 */
1169 char_u *
1170get_profile_name(xp, idx)
1171 expand_T *xp UNUSED;
1172 int idx;
1173{
1174 switch (pexpand_what)
1175 {
1176 case PEXP_SUBCMD:
1177 return (char_u *)pexpand_cmds[idx];
1178 /* case PEXP_FUNC: TODO */
1179 default:
1180 return NULL;
1181 }
1182}
1183
1184/*
1185 * Handle command line completion for :profile command.
1186 */
1187 void
1188set_context_in_profile_cmd(xp, arg)
1189 expand_T *xp;
1190 char_u *arg;
1191{
1192 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001193
1194 /* Default: expand subcommands. */
1195 xp->xp_context = EXPAND_PROFILE;
1196 pexpand_what = PEXP_SUBCMD;
1197 xp->xp_pattern = arg;
1198
1199 end_subcmd = skiptowhite(arg);
1200 if (*end_subcmd == NUL)
1201 return;
1202
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001203 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001204 {
1205 xp->xp_context = EXPAND_FILES;
1206 xp->xp_pattern = skipwhite(end_subcmd);
1207 return;
1208 }
1209
1210 /* TODO: expand function names after "func" */
1211 xp->xp_context = EXPAND_NOTHING;
1212}
1213
Bram Moolenaar05159a02005-02-26 23:04:13 +00001214/*
1215 * Dump the profiling info.
1216 */
1217 void
1218profile_dump()
1219{
1220 FILE *fd;
1221
1222 if (profile_fname != NULL)
1223 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001224 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001225 if (fd == NULL)
1226 EMSG2(_(e_notopen), profile_fname);
1227 else
1228 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001229 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001230 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001231 fclose(fd);
1232 }
1233 }
1234}
1235
1236/*
1237 * Start profiling script "fp".
1238 */
1239 static void
1240script_do_profile(si)
1241 scriptitem_T *si;
1242{
1243 si->sn_pr_count = 0;
1244 profile_zero(&si->sn_pr_total);
1245 profile_zero(&si->sn_pr_self);
1246
1247 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1248 si->sn_prl_idx = -1;
1249 si->sn_prof_on = TRUE;
1250 si->sn_pr_nest = 0;
1251}
1252
1253/*
1254 * save time when starting to invoke another script or function.
1255 */
1256 void
1257script_prof_save(tm)
1258 proftime_T *tm; /* place to store wait time */
1259{
1260 scriptitem_T *si;
1261
1262 if (current_SID > 0 && current_SID <= script_items.ga_len)
1263 {
1264 si = &SCRIPT_ITEM(current_SID);
1265 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1266 profile_start(&si->sn_pr_child);
1267 }
1268 profile_get_wait(tm);
1269}
1270
1271/*
1272 * Count time spent in children after invoking another script or function.
1273 */
1274 void
1275script_prof_restore(tm)
1276 proftime_T *tm;
1277{
1278 scriptitem_T *si;
1279
1280 if (current_SID > 0 && current_SID <= script_items.ga_len)
1281 {
1282 si = &SCRIPT_ITEM(current_SID);
1283 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1284 {
1285 profile_end(&si->sn_pr_child);
1286 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1287 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1288 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1289 }
1290 }
1291}
1292
1293static proftime_T inchar_time;
1294
1295/*
1296 * Called when starting to wait for the user to type a character.
1297 */
1298 void
1299prof_inchar_enter()
1300{
1301 profile_start(&inchar_time);
1302}
1303
1304/*
1305 * Called when finished waiting for the user to type a character.
1306 */
1307 void
1308prof_inchar_exit()
1309{
1310 profile_end(&inchar_time);
1311 profile_add(&prof_wait_time, &inchar_time);
1312}
1313
1314/*
1315 * Dump the profiling results for all scripts in file "fd".
1316 */
1317 static void
1318script_dump_profile(fd)
1319 FILE *fd;
1320{
1321 int id;
1322 scriptitem_T *si;
1323 int i;
1324 FILE *sfd;
1325 sn_prl_T *pp;
1326
1327 for (id = 1; id <= script_items.ga_len; ++id)
1328 {
1329 si = &SCRIPT_ITEM(id);
1330 if (si->sn_prof_on)
1331 {
1332 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1333 if (si->sn_pr_count == 1)
1334 fprintf(fd, "Sourced 1 time\n");
1335 else
1336 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1337 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1338 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1339 fprintf(fd, "\n");
1340 fprintf(fd, "count total (s) self (s)\n");
1341
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001342 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001343 if (sfd == NULL)
1344 fprintf(fd, "Cannot open file!\n");
1345 else
1346 {
1347 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1348 {
1349 if (vim_fgets(IObuff, IOSIZE, sfd))
1350 break;
1351 pp = &PRL_ITEM(si, i);
1352 if (pp->snp_count > 0)
1353 {
1354 fprintf(fd, "%5d ", pp->snp_count);
1355 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1356 fprintf(fd, " ");
1357 else
1358 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1359 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1360 }
1361 else
1362 fprintf(fd, " ");
1363 fprintf(fd, "%s", IObuff);
1364 }
1365 fclose(sfd);
1366 }
1367 fprintf(fd, "\n");
1368 }
1369 }
1370}
1371
1372/*
1373 * Return TRUE when a function defined in the current script should be
1374 * profiled.
1375 */
1376 int
1377prof_def_func()
1378{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001379 if (current_SID > 0)
1380 return SCRIPT_ITEM(current_SID).sn_pr_force;
1381 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001382}
1383
1384# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001385#endif
1386
1387/*
1388 * If 'autowrite' option set, try to write the file.
1389 * Careful: autocommands may make "buf" invalid!
1390 *
1391 * return FAIL for failure, OK otherwise
1392 */
1393 int
1394autowrite(buf, forceit)
1395 buf_T *buf;
1396 int forceit;
1397{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001398 int r;
1399
Bram Moolenaar071d4272004-06-13 20:20:40 +00001400 if (!(p_aw || p_awa) || !p_write
1401#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001402 /* never autowrite a "nofile" or "nowrite" buffer */
1403 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001404#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001405 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001406 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001407 r = buf_write_all(buf, forceit);
1408
1409 /* Writing may succeed but the buffer still changed, e.g., when there is a
1410 * conversion error. We do want to return FAIL then. */
1411 if (buf_valid(buf) && bufIsChanged(buf))
1412 r = FAIL;
1413 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001414}
1415
1416/*
1417 * flush all buffers, except the ones that are readonly
1418 */
1419 void
1420autowrite_all()
1421{
1422 buf_T *buf;
1423
1424 if (!(p_aw || p_awa) || !p_write)
1425 return;
1426 for (buf = firstbuf; buf; buf = buf->b_next)
1427 if (bufIsChanged(buf) && !buf->b_p_ro)
1428 {
1429 (void)buf_write_all(buf, FALSE);
1430#ifdef FEAT_AUTOCMD
1431 /* an autocommand may have deleted the buffer */
1432 if (!buf_valid(buf))
1433 buf = firstbuf;
1434#endif
1435 }
1436}
1437
1438/*
1439 * return TRUE if buffer was changed and cannot be abandoned.
1440 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001441 int
1442check_changed(buf, checkaw, mult_win, forceit, allbuf)
1443 buf_T *buf;
1444 int checkaw; /* do autowrite if buffer was changed */
1445 int mult_win; /* check also when several wins for the buf */
1446 int forceit;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001447 int allbuf UNUSED; /* may write all buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001448{
1449 if ( !forceit
1450 && bufIsChanged(buf)
1451 && (mult_win || buf->b_nwindows <= 1)
1452 && (!checkaw || autowrite(buf, forceit) == FAIL))
1453 {
1454#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1455 if ((p_confirm || cmdmod.confirm) && p_write)
1456 {
1457 buf_T *buf2;
1458 int count = 0;
1459
1460 if (allbuf)
1461 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1462 if (bufIsChanged(buf2)
1463 && (buf2->b_ffname != NULL
1464# ifdef FEAT_BROWSE
1465 || cmdmod.browse
1466# endif
1467 ))
1468 ++count;
1469# ifdef FEAT_AUTOCMD
1470 if (!buf_valid(buf))
1471 /* Autocommand deleted buffer, oops! It's not changed now. */
1472 return FALSE;
1473# endif
1474 dialog_changed(buf, count > 1);
1475# ifdef FEAT_AUTOCMD
1476 if (!buf_valid(buf))
1477 /* Autocommand deleted buffer, oops! It's not changed now. */
1478 return FALSE;
1479# endif
1480 return bufIsChanged(buf);
1481 }
1482#endif
1483 EMSG(_(e_nowrtmsg));
1484 return TRUE;
1485 }
1486 return FALSE;
1487}
1488
1489#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1490
1491#if defined(FEAT_BROWSE) || defined(PROTO)
1492/*
1493 * When wanting to write a file without a file name, ask the user for a name.
1494 */
1495 void
1496browse_save_fname(buf)
1497 buf_T *buf;
1498{
1499 if (buf->b_fname == NULL)
1500 {
1501 char_u *fname;
1502
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001503 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1504 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001505 if (fname != NULL)
1506 {
1507 if (setfname(buf, fname, NULL, TRUE) == OK)
1508 buf->b_flags |= BF_NOTEDITED;
1509 vim_free(fname);
1510 }
1511 }
1512}
1513#endif
1514
1515/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001516 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001517 * Must check 'write' option first!
1518 */
1519 void
1520dialog_changed(buf, checkall)
1521 buf_T *buf;
1522 int checkall; /* may abandon all changed buffers */
1523{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001524 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001525 int ret;
1526 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001527 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001528
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001529 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530 (buf->b_fname != NULL) ?
1531 buf->b_fname : (char_u *)_("Untitled"));
1532 if (checkall)
1533 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1534 else
1535 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1536
Bram Moolenaar8218f602012-04-25 17:32:18 +02001537 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1538 * function. */
1539 ea.append = ea.forceit = FALSE;
1540
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541 if (ret == VIM_YES)
1542 {
1543#ifdef FEAT_BROWSE
1544 /* May get file name, when there is none */
1545 browse_save_fname(buf);
1546#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001547 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1548 buf->b_fname, buf->b_ffname, FALSE) == OK)
1549 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550 (void)buf_write_all(buf, FALSE);
1551 }
1552 else if (ret == VIM_NO)
1553 {
1554 unchanged(buf, TRUE);
1555 }
1556 else if (ret == VIM_ALL)
1557 {
1558 /*
1559 * Write all modified files that can be written.
1560 * Skip readonly buffers, these need to be confirmed
1561 * individually.
1562 */
1563 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1564 {
1565 if (bufIsChanged(buf2)
1566 && (buf2->b_ffname != NULL
1567#ifdef FEAT_BROWSE
1568 || cmdmod.browse
1569#endif
1570 )
1571 && !buf2->b_p_ro)
1572 {
1573#ifdef FEAT_BROWSE
1574 /* May get file name, when there is none */
1575 browse_save_fname(buf2);
1576#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001577 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1578 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1579 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001580 (void)buf_write_all(buf2, FALSE);
1581#ifdef FEAT_AUTOCMD
1582 /* an autocommand may have deleted the buffer */
1583 if (!buf_valid(buf2))
1584 buf2 = firstbuf;
1585#endif
1586 }
1587 }
1588 }
1589 else if (ret == VIM_DISCARDALL)
1590 {
1591 /*
1592 * mark all buffers as unchanged
1593 */
1594 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1595 unchanged(buf2, TRUE);
1596 }
1597}
1598#endif
1599
1600/*
1601 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1602 * hidden, autowriting it or unloading it.
1603 */
1604 int
1605can_abandon(buf, forceit)
1606 buf_T *buf;
1607 int forceit;
1608{
1609 return ( P_HID(buf)
1610 || !bufIsChanged(buf)
1611 || buf->b_nwindows > 1
1612 || autowrite(buf, forceit) == OK
1613 || forceit);
1614}
1615
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001616static void add_bufnum __ARGS((int *bufnrs, int *bufnump, int nr));
1617
1618/*
1619 * Add a buffer number to "bufnrs", unless it's already there.
1620 */
1621 static void
1622add_bufnum(bufnrs, bufnump, nr)
1623 int *bufnrs;
1624 int *bufnump;
1625 int nr;
1626{
1627 int i;
1628
1629 for (i = 0; i < *bufnump; ++i)
1630 if (bufnrs[i] == nr)
1631 return;
1632 bufnrs[*bufnump] = nr;
1633 *bufnump = *bufnump + 1;
1634}
1635
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636/*
1637 * Return TRUE if any buffer was changed and cannot be abandoned.
1638 * That changed buffer becomes the current buffer.
1639 */
1640 int
1641check_changed_any(hidden)
1642 int hidden; /* Only check hidden buffers */
1643{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001644 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001645 buf_T *buf;
1646 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001647 int i;
1648 int bufnum = 0;
1649 int bufcount = 0;
1650 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001652 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001653 win_T *wp;
1654#endif
1655
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001656 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1657 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001658
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001659 if (bufcount == 0)
1660 return FALSE;
1661
1662 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1663 if (bufnrs == NULL)
1664 return FALSE;
1665
1666 /* curbuf */
1667 bufnrs[bufnum++] = curbuf->b_fnum;
1668#ifdef FEAT_WINDOWS
1669 /* buf in curtab */
1670 FOR_ALL_WINDOWS(wp)
1671 if (wp->w_buffer != curbuf)
1672 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1673
1674 /* buf in other tab */
1675 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1676 if (tp != curtab)
1677 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1678 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1679#endif
1680 /* any other buf */
1681 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1682 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1683
1684 for (i = 0; i < bufnum; ++i)
1685 {
1686 buf = buflist_findnr(bufnrs[i]);
1687 if (buf == NULL)
1688 continue;
1689 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1690 {
1691 /* Try auto-writing the buffer. If this fails but the buffer no
1692 * longer exists it's not changed, that's OK. */
1693 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1694 break; /* didn't save - still changes */
1695 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696 }
1697
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001698 if (i >= bufnum)
1699 goto theend;
1700
1701 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001702 exiting = FALSE;
1703#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1704 /*
1705 * When ":confirm" used, don't give an error message.
1706 */
1707 if (!(p_confirm || cmdmod.confirm))
1708#endif
1709 {
1710 /* There must be a wait_return for this message, do_buffer()
1711 * may cause a redraw. But wait_return() is a no-op when vgetc()
1712 * is busy (Quit used from window menu), then make sure we don't
1713 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001714 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715 {
1716 msg_row = cmdline_row;
1717 msg_col = 0;
1718 msg_didout = FALSE;
1719 }
1720 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001721 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722 {
1723 save = no_wait_return;
1724 no_wait_return = FALSE;
1725 wait_return(FALSE);
1726 no_wait_return = save;
1727 }
1728 }
1729
1730#ifdef FEAT_WINDOWS
1731 /* Try to find a window that contains the buffer. */
1732 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001733 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 if (wp->w_buffer == buf)
1735 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001736 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737# ifdef FEAT_AUTOCMD
1738 /* Paranoia: did autocms wipe out the buffer with changes? */
1739 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001740 {
1741 goto theend;
1742 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001744 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001746buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747#endif
1748
1749 /* Open the changed buffer in the current window. */
1750 if (buf != curbuf)
1751 set_curbuf(buf, DOBUF_GOTO);
1752
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001753theend:
1754 vim_free(bufnrs);
1755 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756}
1757
1758/*
1759 * return FAIL if there is no file name, OK if there is one
1760 * give error message for FAIL
1761 */
1762 int
1763check_fname()
1764{
1765 if (curbuf->b_ffname == NULL)
1766 {
1767 EMSG(_(e_noname));
1768 return FAIL;
1769 }
1770 return OK;
1771}
1772
1773/*
1774 * flush the contents of a buffer, unless it has no file name
1775 *
1776 * return FAIL for failure, OK otherwise
1777 */
1778 int
1779buf_write_all(buf, forceit)
1780 buf_T *buf;
1781 int forceit;
1782{
1783 int retval;
1784#ifdef FEAT_AUTOCMD
1785 buf_T *old_curbuf = curbuf;
1786#endif
1787
1788 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1789 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1790 FALSE, forceit, TRUE, FALSE));
1791#ifdef FEAT_AUTOCMD
1792 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001793 {
1794 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001796 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797#endif
1798 return retval;
1799}
1800
1801/*
1802 * Code to handle the argument list.
1803 */
1804
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001805static char_u *do_one_arg __ARGS((char_u *str));
1806static int do_arglist __ARGS((char_u *str, int what, int after));
1807static void alist_check_arg_idx __ARGS((void));
1808static int editing_arg_idx __ARGS((win_T *win));
1809#ifdef FEAT_LISTCMDS
1810static int alist_add_list __ARGS((int count, char_u **files, int after));
1811#endif
1812#define AL_SET 1
1813#define AL_ADD 2
1814#define AL_DEL 3
1815
Bram Moolenaar071d4272004-06-13 20:20:40 +00001816/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001817 * Isolate one argument, taking backticks.
1818 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819 * Return a pointer to the start of the next argument.
1820 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001821 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822do_one_arg(str)
1823 char_u *str;
1824{
1825 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826 int inbacktick;
1827
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828 inbacktick = FALSE;
1829 for (p = str; *str; ++str)
1830 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001831 /* When the backslash is used for escaping the special meaning of a
1832 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833 if (rem_backslash(str))
1834 {
1835 *p++ = *str++;
1836 *p++ = *str;
1837 }
1838 else
1839 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001840 /* An item ends at a space not in backticks */
1841 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001842 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001843 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001845 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846 }
1847 }
1848 str = skipwhite(str);
1849 *p = NUL;
1850
1851 return str;
1852}
1853
Bram Moolenaar86b68352004-12-27 21:59:20 +00001854/*
1855 * Separate the arguments in "str" and return a list of pointers in the
1856 * growarray "gap".
1857 */
1858 int
1859get_arglist(gap, str)
1860 garray_T *gap;
1861 char_u *str;
1862{
1863 ga_init2(gap, (int)sizeof(char_u *), 20);
1864 while (*str != NUL)
1865 {
1866 if (ga_grow(gap, 1) == FAIL)
1867 {
1868 ga_clear(gap);
1869 return FAIL;
1870 }
1871 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1872
1873 /* Isolate one argument, change it in-place, put a NUL after it. */
1874 str = do_one_arg(str);
1875 }
1876 return OK;
1877}
1878
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001879#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001880/*
1881 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001882 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001883 * Return FAIL or OK.
1884 */
1885 int
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001886get_arglist_exp(str, fcountp, fnamesp, wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001887 char_u *str;
1888 int *fcountp;
1889 char_u ***fnamesp;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001890 int wig;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001891{
1892 garray_T ga;
1893 int i;
1894
1895 if (get_arglist(&ga, str) == FAIL)
1896 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001897 if (wig == TRUE)
1898 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1899 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1900 else
1901 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1902 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1903
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001904 ga_clear(&ga);
1905 return i;
1906}
1907#endif
1908
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1910/*
1911 * Redefine the argument list.
1912 */
1913 void
1914set_arglist(str)
1915 char_u *str;
1916{
1917 do_arglist(str, AL_SET, 0);
1918}
1919#endif
1920
1921/*
1922 * "what" == AL_SET: Redefine the argument list to 'str'.
1923 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1924 * "what" == AL_DEL: remove files in 'str' from the argument list.
1925 *
1926 * Return FAIL for failure, OK otherwise.
1927 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 static int
1929do_arglist(str, what, after)
1930 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001931 int what UNUSED;
1932 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933{
1934 garray_T new_ga;
1935 int exp_count;
1936 char_u **exp_files;
1937 int i;
1938#ifdef FEAT_LISTCMDS
1939 char_u *p;
1940 int match;
1941#endif
1942
1943 /*
1944 * Collect all file name arguments in "new_ga".
1945 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001946 if (get_arglist(&new_ga, str) == FAIL)
1947 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948
1949#ifdef FEAT_LISTCMDS
1950 if (what == AL_DEL)
1951 {
1952 regmatch_T regmatch;
1953 int didone;
1954
1955 /*
1956 * Delete the items: use each item as a regexp and find a match in the
1957 * argument list.
1958 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01001959 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1961 {
1962 p = ((char_u **)new_ga.ga_data)[i];
1963 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1964 if (p == NULL)
1965 break;
1966 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1967 if (regmatch.regprog == NULL)
1968 {
1969 vim_free(p);
1970 break;
1971 }
1972
1973 didone = FALSE;
1974 for (match = 0; match < ARGCOUNT; ++match)
1975 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1976 (colnr_T)0))
1977 {
1978 didone = TRUE;
1979 vim_free(ARGLIST[match].ae_fname);
1980 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1981 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1982 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983 if (curwin->w_arg_idx > match)
1984 --curwin->w_arg_idx;
1985 --match;
1986 }
1987
Bram Moolenaar473de612013-06-08 18:19:48 +02001988 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989 vim_free(p);
1990 if (!didone)
1991 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1992 }
1993 ga_clear(&new_ga);
1994 }
1995 else
1996#endif
1997 {
1998 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1999 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2000 ga_clear(&new_ga);
2001 if (i == FAIL)
2002 return FAIL;
2003 if (exp_count == 0)
2004 {
2005 EMSG(_(e_nomatch));
2006 return FAIL;
2007 }
2008
2009#ifdef FEAT_LISTCMDS
2010 if (what == AL_ADD)
2011 {
2012 (void)alist_add_list(exp_count, exp_files, after);
2013 vim_free(exp_files);
2014 }
2015 else /* what == AL_SET */
2016#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002017 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002018 }
2019
2020 alist_check_arg_idx();
2021
2022 return OK;
2023}
2024
2025/*
2026 * Check the validity of the arg_idx for each other window.
2027 */
2028 static void
2029alist_check_arg_idx()
2030{
2031#ifdef FEAT_WINDOWS
2032 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002033 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002034
Bram Moolenaarf740b292006-02-16 22:11:02 +00002035 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002036 if (win->w_alist == curwin->w_alist)
2037 check_arg_idx(win);
2038#else
2039 check_arg_idx(curwin);
2040#endif
2041}
2042
2043/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002044 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002045 * index.
2046 */
2047 static int
2048editing_arg_idx(win)
2049 win_T *win;
2050{
2051 return !(win->w_arg_idx >= WARGCOUNT(win)
2052 || (win->w_buffer->b_fnum
2053 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2054 && (win->w_buffer->b_ffname == NULL
2055 || !(fullpathcmp(
2056 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2057 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2058}
2059
2060/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002061 * Check if window "win" is editing the w_arg_idx file in its argument list.
2062 */
2063 void
2064check_arg_idx(win)
2065 win_T *win;
2066{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002067 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068 {
2069 /* We are not editing the current entry in the argument list.
2070 * Set "arg_had_last" if we are editing the last one. */
2071 win->w_arg_idx_invalid = TRUE;
2072 if (win->w_arg_idx != WARGCOUNT(win) - 1
2073 && arg_had_last == FALSE
2074#ifdef FEAT_WINDOWS
2075 && ALIST(win) == &global_alist
2076#endif
2077 && GARGCOUNT > 0
2078 && win->w_arg_idx < GARGCOUNT
2079 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2080 || (win->w_buffer->b_ffname != NULL
2081 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2082 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2083 arg_had_last = TRUE;
2084 }
2085 else
2086 {
2087 /* We are editing the current entry in the argument list.
2088 * Set "arg_had_last" if it's also the last one */
2089 win->w_arg_idx_invalid = FALSE;
2090 if (win->w_arg_idx == WARGCOUNT(win) - 1
2091#ifdef FEAT_WINDOWS
2092 && win->w_alist == &global_alist
2093#endif
2094 )
2095 arg_had_last = TRUE;
2096 }
2097}
2098
2099/*
2100 * ":args", ":argslocal" and ":argsglobal".
2101 */
2102 void
2103ex_args(eap)
2104 exarg_T *eap;
2105{
2106 int i;
2107
2108 if (eap->cmdidx != CMD_args)
2109 {
2110#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2111 alist_unlink(ALIST(curwin));
2112 if (eap->cmdidx == CMD_argglobal)
2113 ALIST(curwin) = &global_alist;
2114 else /* eap->cmdidx == CMD_arglocal */
2115 alist_new();
2116#else
2117 ex_ni(eap);
2118 return;
2119#endif
2120 }
2121
2122 if (!ends_excmd(*eap->arg))
2123 {
2124 /*
2125 * ":args file ..": define new argument list, handle like ":next"
2126 * Also for ":argslocal file .." and ":argsglobal file ..".
2127 */
2128 ex_next(eap);
2129 }
2130 else
2131#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2132 if (eap->cmdidx == CMD_args)
2133#endif
2134 {
2135 /*
2136 * ":args": list arguments.
2137 */
2138 if (ARGCOUNT > 0)
2139 {
2140 /* Overwrite the command, for a short list there is no scrolling
2141 * required and no wait_return(). */
2142 gotocmdline(TRUE);
2143 for (i = 0; i < ARGCOUNT; ++i)
2144 {
2145 if (i == curwin->w_arg_idx)
2146 msg_putchar('[');
2147 msg_outtrans(alist_name(&ARGLIST[i]));
2148 if (i == curwin->w_arg_idx)
2149 msg_putchar(']');
2150 msg_putchar(' ');
2151 }
2152 }
2153 }
2154#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2155 else if (eap->cmdidx == CMD_arglocal)
2156 {
2157 garray_T *gap = &curwin->w_alist->al_ga;
2158
2159 /*
2160 * ":argslocal": make a local copy of the global argument list.
2161 */
2162 if (ga_grow(gap, GARGCOUNT) == OK)
2163 for (i = 0; i < GARGCOUNT; ++i)
2164 if (GARGLIST[i].ae_fname != NULL)
2165 {
2166 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2167 vim_strsave(GARGLIST[i].ae_fname);
2168 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2169 GARGLIST[i].ae_fnum;
2170 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002171 }
2172 }
2173#endif
2174}
2175
2176/*
2177 * ":previous", ":sprevious", ":Next" and ":sNext".
2178 */
2179 void
2180ex_previous(eap)
2181 exarg_T *eap;
2182{
2183 /* If past the last one already, go to the last one. */
2184 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2185 do_argfile(eap, ARGCOUNT - 1);
2186 else
2187 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2188}
2189
2190/*
2191 * ":rewind", ":first", ":sfirst" and ":srewind".
2192 */
2193 void
2194ex_rewind(eap)
2195 exarg_T *eap;
2196{
2197 do_argfile(eap, 0);
2198}
2199
2200/*
2201 * ":last" and ":slast".
2202 */
2203 void
2204ex_last(eap)
2205 exarg_T *eap;
2206{
2207 do_argfile(eap, ARGCOUNT - 1);
2208}
2209
2210/*
2211 * ":argument" and ":sargument".
2212 */
2213 void
2214ex_argument(eap)
2215 exarg_T *eap;
2216{
2217 int i;
2218
2219 if (eap->addr_count > 0)
2220 i = eap->line2 - 1;
2221 else
2222 i = curwin->w_arg_idx;
2223 do_argfile(eap, i);
2224}
2225
2226/*
2227 * Edit file "argn" of the argument lists.
2228 */
2229 void
2230do_argfile(eap, argn)
2231 exarg_T *eap;
2232 int argn;
2233{
2234 int other;
2235 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002236 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002237
2238 if (argn < 0 || argn >= ARGCOUNT)
2239 {
2240 if (ARGCOUNT <= 1)
2241 EMSG(_("E163: There is only one file to edit"));
2242 else if (argn < 0)
2243 EMSG(_("E164: Cannot go before first file"));
2244 else
2245 EMSG(_("E165: Cannot go beyond last file"));
2246 }
2247 else
2248 {
2249 setpcmark();
2250#ifdef FEAT_GUI
2251 need_mouse_correct = TRUE;
2252#endif
2253
2254#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002255 /* split window or create new tab page first */
2256 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 {
2258 if (win_split(0, 0) == FAIL)
2259 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002260 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261 }
2262 else
2263#endif
2264 {
2265 /*
2266 * if 'hidden' set, only check for changed file when re-editing
2267 * the same buffer
2268 */
2269 other = TRUE;
2270 if (P_HID(curbuf))
2271 {
2272 p = fix_fname(alist_name(&ARGLIST[argn]));
2273 other = otherfile(p);
2274 vim_free(p);
2275 }
2276 if ((!P_HID(curbuf) || !other)
2277 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2278 return;
2279 }
2280
2281 curwin->w_arg_idx = argn;
2282 if (argn == ARGCOUNT - 1
2283#ifdef FEAT_WINDOWS
2284 && curwin->w_alist == &global_alist
2285#endif
2286 )
2287 arg_had_last = TRUE;
2288
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002289 /* Edit the file; always use the last known line number.
2290 * When it fails (e.g. Abort for already edited file) restore the
2291 * argument index. */
2292 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002294 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2295 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002296 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002298 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002299 setmark('\'');
2300 }
2301}
2302
2303/*
2304 * ":next", and commands that behave like it.
2305 */
2306 void
2307ex_next(eap)
2308 exarg_T *eap;
2309{
2310 int i;
2311
2312 /*
2313 * check for changed buffer now, if this fails the argument list is not
2314 * redefined.
2315 */
2316 if ( P_HID(curbuf)
2317 || eap->cmdidx == CMD_snext
2318 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2319 {
2320 if (*eap->arg != NUL) /* redefine file list */
2321 {
2322 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2323 return;
2324 i = 0;
2325 }
2326 else
2327 i = curwin->w_arg_idx + (int)eap->line2;
2328 do_argfile(eap, i);
2329 }
2330}
2331
2332#ifdef FEAT_LISTCMDS
2333/*
2334 * ":argedit"
2335 */
2336 void
2337ex_argedit(eap)
2338 exarg_T *eap;
2339{
2340 int fnum;
2341 int i;
2342 char_u *s;
2343
2344 /* Add the argument to the buffer list and get the buffer number. */
2345 fnum = buflist_add(eap->arg, BLN_LISTED);
2346
2347 /* Check if this argument is already in the argument list. */
2348 for (i = 0; i < ARGCOUNT; ++i)
2349 if (ARGLIST[i].ae_fnum == fnum)
2350 break;
2351 if (i == ARGCOUNT)
2352 {
2353 /* Can't find it, add it to the argument list. */
2354 s = vim_strsave(eap->arg);
2355 if (s == NULL)
2356 return;
2357 i = alist_add_list(1, &s,
2358 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2359 if (i < 0)
2360 return;
2361 curwin->w_arg_idx = i;
2362 }
2363
2364 alist_check_arg_idx();
2365
2366 /* Edit the argument. */
2367 do_argfile(eap, i);
2368}
2369
2370/*
2371 * ":argadd"
2372 */
2373 void
2374ex_argadd(eap)
2375 exarg_T *eap;
2376{
2377 do_arglist(eap->arg, AL_ADD,
2378 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2379#ifdef FEAT_TITLE
2380 maketitle();
2381#endif
2382}
2383
2384/*
2385 * ":argdelete"
2386 */
2387 void
2388ex_argdelete(eap)
2389 exarg_T *eap;
2390{
2391 int i;
2392 int n;
2393
2394 if (eap->addr_count > 0)
2395 {
2396 /* ":1,4argdel": Delete all arguments in the range. */
2397 if (eap->line2 > ARGCOUNT)
2398 eap->line2 = ARGCOUNT;
2399 n = eap->line2 - eap->line1 + 1;
2400 if (*eap->arg != NUL || n <= 0)
2401 EMSG(_(e_invarg));
2402 else
2403 {
2404 for (i = eap->line1; i <= eap->line2; ++i)
2405 vim_free(ARGLIST[i - 1].ae_fname);
2406 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2407 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2408 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409 if (curwin->w_arg_idx >= eap->line2)
2410 curwin->w_arg_idx -= n;
2411 else if (curwin->w_arg_idx > eap->line1)
2412 curwin->w_arg_idx = eap->line1;
2413 }
2414 }
2415 else if (*eap->arg == NUL)
2416 EMSG(_(e_argreq));
2417 else
2418 do_arglist(eap->arg, AL_DEL, 0);
2419#ifdef FEAT_TITLE
2420 maketitle();
2421#endif
2422}
2423
2424/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002425 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 */
2427 void
2428ex_listdo(eap)
2429 exarg_T *eap;
2430{
2431 int i;
2432#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002433 win_T *wp;
2434 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435#endif
2436 buf_T *buf;
2437 int next_fnum = 0;
2438#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2439 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002441 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442
2443#ifndef FEAT_WINDOWS
2444 if (eap->cmdidx == CMD_windo)
2445 {
2446 ex_ni(eap);
2447 return;
2448 }
2449#endif
2450
2451#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002452 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002453 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2454 * great speed improvement. */
2455 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456#endif
2457
2458 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002459 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 || P_HID(curbuf)
2461 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2462 {
2463 /* start at the first argument/window/buffer */
2464 i = 0;
2465#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002466 wp = firstwin;
2467 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468#endif
2469 /* set pcmark now */
2470 if (eap->cmdidx == CMD_bufdo)
2471 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2472 else
2473 setpcmark();
2474 listcmd_busy = TRUE; /* avoids setting pcmark below */
2475
2476 while (!got_int)
2477 {
2478 if (eap->cmdidx == CMD_argdo)
2479 {
2480 /* go to argument "i" */
2481 if (i == ARGCOUNT)
2482 break;
2483 /* Don't call do_argfile() when already there, it will try
2484 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002485 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002486 {
2487 /* Clear 'shm' to avoid that the file message overwrites
2488 * any output from the command. */
2489 p_shm_save = vim_strsave(p_shm);
2490 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002491 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002492 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2493 vim_free(p_shm_save);
2494 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495 if (curwin->w_arg_idx != i)
2496 break;
2497 ++i;
2498 }
2499#ifdef FEAT_WINDOWS
2500 else if (eap->cmdidx == CMD_windo)
2501 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002502 /* go to window "wp" */
2503 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002505 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002506 if (curwin != wp)
2507 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002508 wp = curwin->w_next;
2509 }
2510 else if (eap->cmdidx == CMD_tabdo)
2511 {
2512 /* go to window "tp" */
2513 if (!valid_tabpage(tp))
2514 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002515 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002516 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002517 }
2518#endif
2519 else if (eap->cmdidx == CMD_bufdo)
2520 {
2521 /* Remember the number of the next listed buffer, in case
2522 * ":bwipe" is used or autocommands do something strange. */
2523 next_fnum = -1;
2524 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2525 if (buf->b_p_bl)
2526 {
2527 next_fnum = buf->b_fnum;
2528 break;
2529 }
2530 }
2531
2532 /* execute the command */
2533 do_cmdline(eap->arg, eap->getline, eap->cookie,
2534 DOCMD_VERBOSE + DOCMD_NOWAIT);
2535
2536 if (eap->cmdidx == CMD_bufdo)
2537 {
2538 /* Done? */
2539 if (next_fnum < 0)
2540 break;
2541 /* Check if the buffer still exists. */
2542 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2543 if (buf->b_fnum == next_fnum)
2544 break;
2545 if (buf == NULL)
2546 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002547
2548 /* Go to the next buffer. Clear 'shm' to avoid that the file
2549 * message overwrites any output from the command. */
2550 p_shm_save = vim_strsave(p_shm);
2551 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002553 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2554 vim_free(p_shm_save);
2555
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556 /* If autocommands took us elsewhere, quit here */
2557 if (curbuf->b_fnum != next_fnum)
2558 break;
2559 }
2560
2561 if (eap->cmdidx == CMD_windo)
2562 {
2563 validate_cursor(); /* cursor may have moved */
2564#ifdef FEAT_SCROLLBIND
2565 /* required when 'scrollbind' has been set */
2566 if (curwin->w_p_scb)
2567 do_check_scrollbind(TRUE);
2568#endif
2569 }
2570 }
2571 listcmd_busy = FALSE;
2572 }
2573
2574#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002575 if (save_ei != NULL)
2576 {
2577 au_event_restore(save_ei);
2578 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2579 curbuf->b_fname, TRUE, curbuf);
2580 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002581#endif
2582}
2583
2584/*
2585 * Add files[count] to the arglist of the current window after arg "after".
2586 * The file names in files[count] must have been allocated and are taken over.
2587 * Files[] itself is not taken over.
2588 * Returns index of first added argument. Returns -1 when failed (out of mem).
2589 */
2590 static int
2591alist_add_list(count, files, after)
2592 int count;
2593 char_u **files;
2594 int after; /* where to add: 0 = before first one */
2595{
2596 int i;
2597
2598 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2599 {
2600 if (after < 0)
2601 after = 0;
2602 if (after > ARGCOUNT)
2603 after = ARGCOUNT;
2604 if (after < ARGCOUNT)
2605 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2606 (ARGCOUNT - after) * sizeof(aentry_T));
2607 for (i = 0; i < count; ++i)
2608 {
2609 ARGLIST[after + i].ae_fname = files[i];
2610 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2611 }
2612 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002613 if (curwin->w_arg_idx >= after)
2614 ++curwin->w_arg_idx;
2615 return after;
2616 }
2617
2618 for (i = 0; i < count; ++i)
2619 vim_free(files[i]);
2620 return -1;
2621}
2622
2623#endif /* FEAT_LISTCMDS */
2624
2625#ifdef FEAT_EVAL
2626/*
2627 * ":compiler[!] {name}"
2628 */
2629 void
2630ex_compiler(eap)
2631 exarg_T *eap;
2632{
2633 char_u *buf;
2634 char_u *old_cur_comp = NULL;
2635 char_u *p;
2636
2637 if (*eap->arg == NUL)
2638 {
2639 /* List all compiler scripts. */
2640 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2641 /* ) keep the indenter happy... */
2642 }
2643 else
2644 {
2645 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2646 if (buf != NULL)
2647 {
2648 if (eap->forceit)
2649 {
2650 /* ":compiler! {name}" sets global options */
2651 do_cmdline_cmd((char_u *)
2652 "command -nargs=* CompilerSet set <args>");
2653 }
2654 else
2655 {
2656 /* ":compiler! {name}" sets local options.
2657 * To remain backwards compatible "current_compiler" is always
2658 * used. A user's compiler plugin may set it, the distributed
2659 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002660 * "b:current_compiler" and restore "current_compiler".
2661 * Explicitly prepend "g:" to make it work in a function. */
2662 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002663 if (old_cur_comp != NULL)
2664 old_cur_comp = vim_strsave(old_cur_comp);
2665 do_cmdline_cmd((char_u *)
2666 "command -nargs=* CompilerSet setlocal <args>");
2667 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002668 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002669 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002670
2671 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002672 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2674 vim_free(buf);
2675
2676 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2677
2678 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002679 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680 if (p != NULL)
2681 set_internal_string_var((char_u *)"b:current_compiler", p);
2682
2683 /* Restore "current_compiler" for ":compiler {name}". */
2684 if (!eap->forceit)
2685 {
2686 if (old_cur_comp != NULL)
2687 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002688 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 old_cur_comp);
2690 vim_free(old_cur_comp);
2691 }
2692 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002693 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694 }
2695 }
2696 }
2697}
2698#endif
2699
2700/*
2701 * ":runtime {name}"
2702 */
2703 void
2704ex_runtime(eap)
2705 exarg_T *eap;
2706{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002707 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708}
2709
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002710static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711
2712 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002713source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002715 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002717 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718}
2719
2720/*
2721 * Source the file "name" from all directories in 'runtimepath'.
2722 * "name" can contain wildcards.
2723 * When "all" is TRUE, source all files, otherwise only the first one.
2724 * return FAIL when no file could be sourced, OK otherwise.
2725 */
2726 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002727source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002728 char_u *name;
2729 int all;
2730{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002731 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002732}
2733
2734/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002735 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2736 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2738 * used.
2739 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002740 *
2741 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2742 * passed by reference in this case, setting it to NULL indicates that callback
2743 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744 */
2745 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002746do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747 char_u *name;
2748 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002749 void (*callback)__ARGS((char_u *fname, void *ck));
2750 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002751{
2752 char_u *rtp;
2753 char_u *np;
2754 char_u *buf;
2755 char_u *rtp_copy;
2756 char_u *tail;
2757 int num_files;
2758 char_u **files;
2759 int i;
2760 int did_one = FALSE;
2761#ifdef AMIGA
2762 struct Process *proc = (struct Process *)FindTask(0L);
2763 APTR save_winptr = proc->pr_WindowPtr;
2764
2765 /* Avoid a requester here for a volume that doesn't exist. */
2766 proc->pr_WindowPtr = (APTR)-1L;
2767#endif
2768
2769 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2770 * value. */
2771 rtp_copy = vim_strsave(p_rtp);
2772 buf = alloc(MAXPATHL);
2773 if (buf != NULL && rtp_copy != NULL)
2774 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002775 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002776 {
2777 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002778 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002780 verbose_leave();
2781 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002782
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783 /* Loop over all entries in 'runtimepath'. */
2784 rtp = rtp_copy;
2785 while (*rtp != NUL && (all || !did_one))
2786 {
2787 /* Copy the path from 'runtimepath' to buf[]. */
2788 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002789 if (name == NULL)
2790 {
2791 (*callback)(buf, (void *) &cookie);
2792 if (!did_one)
2793 did_one = (cookie == NULL);
2794 }
2795 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796 {
2797 add_pathsep(buf);
2798 tail = buf + STRLEN(buf);
2799
2800 /* Loop over all patterns in "name" */
2801 np = name;
2802 while (*np != NUL && (all || !did_one))
2803 {
2804 /* Append the pattern from "name" to buf[]. */
2805 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2806 "\t ");
2807
2808 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002809 {
2810 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002811 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002812 verbose_leave();
2813 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814
2815 /* Expand wildcards, invoke the callback for each match. */
2816 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2817 EW_FILE) == OK)
2818 {
2819 for (i = 0; i < num_files; ++i)
2820 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002821 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822 did_one = TRUE;
2823 if (!all)
2824 break;
2825 }
2826 FreeWild(num_files, files);
2827 }
2828 }
2829 }
2830 }
2831 }
2832 vim_free(buf);
2833 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002834 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002835 {
2836 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002837 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002838 verbose_leave();
2839 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840
2841#ifdef AMIGA
2842 proc->pr_WindowPtr = save_winptr;
2843#endif
2844
2845 return did_one ? OK : FAIL;
2846}
2847
2848#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2849/*
2850 * ":options"
2851 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002852 void
2853ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002854 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855{
2856 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2857}
2858#endif
2859
2860/*
2861 * ":source {fname}"
2862 */
2863 void
2864ex_source(eap)
2865 exarg_T *eap;
2866{
2867#ifdef FEAT_BROWSE
2868 if (cmdmod.browse)
2869 {
2870 char_u *fname = NULL;
2871
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002872 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2874 if (fname != NULL)
2875 {
2876 cmd_source(fname, eap);
2877 vim_free(fname);
2878 }
2879 }
2880 else
2881#endif
2882 cmd_source(eap->arg, eap);
2883}
2884
2885 static void
2886cmd_source(fname, eap)
2887 char_u *fname;
2888 exarg_T *eap;
2889{
2890 if (*fname == NUL)
2891 EMSG(_(e_argreq));
2892
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002894 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002895 * Need to execute the commands directly. This is required at least
2896 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897 * - ":g" command busy
2898 * - after ":argdo", ":windo" or ":bufdo"
2899 * - another command follows
2900 * - inside a loop
2901 */
2902 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2903#ifdef FEAT_EVAL
2904 || eap->cstack->cs_idx >= 0
2905#endif
2906 );
2907
2908 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002909 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910 EMSG2(_(e_notopen), fname);
2911}
2912
2913/*
2914 * ":source" and associated commands.
2915 */
2916/*
2917 * Structure used to store info for each sourced file.
2918 * It is shared between do_source() and getsourceline().
2919 * This is required, because it needs to be handed to do_cmdline() and
2920 * sourcing can be done recursively.
2921 */
2922struct source_cookie
2923{
2924 FILE *fp; /* opened file for sourcing */
2925 char_u *nextline; /* if not NULL: line that was read ahead */
2926 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002927#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2929 int error; /* TRUE if LF found after CR-LF */
2930#endif
2931#ifdef FEAT_EVAL
2932 linenr_T breakpoint; /* next line with breakpoint or zero */
2933 char_u *fname; /* name of sourced file */
2934 int dbg_tick; /* debug_tick when breakpoint was set */
2935 int level; /* top nesting level of sourced file */
2936#endif
2937#ifdef FEAT_MBYTE
2938 vimconv_T conv; /* type of conversion */
2939#endif
2940};
2941
2942#ifdef FEAT_EVAL
2943/*
2944 * Return the address holding the next breakpoint line for a source cookie.
2945 */
2946 linenr_T *
2947source_breakpoint(cookie)
2948 void *cookie;
2949{
2950 return &((struct source_cookie *)cookie)->breakpoint;
2951}
2952
2953/*
2954 * Return the address holding the debug tick for a source cookie.
2955 */
2956 int *
2957source_dbg_tick(cookie)
2958 void *cookie;
2959{
2960 return &((struct source_cookie *)cookie)->dbg_tick;
2961}
2962
2963/*
2964 * Return the nesting level for a source cookie.
2965 */
2966 int
2967source_level(cookie)
2968 void *cookie;
2969{
2970 return ((struct source_cookie *)cookie)->level;
2971}
2972#endif
2973
2974static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2975
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002976#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2977# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002978static FILE *fopen_noinh_readbin __ARGS((char *filename));
2979
2980/*
2981 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002982 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983 */
2984 static FILE *
2985fopen_noinh_readbin(filename)
2986 char *filename;
2987{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002988# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002989 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2990# else
2991 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002992# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002993
2994 if (fd_tmp == -1)
2995 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002996
2997# ifdef HAVE_FD_CLOEXEC
2998 {
2999 int fdflags = fcntl(fd_tmp, F_GETFD);
3000 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
3001 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
3002 }
3003# endif
3004
Bram Moolenaar071d4272004-06-13 20:20:40 +00003005 return fdopen(fd_tmp, READBIN);
3006}
3007#endif
3008
3009
3010/*
3011 * do_source: Read the file "fname" and execute its lines as EX commands.
3012 *
3013 * This function may be called recursively!
3014 *
3015 * return FAIL if file could not be opened, OK otherwise
3016 */
3017 int
3018do_source(fname, check_other, is_vimrc)
3019 char_u *fname;
3020 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003021 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022{
3023 struct source_cookie cookie;
3024 char_u *save_sourcing_name;
3025 linenr_T save_sourcing_lnum;
3026 char_u *p;
3027 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003028 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003029 int retval = FAIL;
3030#ifdef FEAT_EVAL
3031 scid_T save_current_SID;
3032 static scid_T last_current_SID = 0;
3033 void *save_funccalp;
3034 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003035 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036# ifdef UNIX
3037 struct stat st;
3038 int stat_ok;
3039# endif
3040#endif
3041#ifdef STARTUPTIME
3042 struct timeval tv_rel;
3043 struct timeval tv_start;
3044#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003045#ifdef FEAT_PROFILE
3046 proftime_T wait_start;
3047#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003050 if (p == NULL)
3051 return retval;
3052 fname_exp = fix_fname(p);
3053 vim_free(p);
3054 if (fname_exp == NULL)
3055 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056 if (mch_isdir(fname_exp))
3057 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003058 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059 goto theend;
3060 }
3061
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003062#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003063 /* Apply SourceCmd autocommands, they should get the file and source it. */
3064 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3065 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3066 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003067 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003068# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003069 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003070# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003071 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003072# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003073 goto theend;
3074 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003075
3076 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003077 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3078#endif
3079
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003080#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003081 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3082#else
3083 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3084#endif
3085 if (cookie.fp == NULL && check_other)
3086 {
3087 /*
3088 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3089 * and ".exrc" by "_exrc" or vice versa.
3090 */
3091 p = gettail(fname_exp);
3092 if ((*p == '.' || *p == '_')
3093 && (STRICMP(p + 1, "vimrc") == 0
3094 || STRICMP(p + 1, "gvimrc") == 0
3095 || STRICMP(p + 1, "exrc") == 0))
3096 {
3097 if (*p == '_')
3098 *p = '.';
3099 else
3100 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003101#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003102 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3103#else
3104 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3105#endif
3106 }
3107 }
3108
3109 if (cookie.fp == NULL)
3110 {
3111 if (p_verbose > 0)
3112 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003113 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003115 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 else
3117 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003118 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003119 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003120 }
3121 goto theend;
3122 }
3123
3124 /*
3125 * The file exists.
3126 * - In verbose mode, give a message.
3127 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3128 */
3129 if (p_verbose > 1)
3130 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003131 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003133 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134 else
3135 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003136 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003137 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003139 if (is_vimrc == DOSO_VIMRC)
3140 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3141 else if (is_vimrc == DOSO_GVIMRC)
3142 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143
3144#ifdef USE_CRNL
3145 /* If no automatic file format: Set default to CR-NL. */
3146 if (*p_ffs == NUL)
3147 cookie.fileformat = EOL_DOS;
3148 else
3149 cookie.fileformat = EOL_UNKNOWN;
3150 cookie.error = FALSE;
3151#endif
3152
3153#ifdef USE_CR
3154 /* If no automatic file format: Set default to CR. */
3155 if (*p_ffs == NUL)
3156 cookie.fileformat = EOL_MAC;
3157 else
3158 cookie.fileformat = EOL_UNKNOWN;
3159 cookie.error = FALSE;
3160#endif
3161
3162 cookie.nextline = NULL;
3163 cookie.finished = FALSE;
3164
3165#ifdef FEAT_EVAL
3166 /*
3167 * Check if this script has a breakpoint.
3168 */
3169 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3170 cookie.fname = fname_exp;
3171 cookie.dbg_tick = debug_tick;
3172
3173 cookie.level = ex_nesting_level;
3174#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003175
3176 /*
3177 * Keep the sourcing name/lnum, for recursive calls.
3178 */
3179 save_sourcing_name = sourcing_name;
3180 sourcing_name = fname_exp;
3181 save_sourcing_lnum = sourcing_lnum;
3182 sourcing_lnum = 0;
3183
Bram Moolenaar73881402009-02-04 16:50:47 +00003184#ifdef FEAT_MBYTE
3185 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3186
3187 /* Read the first line so we can check for a UTF-8 BOM. */
3188 firstline = getsourceline(0, (void *)&cookie, 0);
3189 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3190 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3191 {
3192 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3193 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3194 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003195 if (p == NULL)
3196 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003197 if (p != NULL)
3198 {
3199 vim_free(firstline);
3200 firstline = p;
3201 }
3202 }
3203#endif
3204
Bram Moolenaar071d4272004-06-13 20:20:40 +00003205#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003206 if (time_fd != NULL)
3207 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208#endif
3209
3210#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003211# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003212 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003213 prof_child_enter(&wait_start); /* entering a child now */
3214# endif
3215
3216 /* Don't use local function variables, if called from a function.
3217 * Also starts profiling timer for nested script. */
3218 save_funccalp = save_funccal();
3219
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220 /*
3221 * Check if this script was sourced before to finds its SID.
3222 * If it's new, generate a new SID.
3223 */
3224 save_current_SID = current_SID;
3225# ifdef UNIX
3226 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3227# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003228 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3229 {
3230 si = &SCRIPT_ITEM(current_SID);
3231 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003232 && (
3233# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003234 /* Compare dev/ino when possible, it catches symbolic
3235 * links. Also compare file names, the inode may change
3236 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003237 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003238 && (si->sn_dev == st.st_dev
3239 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003240# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003241 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003243 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244 if (current_SID == 0)
3245 {
3246 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003247 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3248 == FAIL)
3249 goto almosttheend;
3250 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003251 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003252 ++script_items.ga_len;
3253 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3254# ifdef FEAT_PROFILE
3255 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003257 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003258 si = &SCRIPT_ITEM(current_SID);
3259 si->sn_name = fname_exp;
3260 fname_exp = NULL;
3261# ifdef UNIX
3262 if (stat_ok)
3263 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003264 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003265 si->sn_dev = st.st_dev;
3266 si->sn_ino = st.st_ino;
3267 }
3268 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003269 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003270# endif
3271
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272 /* Allocate the local script variables to use for this script. */
3273 new_script_vars(current_SID);
3274 }
3275
Bram Moolenaar05159a02005-02-26 23:04:13 +00003276# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003277 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003278 {
3279 int forceit;
3280
3281 /* Check if we do profiling for this script. */
3282 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3283 {
3284 script_do_profile(si);
3285 si->sn_pr_force = forceit;
3286 }
3287 if (si->sn_prof_on)
3288 {
3289 ++si->sn_pr_count;
3290 profile_start(&si->sn_pr_start);
3291 profile_zero(&si->sn_pr_children);
3292 }
3293 }
3294# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295#endif
3296
3297 /*
3298 * Call do_cmdline, which will call getsourceline() to get the lines.
3299 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003300 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003303
3304#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003305 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003306 {
3307 /* Get "si" again, "script_items" may have been reallocated. */
3308 si = &SCRIPT_ITEM(current_SID);
3309 if (si->sn_prof_on)
3310 {
3311 profile_end(&si->sn_pr_start);
3312 profile_sub_wait(&wait_start, &si->sn_pr_start);
3313 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003314 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3315 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003316 }
3317 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318#endif
3319
3320 if (got_int)
3321 EMSG(_(e_interr));
3322 sourcing_name = save_sourcing_name;
3323 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 if (p_verbose > 1)
3325 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003326 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003327 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003329 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003330 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331 }
3332#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003333 if (time_fd != NULL)
3334 {
3335 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3336 time_msg((char *)IObuff, &tv_start);
3337 time_pop(&tv_rel);
3338 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339#endif
3340
3341#ifdef FEAT_EVAL
3342 /*
3343 * After a "finish" in debug mode, need to break at first command of next
3344 * sourced file.
3345 */
3346 if (save_debug_break_level > ex_nesting_level
3347 && debug_break_level == ex_nesting_level)
3348 ++debug_break_level;
3349#endif
3350
Bram Moolenaar05159a02005-02-26 23:04:13 +00003351#ifdef FEAT_EVAL
3352almosttheend:
3353 current_SID = save_current_SID;
3354 restore_funccal(save_funccalp);
3355# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003356 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003357 prof_child_exit(&wait_start); /* leaving a child now */
3358# endif
3359#endif
3360 fclose(cookie.fp);
3361 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003362 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003363#ifdef FEAT_MBYTE
3364 convert_setup(&cookie.conv, NULL, NULL);
3365#endif
3366
Bram Moolenaar071d4272004-06-13 20:20:40 +00003367theend:
3368 vim_free(fname_exp);
3369 return retval;
3370}
3371
3372#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003373
Bram Moolenaar071d4272004-06-13 20:20:40 +00003374/*
3375 * ":scriptnames"
3376 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377 void
3378ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003379 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003380{
3381 int i;
3382
Bram Moolenaar05159a02005-02-26 23:04:13 +00003383 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3384 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003385 {
3386 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3387 NameBuff, MAXPATHL, TRUE);
3388 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003389 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003390}
3391
3392# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3393/*
3394 * Fix slashes in the list of script names for 'shellslash'.
3395 */
3396 void
3397scriptnames_slash_adjust()
3398{
3399 int i;
3400
Bram Moolenaar05159a02005-02-26 23:04:13 +00003401 for (i = 1; i <= script_items.ga_len; ++i)
3402 if (SCRIPT_ITEM(i).sn_name != NULL)
3403 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003404}
3405# endif
3406
3407/*
3408 * Get a pointer to a script name. Used for ":verbose set".
3409 */
3410 char_u *
3411get_scriptname(id)
3412 scid_T id;
3413{
3414 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003415 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003416 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003417 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003418 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003419 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003420 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003421 return (char_u *)_("environment variable");
3422 if (id == SID_ERROR)
3423 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003424 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003426
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003427# if defined(EXITFREE) || defined(PROTO)
3428 void
3429free_scriptnames()
3430{
3431 int i;
3432
3433 for (i = script_items.ga_len; i > 0; --i)
3434 vim_free(SCRIPT_ITEM(i).sn_name);
3435 ga_clear(&script_items);
3436}
3437# endif
3438
Bram Moolenaar071d4272004-06-13 20:20:40 +00003439#endif
3440
3441#if defined(USE_CR) || defined(PROTO)
3442
3443# if defined(__MSL__) && (__MSL__ >= 22)
3444/*
3445 * Newer version of the Metrowerks library handle DOS and UNIX files
3446 * without help.
3447 * Test with earlier versions, MSL 2.2 is the library supplied with
3448 * Codewarrior Pro 2.
3449 */
3450 char *
3451fgets_cr(s, n, stream)
3452 char *s;
3453 int n;
3454 FILE *stream;
3455{
3456 return fgets(s, n, stream);
3457}
3458# else
3459/*
3460 * Version of fgets() which also works for lines ending in a <CR> only
3461 * (Macintosh format).
3462 * For older versions of the Metrowerks library.
3463 * At least CodeWarrior 9 needed this code.
3464 */
3465 char *
3466fgets_cr(s, n, stream)
3467 char *s;
3468 int n;
3469 FILE *stream;
3470{
3471 int c = 0;
3472 int char_read = 0;
3473
3474 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3475 {
3476 c = fgetc(stream);
3477 s[char_read++] = c;
3478 /* If the file is in DOS format, we need to skip a NL after a CR. I
3479 * thought it was the other way around, but this appears to work... */
3480 if (c == '\n')
3481 {
3482 c = fgetc(stream);
3483 if (c != '\r')
3484 ungetc(c, stream);
3485 }
3486 }
3487
3488 s[char_read] = 0;
3489 if (char_read == 0)
3490 return NULL;
3491
3492 if (feof(stream) && char_read == 1)
3493 return NULL;
3494
3495 return s;
3496}
3497# endif
3498#endif
3499
3500/*
3501 * Get one full line from a sourced file.
3502 * Called by do_cmdline() when it's called from do_source().
3503 *
3504 * Return a pointer to the line in allocated memory.
3505 * Return NULL for end-of-file or some error.
3506 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003507 char_u *
3508getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003509 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003511 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003512{
3513 struct source_cookie *sp = (struct source_cookie *)cookie;
3514 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003515 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003516
3517#ifdef FEAT_EVAL
3518 /* If breakpoints have been added/deleted need to check for it. */
3519 if (sp->dbg_tick < debug_tick)
3520 {
3521 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3522 sp->dbg_tick = debug_tick;
3523 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003524# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003525 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003526 script_line_end();
3527# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003528#endif
3529 /*
3530 * Get current line. If there is a read-ahead line, use it, otherwise get
3531 * one now.
3532 */
3533 if (sp->finished)
3534 line = NULL;
3535 else if (sp->nextline == NULL)
3536 line = get_one_sourceline(sp);
3537 else
3538 {
3539 line = sp->nextline;
3540 sp->nextline = NULL;
3541 ++sourcing_lnum;
3542 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003543#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003544 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003545 script_line_start();
3546#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003547
3548 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3549 * contain the 'C' flag. */
3550 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3551 {
3552 /* compensate for the one line read-ahead */
3553 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003554
3555 /* Get the next line and concatenate it when it starts with a
3556 * backslash. We always need to read the next line, keep it in
3557 * sp->nextline. */
3558 sp->nextline = get_one_sourceline(sp);
3559 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003561 garray_T ga;
3562
Bram Moolenaarb549a732012-02-22 18:29:33 +01003563 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003564 ga_concat(&ga, line);
3565 ga_concat(&ga, p + 1);
3566 for (;;)
3567 {
3568 vim_free(sp->nextline);
3569 sp->nextline = get_one_sourceline(sp);
3570 if (sp->nextline == NULL)
3571 break;
3572 p = skipwhite(sp->nextline);
3573 if (*p != '\\')
3574 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003575 /* Adjust the growsize to the current length to speed up
3576 * concatenating many lines. */
3577 if (ga.ga_len > 400)
3578 {
3579 if (ga.ga_len > 8000)
3580 ga.ga_growsize = 8000;
3581 else
3582 ga.ga_growsize = ga.ga_len;
3583 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003584 ga_concat(&ga, p + 1);
3585 }
3586 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003587 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003588 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003589 }
3590 }
3591
3592#ifdef FEAT_MBYTE
3593 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3594 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003595 char_u *s;
3596
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597 /* Convert the encoding of the script line. */
3598 s = string_convert(&sp->conv, line, NULL);
3599 if (s != NULL)
3600 {
3601 vim_free(line);
3602 line = s;
3603 }
3604 }
3605#endif
3606
3607#ifdef FEAT_EVAL
3608 /* Did we encounter a breakpoint? */
3609 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3610 {
3611 dbg_breakpoint(sp->fname, sourcing_lnum);
3612 /* Find next breakpoint. */
3613 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3614 sp->dbg_tick = debug_tick;
3615 }
3616#endif
3617
3618 return line;
3619}
3620
3621 static char_u *
3622get_one_sourceline(sp)
3623 struct source_cookie *sp;
3624{
3625 garray_T ga;
3626 int len;
3627 int c;
3628 char_u *buf;
3629#ifdef USE_CRNL
3630 int has_cr; /* CR-LF found */
3631#endif
3632#ifdef USE_CR
3633 char_u *scan;
3634#endif
3635 int have_read = FALSE;
3636
3637 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003638 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003639
3640 /*
3641 * Loop until there is a finished line (or end-of-file).
3642 */
3643 sourcing_lnum++;
3644 for (;;)
3645 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003646 /* make room to read at least 120 (more) characters */
3647 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003648 break;
3649 buf = (char_u *)ga.ga_data;
3650
3651#ifdef USE_CR
3652 if (sp->fileformat == EOL_MAC)
3653 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003654 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3655 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003656 break;
3657 }
3658 else
3659#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003660 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3661 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003662 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003663 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003664#ifdef USE_CRNL
3665 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3666 * CTRL-Z by its own, or after a NL. */
3667 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3668 && sp->fileformat == EOL_DOS
3669 && buf[len - 1] == Ctrl_Z)
3670 {
3671 buf[len - 1] = NUL;
3672 break;
3673 }
3674#endif
3675
3676#ifdef USE_CR
3677 /* If the read doesn't stop on a new line, and there's
3678 * some CR then we assume a Mac format */
3679 if (sp->fileformat == EOL_UNKNOWN)
3680 {
3681 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3682 sp->fileformat = EOL_MAC;
3683 else
3684 sp->fileformat = EOL_UNIX;
3685 }
3686
3687 if (sp->fileformat == EOL_MAC)
3688 {
3689 scan = vim_strchr(buf, '\r');
3690
3691 if (scan != NULL)
3692 {
3693 *scan = '\n';
3694 if (*(scan + 1) != 0)
3695 {
3696 *(scan + 1) = 0;
3697 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3698 }
3699 }
3700 len = STRLEN(buf);
3701 }
3702#endif
3703
3704 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705 ga.ga_len = len;
3706
3707 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003708 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003709 continue;
3710
3711 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3712 {
3713#ifdef USE_CRNL
3714 has_cr = (len >= 2 && buf[len - 2] == '\r');
3715 if (sp->fileformat == EOL_UNKNOWN)
3716 {
3717 if (has_cr)
3718 sp->fileformat = EOL_DOS;
3719 else
3720 sp->fileformat = EOL_UNIX;
3721 }
3722
3723 if (sp->fileformat == EOL_DOS)
3724 {
3725 if (has_cr) /* replace trailing CR */
3726 {
3727 buf[len - 2] = '\n';
3728 --len;
3729 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003730 }
3731 else /* lines like ":map xx yy^M" will have failed */
3732 {
3733 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003734 {
3735 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003737 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003738 sp->error = TRUE;
3739 sp->fileformat = EOL_UNIX;
3740 }
3741 }
3742#endif
3743 /* The '\n' is escaped if there is an odd number of ^V's just
3744 * before it, first set "c" just before the 'V's and then check
3745 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3746 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3747 ;
3748 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3749 {
3750 sourcing_lnum++;
3751 continue;
3752 }
3753
3754 buf[len - 1] = NUL; /* remove the NL */
3755 }
3756
3757 /*
3758 * Check for ^C here now and then, so recursive :so can be broken.
3759 */
3760 line_breakcheck();
3761 break;
3762 }
3763
3764 if (have_read)
3765 return (char_u *)ga.ga_data;
3766
3767 vim_free(ga.ga_data);
3768 return NULL;
3769}
3770
Bram Moolenaar05159a02005-02-26 23:04:13 +00003771#if defined(FEAT_PROFILE) || defined(PROTO)
3772/*
3773 * Called when starting to read a script line.
3774 * "sourcing_lnum" must be correct!
3775 * When skipping lines it may not actually be executed, but we won't find out
3776 * until later and we need to store the time now.
3777 */
3778 void
3779script_line_start()
3780{
3781 scriptitem_T *si;
3782 sn_prl_T *pp;
3783
3784 if (current_SID <= 0 || current_SID > script_items.ga_len)
3785 return;
3786 si = &SCRIPT_ITEM(current_SID);
3787 if (si->sn_prof_on && sourcing_lnum >= 1)
3788 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003789 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003790 * here isn't counted. */
3791 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3792 si->sn_prl_idx = sourcing_lnum - 1;
3793 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3794 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3795 {
3796 /* Zero counters for a line that was not used before. */
3797 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3798 pp->snp_count = 0;
3799 profile_zero(&pp->sn_prl_total);
3800 profile_zero(&pp->sn_prl_self);
3801 ++si->sn_prl_ga.ga_len;
3802 }
3803 si->sn_prl_execed = FALSE;
3804 profile_start(&si->sn_prl_start);
3805 profile_zero(&si->sn_prl_children);
3806 profile_get_wait(&si->sn_prl_wait);
3807 }
3808}
3809
3810/*
3811 * Called when actually executing a function line.
3812 */
3813 void
3814script_line_exec()
3815{
3816 scriptitem_T *si;
3817
3818 if (current_SID <= 0 || current_SID > script_items.ga_len)
3819 return;
3820 si = &SCRIPT_ITEM(current_SID);
3821 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3822 si->sn_prl_execed = TRUE;
3823}
3824
3825/*
3826 * Called when done with a function line.
3827 */
3828 void
3829script_line_end()
3830{
3831 scriptitem_T *si;
3832 sn_prl_T *pp;
3833
3834 if (current_SID <= 0 || current_SID > script_items.ga_len)
3835 return;
3836 si = &SCRIPT_ITEM(current_SID);
3837 if (si->sn_prof_on && si->sn_prl_idx >= 0
3838 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3839 {
3840 if (si->sn_prl_execed)
3841 {
3842 pp = &PRL_ITEM(si, si->sn_prl_idx);
3843 ++pp->snp_count;
3844 profile_end(&si->sn_prl_start);
3845 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003846 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003847 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3848 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003849 }
3850 si->sn_prl_idx = -1;
3851 }
3852}
3853#endif
3854
Bram Moolenaar071d4272004-06-13 20:20:40 +00003855/*
3856 * ":scriptencoding": Set encoding conversion for a sourced script.
3857 * Without the multi-byte feature it's simply ignored.
3858 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003859 void
3860ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003861 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003862{
3863#ifdef FEAT_MBYTE
3864 struct source_cookie *sp;
3865 char_u *name;
3866
3867 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3868 {
3869 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3870 return;
3871 }
3872
3873 if (*eap->arg != NUL)
3874 {
3875 name = enc_canonize(eap->arg);
3876 if (name == NULL) /* out of memory */
3877 return;
3878 }
3879 else
3880 name = eap->arg;
3881
3882 /* Setup for conversion from the specified encoding to 'encoding'. */
3883 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3884 convert_setup(&sp->conv, name, p_enc);
3885
3886 if (name != eap->arg)
3887 vim_free(name);
3888#endif
3889}
3890
3891#if defined(FEAT_EVAL) || defined(PROTO)
3892/*
3893 * ":finish": Mark a sourced file as finished.
3894 */
3895 void
3896ex_finish(eap)
3897 exarg_T *eap;
3898{
3899 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3900 do_finish(eap, FALSE);
3901 else
3902 EMSG(_("E168: :finish used outside of a sourced file"));
3903}
3904
3905/*
3906 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3907 * Also called for a pending finish at the ":endtry" or after returning from
3908 * an extra do_cmdline(). "reanimate" is used in the latter case.
3909 */
3910 void
3911do_finish(eap, reanimate)
3912 exarg_T *eap;
3913 int reanimate;
3914{
3915 int idx;
3916
3917 if (reanimate)
3918 ((struct source_cookie *)getline_cookie(eap->getline,
3919 eap->cookie))->finished = FALSE;
3920
3921 /*
3922 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3923 * not in its finally clause (which then is to be executed next) is found.
3924 * In this case, make the ":finish" pending for execution at the ":endtry".
3925 * Otherwise, finish normally.
3926 */
3927 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3928 if (idx >= 0)
3929 {
3930 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3931 report_make_pending(CSTP_FINISH, NULL);
3932 }
3933 else
3934 ((struct source_cookie *)getline_cookie(eap->getline,
3935 eap->cookie))->finished = TRUE;
3936}
3937
3938
3939/*
3940 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3941 * message for missing ":endif".
3942 * Return FALSE when not sourcing a file.
3943 */
3944 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003945source_finished(fgetline, cookie)
3946 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003947 void *cookie;
3948{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003949 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003950 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003951 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003952}
3953#endif
3954
3955#if defined(FEAT_LISTCMDS) || defined(PROTO)
3956/*
3957 * ":checktime [buffer]"
3958 */
3959 void
3960ex_checktime(eap)
3961 exarg_T *eap;
3962{
3963 buf_T *buf;
3964 int save_no_check_timestamps = no_check_timestamps;
3965
3966 no_check_timestamps = 0;
3967 if (eap->addr_count == 0) /* default is all buffers */
3968 check_timestamps(FALSE);
3969 else
3970 {
3971 buf = buflist_findnr((int)eap->line2);
3972 if (buf != NULL) /* cannot happen? */
3973 (void)buf_check_timestamp(buf, FALSE);
3974 }
3975 no_check_timestamps = save_no_check_timestamps;
3976}
3977#endif
3978
Bram Moolenaar071d4272004-06-13 20:20:40 +00003979#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3980 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003981# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003982static char *get_locale_val __ARGS((int what));
3983
3984 static char *
3985get_locale_val(what)
3986 int what;
3987{
3988 char *loc;
3989
3990 /* Obtain the locale value from the libraries. For DJGPP this is
3991 * redefined and it doesn't use the arguments. */
3992 loc = setlocale(what, NULL);
3993
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003994# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 if (loc != NULL)
3996 {
3997 char_u *p;
3998
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003999 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4000 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004001 p = vim_strchr(loc, '=');
4002 if (p != NULL)
4003 {
4004 loc = ++p;
4005 while (*p != NUL) /* remove trailing newline */
4006 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004007 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004008 {
4009 *p = NUL;
4010 break;
4011 }
4012 ++p;
4013 }
4014 }
4015 }
4016# endif
4017
4018 return loc;
4019}
4020#endif
4021
4022
4023#ifdef WIN32
4024/*
4025 * On MS-Windows locale names are strings like "German_Germany.1252", but
4026 * gettext expects "de". Try to translate one into another here for a few
4027 * supported languages.
4028 */
4029 static char_u *
4030gettext_lang(char_u *name)
4031{
4032 int i;
4033 static char *(mtable[]) = {
4034 "afrikaans", "af",
4035 "czech", "cs",
4036 "dutch", "nl",
4037 "german", "de",
4038 "english_united kingdom", "en_GB",
4039 "spanish", "es",
4040 "french", "fr",
4041 "italian", "it",
4042 "japanese", "ja",
4043 "korean", "ko",
4044 "norwegian", "no",
4045 "polish", "pl",
4046 "russian", "ru",
4047 "slovak", "sk",
4048 "swedish", "sv",
4049 "ukrainian", "uk",
4050 "chinese_china", "zh_CN",
4051 "chinese_taiwan", "zh_TW",
4052 NULL};
4053
4054 for (i = 0; mtable[i] != NULL; i += 2)
4055 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4056 return mtable[i + 1];
4057 return name;
4058}
4059#endif
4060
4061#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4062/*
4063 * Obtain the current messages language. Used to set the default for
4064 * 'helplang'. May return NULL or an empty string.
4065 */
4066 char_u *
4067get_mess_lang()
4068{
4069 char_u *p;
4070
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004071# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072# if defined(LC_MESSAGES)
4073 p = (char_u *)get_locale_val(LC_MESSAGES);
4074# else
4075 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004076 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4077 * and LC_MONETARY may be set differently for a Japanese working in the
4078 * US. */
4079 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004080# endif
4081# else
4082 p = mch_getenv((char_u *)"LC_ALL");
4083 if (p == NULL || *p == NUL)
4084 {
4085 p = mch_getenv((char_u *)"LC_MESSAGES");
4086 if (p == NULL || *p == NUL)
4087 p = mch_getenv((char_u *)"LANG");
4088 }
4089# endif
4090# ifdef WIN32
4091 p = gettext_lang(p);
4092# endif
4093 return p;
4094}
4095#endif
4096
Bram Moolenaardef9e822004-12-31 20:58:58 +00004097/* Complicated #if; matches with where get_mess_env() is used below. */
4098#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4099 && defined(LC_MESSAGES))) \
4100 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4101 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4102 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004103static char_u *get_mess_env __ARGS((void));
4104
4105/*
4106 * Get the language used for messages from the environment.
4107 */
4108 static char_u *
4109get_mess_env()
4110{
4111 char_u *p;
4112
4113 p = mch_getenv((char_u *)"LC_ALL");
4114 if (p == NULL || *p == NUL)
4115 {
4116 p = mch_getenv((char_u *)"LC_MESSAGES");
4117 if (p == NULL || *p == NUL)
4118 {
4119 p = mch_getenv((char_u *)"LANG");
4120 if (p != NULL && VIM_ISDIGIT(*p))
4121 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004122# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123 if (p == NULL || *p == NUL)
4124 p = (char_u *)get_locale_val(LC_CTYPE);
4125# endif
4126 }
4127 }
4128 return p;
4129}
4130#endif
4131
4132#if defined(FEAT_EVAL) || defined(PROTO)
4133
4134/*
4135 * Set the "v:lang" variable according to the current locale setting.
4136 * Also do "v:lc_time"and "v:ctype".
4137 */
4138 void
4139set_lang_var()
4140{
4141 char_u *loc;
4142
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004143# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004144 loc = (char_u *)get_locale_val(LC_CTYPE);
4145# else
4146 /* setlocale() not supported: use the default value */
4147 loc = (char_u *)"C";
4148# endif
4149 set_vim_var_string(VV_CTYPE, loc, -1);
4150
4151 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4152 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004153# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 loc = (char_u *)get_locale_val(LC_MESSAGES);
4155# else
4156 loc = get_mess_env();
4157# endif
4158 set_vim_var_string(VV_LANG, loc, -1);
4159
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004160# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161 loc = (char_u *)get_locale_val(LC_TIME);
4162# endif
4163 set_vim_var_string(VV_LC_TIME, loc, -1);
4164}
4165#endif
4166
4167#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4168 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4169/*
4170 * ":language": Set the language (locale).
4171 */
4172 void
4173ex_language(eap)
4174 exarg_T *eap;
4175{
4176 char *loc;
4177 char_u *p;
4178 char_u *name;
4179 int what = LC_ALL;
4180 char *whatstr = "";
4181#ifdef LC_MESSAGES
4182# define VIM_LC_MESSAGES LC_MESSAGES
4183#else
4184# define VIM_LC_MESSAGES 6789
4185#endif
4186
4187 name = eap->arg;
4188
4189 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4190 * Allow abbreviation, but require at least 3 characters to avoid
4191 * confusion with a two letter language name "me" or "ct". */
4192 p = skiptowhite(eap->arg);
4193 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4194 {
4195 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4196 {
4197 what = VIM_LC_MESSAGES;
4198 name = skipwhite(p);
4199 whatstr = "messages ";
4200 }
4201 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4202 {
4203 what = LC_CTYPE;
4204 name = skipwhite(p);
4205 whatstr = "ctype ";
4206 }
4207 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4208 {
4209 what = LC_TIME;
4210 name = skipwhite(p);
4211 whatstr = "time ";
4212 }
4213 }
4214
4215 if (*name == NUL)
4216 {
4217#ifndef LC_MESSAGES
4218 if (what == VIM_LC_MESSAGES)
4219 p = get_mess_env();
4220 else
4221#endif
4222 p = (char_u *)setlocale(what, NULL);
4223 if (p == NULL || *p == NUL)
4224 p = (char_u *)"Unknown";
4225 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4226 }
4227 else
4228 {
4229#ifndef LC_MESSAGES
4230 if (what == VIM_LC_MESSAGES)
4231 loc = "";
4232 else
4233#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004234 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004236#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4237 /* Make sure strtod() uses a decimal point, not a comma. */
4238 setlocale(LC_NUMERIC, "C");
4239#endif
4240 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241 if (loc == NULL)
4242 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4243 else
4244 {
4245#ifdef HAVE_NL_MSG_CAT_CNTR
4246 /* Need to do this for GNU gettext, otherwise cached translations
4247 * will be used again. */
4248 extern int _nl_msg_cat_cntr;
4249
4250 ++_nl_msg_cat_cntr;
4251#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004252 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4254
4255 if (what != LC_TIME)
4256 {
4257 /* Tell gettext() what to translate to. It apparently doesn't
4258 * use the currently effective locale. Also do this when
4259 * FEAT_GETTEXT isn't defined, so that shell commands use this
4260 * value. */
4261 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004262 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004264
4265 /* Clear $LANGUAGE because GNU gettext uses it. */
4266 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004267# ifdef WIN32
4268 /* Apparently MS-Windows printf() may cause a crash when
4269 * we give it 8-bit text while it's expecting text in the
4270 * current locale. This call avoids that. */
4271 setlocale(LC_CTYPE, "C");
4272# endif
4273 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274 if (what != LC_CTYPE)
4275 {
4276 char_u *mname;
4277#ifdef WIN32
4278 mname = gettext_lang(name);
4279#else
4280 mname = name;
4281#endif
4282 vim_setenv((char_u *)"LC_MESSAGES", mname);
4283#ifdef FEAT_MULTI_LANG
4284 set_helplang_default(mname);
4285#endif
4286 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287 }
4288
4289# ifdef FEAT_EVAL
4290 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4291 set_lang_var();
4292# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004293# ifdef FEAT_TITLE
4294 maketitle();
4295# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004296 }
4297 }
4298}
4299
4300# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004301
4302static char_u **locales = NULL; /* Array of all available locales */
4303static int did_init_locales = FALSE;
4304
4305static void init_locales __ARGS((void));
4306static char_u **find_locales __ARGS((void));
4307
4308/*
4309 * Lazy initialization of all available locales.
4310 */
4311 static void
4312init_locales()
4313{
4314 if (!did_init_locales)
4315 {
4316 did_init_locales = TRUE;
4317 locales = find_locales();
4318 }
4319}
4320
4321/* Return an array of strings for all available locales + NULL for the
4322 * last element. Return NULL in case of error. */
4323 static char_u **
4324find_locales()
4325{
4326 garray_T locales_ga;
4327 char_u *loc;
4328
4329 /* Find all available locales by running command "locale -a". If this
4330 * doesn't work we won't have completion. */
4331 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
4332 NULL, SHELL_SILENT);
4333 if (locale_a == NULL)
4334 return NULL;
4335 ga_init2(&locales_ga, sizeof(char_u *), 20);
4336
4337 /* Transform locale_a string where each locale is separated by "\n"
4338 * into an array of locale strings. */
4339 loc = (char_u *)strtok((char *)locale_a, "\n");
4340
4341 while (loc != NULL)
4342 {
4343 if (ga_grow(&locales_ga, 1) == FAIL)
4344 break;
4345 loc = vim_strsave(loc);
4346 if (loc == NULL)
4347 break;
4348
4349 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4350 loc = (char_u *)strtok(NULL, "\n");
4351 }
4352 vim_free(locale_a);
4353 if (ga_grow(&locales_ga, 1) == FAIL)
4354 {
4355 ga_clear(&locales_ga);
4356 return NULL;
4357 }
4358 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4359 return (char_u **)locales_ga.ga_data;
4360}
4361
4362# if defined(EXITFREE) || defined(PROTO)
4363 void
4364free_locales()
4365{
4366 int i;
4367 if (locales != NULL)
4368 {
4369 for (i = 0; locales[i] != NULL; i++)
4370 vim_free(locales[i]);
4371 vim_free(locales);
4372 locales = NULL;
4373 }
4374}
4375# endif
4376
Bram Moolenaar071d4272004-06-13 20:20:40 +00004377/*
4378 * Function given to ExpandGeneric() to obtain the possible arguments of the
4379 * ":language" command.
4380 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004381 char_u *
4382get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004383 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004384 int idx;
4385{
4386 if (idx == 0)
4387 return (char_u *)"messages";
4388 if (idx == 1)
4389 return (char_u *)"ctype";
4390 if (idx == 2)
4391 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004392
4393 init_locales();
4394 if (locales == NULL)
4395 return NULL;
4396 return locales[idx - 3];
4397}
4398
4399/*
4400 * Function given to ExpandGeneric() to obtain the available locales.
4401 */
4402 char_u *
4403get_locales(xp, idx)
4404 expand_T *xp UNUSED;
4405 int idx;
4406{
4407 init_locales();
4408 if (locales == NULL)
4409 return NULL;
4410 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411}
4412# endif
4413
4414#endif