blob: 11446efd414e29960191b6a127b660d5eff27bed [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);
655 vim_free(DEBUGGY(gap, todel).dbg_prog);
656 --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
961# if defined(FEAT_PROFILE) || defined(PROTO)
962/*
963 * Functions for profiling.
964 */
965static void script_do_profile __ARGS((scriptitem_T *si));
966static void script_dump_profile __ARGS((FILE *fd));
967static proftime_T prof_wait_time;
968
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000969/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000970 * Add the time "tm2" to "tm".
971 */
972 void
973profile_add(tm, tm2)
974 proftime_T *tm, *tm2;
975{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000976# ifdef WIN3264
977 tm->QuadPart += tm2->QuadPart;
978# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000979 tm->tv_usec += tm2->tv_usec;
980 tm->tv_sec += tm2->tv_sec;
981 if (tm->tv_usec >= 1000000)
982 {
983 tm->tv_usec -= 1000000;
984 ++tm->tv_sec;
985 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000986# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000987}
988
989/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000990 * Add the "self" time from the total time and the children's time.
991 */
992 void
993profile_self(self, total, children)
994 proftime_T *self, *total, *children;
995{
996 /* Check that the result won't be negative. Can happen with recursive
997 * calls. */
998#ifdef WIN3264
999 if (total->QuadPart <= children->QuadPart)
1000 return;
1001#else
1002 if (total->tv_sec < children->tv_sec
1003 || (total->tv_sec == children->tv_sec
1004 && total->tv_usec <= children->tv_usec))
1005 return;
1006#endif
1007 profile_add(self, total);
1008 profile_sub(self, children);
1009}
1010
1011/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001012 * Get the current waittime.
1013 */
1014 void
1015profile_get_wait(tm)
1016 proftime_T *tm;
1017{
1018 *tm = prof_wait_time;
1019}
1020
1021/*
1022 * Subtract the passed waittime since "tm" from "tma".
1023 */
1024 void
1025profile_sub_wait(tm, tma)
1026 proftime_T *tm, *tma;
1027{
1028 proftime_T tm3 = prof_wait_time;
1029
1030 profile_sub(&tm3, tm);
1031 profile_sub(tma, &tm3);
1032}
1033
1034/*
1035 * Return TRUE if "tm1" and "tm2" are equal.
1036 */
1037 int
1038profile_equal(tm1, tm2)
1039 proftime_T *tm1, *tm2;
1040{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001041# ifdef WIN3264
1042 return (tm1->QuadPart == tm2->QuadPart);
1043# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001044 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001045# endif
1046}
1047
1048/*
1049 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1050 */
1051 int
1052profile_cmp(tm1, tm2)
1053 proftime_T *tm1, *tm2;
1054{
1055# ifdef WIN3264
1056 return (int)(tm2->QuadPart - tm1->QuadPart);
1057# else
1058 if (tm1->tv_sec == tm2->tv_sec)
1059 return tm2->tv_usec - tm1->tv_usec;
1060 return tm2->tv_sec - tm1->tv_sec;
1061# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001062}
1063
Bram Moolenaar05159a02005-02-26 23:04:13 +00001064static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001065static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001066
1067/*
1068 * ":profile cmd args"
1069 */
1070 void
1071ex_profile(eap)
1072 exarg_T *eap;
1073{
1074 char_u *e;
1075 int len;
1076
1077 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001078 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001079 e = skipwhite(e);
1080
1081 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1082 {
1083 vim_free(profile_fname);
1084 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001085 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001086 profile_zero(&prof_wait_time);
1087 set_vim_var_nr(VV_PROFILING, 1L);
1088 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001089 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001090 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001091 else if (STRCMP(eap->arg, "pause") == 0)
1092 {
1093 if (do_profiling == PROF_YES)
1094 profile_start(&pause_time);
1095 do_profiling = PROF_PAUSED;
1096 }
1097 else if (STRCMP(eap->arg, "continue") == 0)
1098 {
1099 if (do_profiling == PROF_PAUSED)
1100 {
1101 profile_end(&pause_time);
1102 profile_add(&prof_wait_time, &pause_time);
1103 }
1104 do_profiling = PROF_YES;
1105 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001106 else
1107 {
1108 /* The rest is similar to ":breakadd". */
1109 ex_breakadd(eap);
1110 }
1111}
1112
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001113/* Command line expansion for :profile. */
1114static enum
1115{
1116 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001117 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001118} pexpand_what;
1119
1120static char *pexpand_cmds[] = {
1121 "start",
1122#define PROFCMD_START 0
1123 "pause",
1124#define PROFCMD_PAUSE 1
1125 "continue",
1126#define PROFCMD_CONTINUE 2
1127 "func",
1128#define PROFCMD_FUNC 3
1129 "file",
1130#define PROFCMD_FILE 4
1131 NULL
1132#define PROFCMD_LAST 5
1133};
1134
1135/*
1136 * Function given to ExpandGeneric() to obtain the profile command
1137 * specific expansion.
1138 */
1139 char_u *
1140get_profile_name(xp, idx)
1141 expand_T *xp UNUSED;
1142 int idx;
1143{
1144 switch (pexpand_what)
1145 {
1146 case PEXP_SUBCMD:
1147 return (char_u *)pexpand_cmds[idx];
1148 /* case PEXP_FUNC: TODO */
1149 default:
1150 return NULL;
1151 }
1152}
1153
1154/*
1155 * Handle command line completion for :profile command.
1156 */
1157 void
1158set_context_in_profile_cmd(xp, arg)
1159 expand_T *xp;
1160 char_u *arg;
1161{
1162 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001163
1164 /* Default: expand subcommands. */
1165 xp->xp_context = EXPAND_PROFILE;
1166 pexpand_what = PEXP_SUBCMD;
1167 xp->xp_pattern = arg;
1168
1169 end_subcmd = skiptowhite(arg);
1170 if (*end_subcmd == NUL)
1171 return;
1172
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001173 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001174 {
1175 xp->xp_context = EXPAND_FILES;
1176 xp->xp_pattern = skipwhite(end_subcmd);
1177 return;
1178 }
1179
1180 /* TODO: expand function names after "func" */
1181 xp->xp_context = EXPAND_NOTHING;
1182}
1183
Bram Moolenaar05159a02005-02-26 23:04:13 +00001184/*
1185 * Dump the profiling info.
1186 */
1187 void
1188profile_dump()
1189{
1190 FILE *fd;
1191
1192 if (profile_fname != NULL)
1193 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001194 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001195 if (fd == NULL)
1196 EMSG2(_(e_notopen), profile_fname);
1197 else
1198 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001199 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001200 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001201 fclose(fd);
1202 }
1203 }
1204}
1205
1206/*
1207 * Start profiling script "fp".
1208 */
1209 static void
1210script_do_profile(si)
1211 scriptitem_T *si;
1212{
1213 si->sn_pr_count = 0;
1214 profile_zero(&si->sn_pr_total);
1215 profile_zero(&si->sn_pr_self);
1216
1217 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1218 si->sn_prl_idx = -1;
1219 si->sn_prof_on = TRUE;
1220 si->sn_pr_nest = 0;
1221}
1222
1223/*
1224 * save time when starting to invoke another script or function.
1225 */
1226 void
1227script_prof_save(tm)
1228 proftime_T *tm; /* place to store wait time */
1229{
1230 scriptitem_T *si;
1231
1232 if (current_SID > 0 && current_SID <= script_items.ga_len)
1233 {
1234 si = &SCRIPT_ITEM(current_SID);
1235 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1236 profile_start(&si->sn_pr_child);
1237 }
1238 profile_get_wait(tm);
1239}
1240
1241/*
1242 * Count time spent in children after invoking another script or function.
1243 */
1244 void
1245script_prof_restore(tm)
1246 proftime_T *tm;
1247{
1248 scriptitem_T *si;
1249
1250 if (current_SID > 0 && current_SID <= script_items.ga_len)
1251 {
1252 si = &SCRIPT_ITEM(current_SID);
1253 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1254 {
1255 profile_end(&si->sn_pr_child);
1256 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1257 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1258 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1259 }
1260 }
1261}
1262
1263static proftime_T inchar_time;
1264
1265/*
1266 * Called when starting to wait for the user to type a character.
1267 */
1268 void
1269prof_inchar_enter()
1270{
1271 profile_start(&inchar_time);
1272}
1273
1274/*
1275 * Called when finished waiting for the user to type a character.
1276 */
1277 void
1278prof_inchar_exit()
1279{
1280 profile_end(&inchar_time);
1281 profile_add(&prof_wait_time, &inchar_time);
1282}
1283
1284/*
1285 * Dump the profiling results for all scripts in file "fd".
1286 */
1287 static void
1288script_dump_profile(fd)
1289 FILE *fd;
1290{
1291 int id;
1292 scriptitem_T *si;
1293 int i;
1294 FILE *sfd;
1295 sn_prl_T *pp;
1296
1297 for (id = 1; id <= script_items.ga_len; ++id)
1298 {
1299 si = &SCRIPT_ITEM(id);
1300 if (si->sn_prof_on)
1301 {
1302 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1303 if (si->sn_pr_count == 1)
1304 fprintf(fd, "Sourced 1 time\n");
1305 else
1306 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1307 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1308 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1309 fprintf(fd, "\n");
1310 fprintf(fd, "count total (s) self (s)\n");
1311
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001312 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001313 if (sfd == NULL)
1314 fprintf(fd, "Cannot open file!\n");
1315 else
1316 {
1317 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1318 {
1319 if (vim_fgets(IObuff, IOSIZE, sfd))
1320 break;
1321 pp = &PRL_ITEM(si, i);
1322 if (pp->snp_count > 0)
1323 {
1324 fprintf(fd, "%5d ", pp->snp_count);
1325 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1326 fprintf(fd, " ");
1327 else
1328 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1329 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1330 }
1331 else
1332 fprintf(fd, " ");
1333 fprintf(fd, "%s", IObuff);
1334 }
1335 fclose(sfd);
1336 }
1337 fprintf(fd, "\n");
1338 }
1339 }
1340}
1341
1342/*
1343 * Return TRUE when a function defined in the current script should be
1344 * profiled.
1345 */
1346 int
1347prof_def_func()
1348{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001349 if (current_SID > 0)
1350 return SCRIPT_ITEM(current_SID).sn_pr_force;
1351 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001352}
1353
1354# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001355#endif
1356
1357/*
1358 * If 'autowrite' option set, try to write the file.
1359 * Careful: autocommands may make "buf" invalid!
1360 *
1361 * return FAIL for failure, OK otherwise
1362 */
1363 int
1364autowrite(buf, forceit)
1365 buf_T *buf;
1366 int forceit;
1367{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001368 int r;
1369
Bram Moolenaar071d4272004-06-13 20:20:40 +00001370 if (!(p_aw || p_awa) || !p_write
1371#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001372 /* never autowrite a "nofile" or "nowrite" buffer */
1373 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001374#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001375 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001376 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001377 r = buf_write_all(buf, forceit);
1378
1379 /* Writing may succeed but the buffer still changed, e.g., when there is a
1380 * conversion error. We do want to return FAIL then. */
1381 if (buf_valid(buf) && bufIsChanged(buf))
1382 r = FAIL;
1383 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001384}
1385
1386/*
1387 * flush all buffers, except the ones that are readonly
1388 */
1389 void
1390autowrite_all()
1391{
1392 buf_T *buf;
1393
1394 if (!(p_aw || p_awa) || !p_write)
1395 return;
1396 for (buf = firstbuf; buf; buf = buf->b_next)
1397 if (bufIsChanged(buf) && !buf->b_p_ro)
1398 {
1399 (void)buf_write_all(buf, FALSE);
1400#ifdef FEAT_AUTOCMD
1401 /* an autocommand may have deleted the buffer */
1402 if (!buf_valid(buf))
1403 buf = firstbuf;
1404#endif
1405 }
1406}
1407
1408/*
1409 * return TRUE if buffer was changed and cannot be abandoned.
1410 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001411 int
1412check_changed(buf, checkaw, mult_win, forceit, allbuf)
1413 buf_T *buf;
1414 int checkaw; /* do autowrite if buffer was changed */
1415 int mult_win; /* check also when several wins for the buf */
1416 int forceit;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001417 int allbuf UNUSED; /* may write all buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001418{
1419 if ( !forceit
1420 && bufIsChanged(buf)
1421 && (mult_win || buf->b_nwindows <= 1)
1422 && (!checkaw || autowrite(buf, forceit) == FAIL))
1423 {
1424#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1425 if ((p_confirm || cmdmod.confirm) && p_write)
1426 {
1427 buf_T *buf2;
1428 int count = 0;
1429
1430 if (allbuf)
1431 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1432 if (bufIsChanged(buf2)
1433 && (buf2->b_ffname != NULL
1434# ifdef FEAT_BROWSE
1435 || cmdmod.browse
1436# endif
1437 ))
1438 ++count;
1439# ifdef FEAT_AUTOCMD
1440 if (!buf_valid(buf))
1441 /* Autocommand deleted buffer, oops! It's not changed now. */
1442 return FALSE;
1443# endif
1444 dialog_changed(buf, count > 1);
1445# ifdef FEAT_AUTOCMD
1446 if (!buf_valid(buf))
1447 /* Autocommand deleted buffer, oops! It's not changed now. */
1448 return FALSE;
1449# endif
1450 return bufIsChanged(buf);
1451 }
1452#endif
1453 EMSG(_(e_nowrtmsg));
1454 return TRUE;
1455 }
1456 return FALSE;
1457}
1458
1459#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1460
1461#if defined(FEAT_BROWSE) || defined(PROTO)
1462/*
1463 * When wanting to write a file without a file name, ask the user for a name.
1464 */
1465 void
1466browse_save_fname(buf)
1467 buf_T *buf;
1468{
1469 if (buf->b_fname == NULL)
1470 {
1471 char_u *fname;
1472
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001473 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1474 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001475 if (fname != NULL)
1476 {
1477 if (setfname(buf, fname, NULL, TRUE) == OK)
1478 buf->b_flags |= BF_NOTEDITED;
1479 vim_free(fname);
1480 }
1481 }
1482}
1483#endif
1484
1485/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001486 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001487 * Must check 'write' option first!
1488 */
1489 void
1490dialog_changed(buf, checkall)
1491 buf_T *buf;
1492 int checkall; /* may abandon all changed buffers */
1493{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001494 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001495 int ret;
1496 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001497 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001499 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001500 (buf->b_fname != NULL) ?
1501 buf->b_fname : (char_u *)_("Untitled"));
1502 if (checkall)
1503 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1504 else
1505 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1506
Bram Moolenaar8218f602012-04-25 17:32:18 +02001507 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1508 * function. */
1509 ea.append = ea.forceit = FALSE;
1510
Bram Moolenaar071d4272004-06-13 20:20:40 +00001511 if (ret == VIM_YES)
1512 {
1513#ifdef FEAT_BROWSE
1514 /* May get file name, when there is none */
1515 browse_save_fname(buf);
1516#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001517 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1518 buf->b_fname, buf->b_ffname, FALSE) == OK)
1519 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001520 (void)buf_write_all(buf, FALSE);
1521 }
1522 else if (ret == VIM_NO)
1523 {
1524 unchanged(buf, TRUE);
1525 }
1526 else if (ret == VIM_ALL)
1527 {
1528 /*
1529 * Write all modified files that can be written.
1530 * Skip readonly buffers, these need to be confirmed
1531 * individually.
1532 */
1533 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1534 {
1535 if (bufIsChanged(buf2)
1536 && (buf2->b_ffname != NULL
1537#ifdef FEAT_BROWSE
1538 || cmdmod.browse
1539#endif
1540 )
1541 && !buf2->b_p_ro)
1542 {
1543#ifdef FEAT_BROWSE
1544 /* May get file name, when there is none */
1545 browse_save_fname(buf2);
1546#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001547 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1548 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1549 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550 (void)buf_write_all(buf2, FALSE);
1551#ifdef FEAT_AUTOCMD
1552 /* an autocommand may have deleted the buffer */
1553 if (!buf_valid(buf2))
1554 buf2 = firstbuf;
1555#endif
1556 }
1557 }
1558 }
1559 else if (ret == VIM_DISCARDALL)
1560 {
1561 /*
1562 * mark all buffers as unchanged
1563 */
1564 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1565 unchanged(buf2, TRUE);
1566 }
1567}
1568#endif
1569
1570/*
1571 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1572 * hidden, autowriting it or unloading it.
1573 */
1574 int
1575can_abandon(buf, forceit)
1576 buf_T *buf;
1577 int forceit;
1578{
1579 return ( P_HID(buf)
1580 || !bufIsChanged(buf)
1581 || buf->b_nwindows > 1
1582 || autowrite(buf, forceit) == OK
1583 || forceit);
1584}
1585
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001586static void add_bufnum __ARGS((int *bufnrs, int *bufnump, int nr));
1587
1588/*
1589 * Add a buffer number to "bufnrs", unless it's already there.
1590 */
1591 static void
1592add_bufnum(bufnrs, bufnump, nr)
1593 int *bufnrs;
1594 int *bufnump;
1595 int nr;
1596{
1597 int i;
1598
1599 for (i = 0; i < *bufnump; ++i)
1600 if (bufnrs[i] == nr)
1601 return;
1602 bufnrs[*bufnump] = nr;
1603 *bufnump = *bufnump + 1;
1604}
1605
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606/*
1607 * Return TRUE if any buffer was changed and cannot be abandoned.
1608 * That changed buffer becomes the current buffer.
1609 */
1610 int
1611check_changed_any(hidden)
1612 int hidden; /* Only check hidden buffers */
1613{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001614 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 buf_T *buf;
1616 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001617 int i;
1618 int bufnum = 0;
1619 int bufcount = 0;
1620 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001622 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001623 win_T *wp;
1624#endif
1625
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001626 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1627 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001628
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001629 if (bufcount == 0)
1630 return FALSE;
1631
1632 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1633 if (bufnrs == NULL)
1634 return FALSE;
1635
1636 /* curbuf */
1637 bufnrs[bufnum++] = curbuf->b_fnum;
1638#ifdef FEAT_WINDOWS
1639 /* buf in curtab */
1640 FOR_ALL_WINDOWS(wp)
1641 if (wp->w_buffer != curbuf)
1642 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1643
1644 /* buf in other tab */
1645 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1646 if (tp != curtab)
1647 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1648 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1649#endif
1650 /* any other buf */
1651 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1652 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1653
1654 for (i = 0; i < bufnum; ++i)
1655 {
1656 buf = buflist_findnr(bufnrs[i]);
1657 if (buf == NULL)
1658 continue;
1659 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1660 {
1661 /* Try auto-writing the buffer. If this fails but the buffer no
1662 * longer exists it's not changed, that's OK. */
1663 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1664 break; /* didn't save - still changes */
1665 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001666 }
1667
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001668 if (i >= bufnum)
1669 goto theend;
1670
1671 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001672 exiting = FALSE;
1673#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1674 /*
1675 * When ":confirm" used, don't give an error message.
1676 */
1677 if (!(p_confirm || cmdmod.confirm))
1678#endif
1679 {
1680 /* There must be a wait_return for this message, do_buffer()
1681 * may cause a redraw. But wait_return() is a no-op when vgetc()
1682 * is busy (Quit used from window menu), then make sure we don't
1683 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001684 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685 {
1686 msg_row = cmdline_row;
1687 msg_col = 0;
1688 msg_didout = FALSE;
1689 }
1690 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001691 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692 {
1693 save = no_wait_return;
1694 no_wait_return = FALSE;
1695 wait_return(FALSE);
1696 no_wait_return = save;
1697 }
1698 }
1699
1700#ifdef FEAT_WINDOWS
1701 /* Try to find a window that contains the buffer. */
1702 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001703 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001704 if (wp->w_buffer == buf)
1705 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001706 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001707# ifdef FEAT_AUTOCMD
1708 /* Paranoia: did autocms wipe out the buffer with changes? */
1709 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001710 {
1711 goto theend;
1712 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001713# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001714 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001716buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001717#endif
1718
1719 /* Open the changed buffer in the current window. */
1720 if (buf != curbuf)
1721 set_curbuf(buf, DOBUF_GOTO);
1722
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001723theend:
1724 vim_free(bufnrs);
1725 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726}
1727
1728/*
1729 * return FAIL if there is no file name, OK if there is one
1730 * give error message for FAIL
1731 */
1732 int
1733check_fname()
1734{
1735 if (curbuf->b_ffname == NULL)
1736 {
1737 EMSG(_(e_noname));
1738 return FAIL;
1739 }
1740 return OK;
1741}
1742
1743/*
1744 * flush the contents of a buffer, unless it has no file name
1745 *
1746 * return FAIL for failure, OK otherwise
1747 */
1748 int
1749buf_write_all(buf, forceit)
1750 buf_T *buf;
1751 int forceit;
1752{
1753 int retval;
1754#ifdef FEAT_AUTOCMD
1755 buf_T *old_curbuf = curbuf;
1756#endif
1757
1758 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1759 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1760 FALSE, forceit, TRUE, FALSE));
1761#ifdef FEAT_AUTOCMD
1762 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001763 {
1764 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001766 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767#endif
1768 return retval;
1769}
1770
1771/*
1772 * Code to handle the argument list.
1773 */
1774
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001775static char_u *do_one_arg __ARGS((char_u *str));
1776static int do_arglist __ARGS((char_u *str, int what, int after));
1777static void alist_check_arg_idx __ARGS((void));
1778static int editing_arg_idx __ARGS((win_T *win));
1779#ifdef FEAT_LISTCMDS
1780static int alist_add_list __ARGS((int count, char_u **files, int after));
1781#endif
1782#define AL_SET 1
1783#define AL_ADD 2
1784#define AL_DEL 3
1785
Bram Moolenaar071d4272004-06-13 20:20:40 +00001786/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001787 * Isolate one argument, taking backticks.
1788 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789 * Return a pointer to the start of the next argument.
1790 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001791 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792do_one_arg(str)
1793 char_u *str;
1794{
1795 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796 int inbacktick;
1797
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798 inbacktick = FALSE;
1799 for (p = str; *str; ++str)
1800 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001801 /* When the backslash is used for escaping the special meaning of a
1802 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803 if (rem_backslash(str))
1804 {
1805 *p++ = *str++;
1806 *p++ = *str;
1807 }
1808 else
1809 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001810 /* An item ends at a space not in backticks */
1811 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001813 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001815 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001816 }
1817 }
1818 str = skipwhite(str);
1819 *p = NUL;
1820
1821 return str;
1822}
1823
Bram Moolenaar86b68352004-12-27 21:59:20 +00001824/*
1825 * Separate the arguments in "str" and return a list of pointers in the
1826 * growarray "gap".
1827 */
1828 int
1829get_arglist(gap, str)
1830 garray_T *gap;
1831 char_u *str;
1832{
1833 ga_init2(gap, (int)sizeof(char_u *), 20);
1834 while (*str != NUL)
1835 {
1836 if (ga_grow(gap, 1) == FAIL)
1837 {
1838 ga_clear(gap);
1839 return FAIL;
1840 }
1841 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1842
1843 /* Isolate one argument, change it in-place, put a NUL after it. */
1844 str = do_one_arg(str);
1845 }
1846 return OK;
1847}
1848
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001849#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001850/*
1851 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001852 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001853 * Return FAIL or OK.
1854 */
1855 int
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001856get_arglist_exp(str, fcountp, fnamesp, wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001857 char_u *str;
1858 int *fcountp;
1859 char_u ***fnamesp;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001860 int wig;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001861{
1862 garray_T ga;
1863 int i;
1864
1865 if (get_arglist(&ga, str) == FAIL)
1866 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001867 if (wig == TRUE)
1868 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1869 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1870 else
1871 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1872 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1873
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001874 ga_clear(&ga);
1875 return i;
1876}
1877#endif
1878
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1880/*
1881 * Redefine the argument list.
1882 */
1883 void
1884set_arglist(str)
1885 char_u *str;
1886{
1887 do_arglist(str, AL_SET, 0);
1888}
1889#endif
1890
1891/*
1892 * "what" == AL_SET: Redefine the argument list to 'str'.
1893 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1894 * "what" == AL_DEL: remove files in 'str' from the argument list.
1895 *
1896 * Return FAIL for failure, OK otherwise.
1897 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 static int
1899do_arglist(str, what, after)
1900 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001901 int what UNUSED;
1902 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903{
1904 garray_T new_ga;
1905 int exp_count;
1906 char_u **exp_files;
1907 int i;
1908#ifdef FEAT_LISTCMDS
1909 char_u *p;
1910 int match;
1911#endif
1912
1913 /*
1914 * Collect all file name arguments in "new_ga".
1915 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001916 if (get_arglist(&new_ga, str) == FAIL)
1917 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918
1919#ifdef FEAT_LISTCMDS
1920 if (what == AL_DEL)
1921 {
1922 regmatch_T regmatch;
1923 int didone;
1924
1925 /*
1926 * Delete the items: use each item as a regexp and find a match in the
1927 * argument list.
1928 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01001929 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1931 {
1932 p = ((char_u **)new_ga.ga_data)[i];
1933 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1934 if (p == NULL)
1935 break;
1936 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1937 if (regmatch.regprog == NULL)
1938 {
1939 vim_free(p);
1940 break;
1941 }
1942
1943 didone = FALSE;
1944 for (match = 0; match < ARGCOUNT; ++match)
1945 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1946 (colnr_T)0))
1947 {
1948 didone = TRUE;
1949 vim_free(ARGLIST[match].ae_fname);
1950 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1951 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1952 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953 if (curwin->w_arg_idx > match)
1954 --curwin->w_arg_idx;
1955 --match;
1956 }
1957
1958 vim_free(regmatch.regprog);
1959 vim_free(p);
1960 if (!didone)
1961 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1962 }
1963 ga_clear(&new_ga);
1964 }
1965 else
1966#endif
1967 {
1968 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1969 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1970 ga_clear(&new_ga);
1971 if (i == FAIL)
1972 return FAIL;
1973 if (exp_count == 0)
1974 {
1975 EMSG(_(e_nomatch));
1976 return FAIL;
1977 }
1978
1979#ifdef FEAT_LISTCMDS
1980 if (what == AL_ADD)
1981 {
1982 (void)alist_add_list(exp_count, exp_files, after);
1983 vim_free(exp_files);
1984 }
1985 else /* what == AL_SET */
1986#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001987 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988 }
1989
1990 alist_check_arg_idx();
1991
1992 return OK;
1993}
1994
1995/*
1996 * Check the validity of the arg_idx for each other window.
1997 */
1998 static void
1999alist_check_arg_idx()
2000{
2001#ifdef FEAT_WINDOWS
2002 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002003 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002004
Bram Moolenaarf740b292006-02-16 22:11:02 +00002005 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002006 if (win->w_alist == curwin->w_alist)
2007 check_arg_idx(win);
2008#else
2009 check_arg_idx(curwin);
2010#endif
2011}
2012
2013/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002014 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002015 * index.
2016 */
2017 static int
2018editing_arg_idx(win)
2019 win_T *win;
2020{
2021 return !(win->w_arg_idx >= WARGCOUNT(win)
2022 || (win->w_buffer->b_fnum
2023 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2024 && (win->w_buffer->b_ffname == NULL
2025 || !(fullpathcmp(
2026 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2027 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2028}
2029
2030/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031 * Check if window "win" is editing the w_arg_idx file in its argument list.
2032 */
2033 void
2034check_arg_idx(win)
2035 win_T *win;
2036{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002037 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002038 {
2039 /* We are not editing the current entry in the argument list.
2040 * Set "arg_had_last" if we are editing the last one. */
2041 win->w_arg_idx_invalid = TRUE;
2042 if (win->w_arg_idx != WARGCOUNT(win) - 1
2043 && arg_had_last == FALSE
2044#ifdef FEAT_WINDOWS
2045 && ALIST(win) == &global_alist
2046#endif
2047 && GARGCOUNT > 0
2048 && win->w_arg_idx < GARGCOUNT
2049 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2050 || (win->w_buffer->b_ffname != NULL
2051 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2052 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2053 arg_had_last = TRUE;
2054 }
2055 else
2056 {
2057 /* We are editing the current entry in the argument list.
2058 * Set "arg_had_last" if it's also the last one */
2059 win->w_arg_idx_invalid = FALSE;
2060 if (win->w_arg_idx == WARGCOUNT(win) - 1
2061#ifdef FEAT_WINDOWS
2062 && win->w_alist == &global_alist
2063#endif
2064 )
2065 arg_had_last = TRUE;
2066 }
2067}
2068
2069/*
2070 * ":args", ":argslocal" and ":argsglobal".
2071 */
2072 void
2073ex_args(eap)
2074 exarg_T *eap;
2075{
2076 int i;
2077
2078 if (eap->cmdidx != CMD_args)
2079 {
2080#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2081 alist_unlink(ALIST(curwin));
2082 if (eap->cmdidx == CMD_argglobal)
2083 ALIST(curwin) = &global_alist;
2084 else /* eap->cmdidx == CMD_arglocal */
2085 alist_new();
2086#else
2087 ex_ni(eap);
2088 return;
2089#endif
2090 }
2091
2092 if (!ends_excmd(*eap->arg))
2093 {
2094 /*
2095 * ":args file ..": define new argument list, handle like ":next"
2096 * Also for ":argslocal file .." and ":argsglobal file ..".
2097 */
2098 ex_next(eap);
2099 }
2100 else
2101#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2102 if (eap->cmdidx == CMD_args)
2103#endif
2104 {
2105 /*
2106 * ":args": list arguments.
2107 */
2108 if (ARGCOUNT > 0)
2109 {
2110 /* Overwrite the command, for a short list there is no scrolling
2111 * required and no wait_return(). */
2112 gotocmdline(TRUE);
2113 for (i = 0; i < ARGCOUNT; ++i)
2114 {
2115 if (i == curwin->w_arg_idx)
2116 msg_putchar('[');
2117 msg_outtrans(alist_name(&ARGLIST[i]));
2118 if (i == curwin->w_arg_idx)
2119 msg_putchar(']');
2120 msg_putchar(' ');
2121 }
2122 }
2123 }
2124#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2125 else if (eap->cmdidx == CMD_arglocal)
2126 {
2127 garray_T *gap = &curwin->w_alist->al_ga;
2128
2129 /*
2130 * ":argslocal": make a local copy of the global argument list.
2131 */
2132 if (ga_grow(gap, GARGCOUNT) == OK)
2133 for (i = 0; i < GARGCOUNT; ++i)
2134 if (GARGLIST[i].ae_fname != NULL)
2135 {
2136 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2137 vim_strsave(GARGLIST[i].ae_fname);
2138 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2139 GARGLIST[i].ae_fnum;
2140 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002141 }
2142 }
2143#endif
2144}
2145
2146/*
2147 * ":previous", ":sprevious", ":Next" and ":sNext".
2148 */
2149 void
2150ex_previous(eap)
2151 exarg_T *eap;
2152{
2153 /* If past the last one already, go to the last one. */
2154 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2155 do_argfile(eap, ARGCOUNT - 1);
2156 else
2157 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2158}
2159
2160/*
2161 * ":rewind", ":first", ":sfirst" and ":srewind".
2162 */
2163 void
2164ex_rewind(eap)
2165 exarg_T *eap;
2166{
2167 do_argfile(eap, 0);
2168}
2169
2170/*
2171 * ":last" and ":slast".
2172 */
2173 void
2174ex_last(eap)
2175 exarg_T *eap;
2176{
2177 do_argfile(eap, ARGCOUNT - 1);
2178}
2179
2180/*
2181 * ":argument" and ":sargument".
2182 */
2183 void
2184ex_argument(eap)
2185 exarg_T *eap;
2186{
2187 int i;
2188
2189 if (eap->addr_count > 0)
2190 i = eap->line2 - 1;
2191 else
2192 i = curwin->w_arg_idx;
2193 do_argfile(eap, i);
2194}
2195
2196/*
2197 * Edit file "argn" of the argument lists.
2198 */
2199 void
2200do_argfile(eap, argn)
2201 exarg_T *eap;
2202 int argn;
2203{
2204 int other;
2205 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002206 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002207
2208 if (argn < 0 || argn >= ARGCOUNT)
2209 {
2210 if (ARGCOUNT <= 1)
2211 EMSG(_("E163: There is only one file to edit"));
2212 else if (argn < 0)
2213 EMSG(_("E164: Cannot go before first file"));
2214 else
2215 EMSG(_("E165: Cannot go beyond last file"));
2216 }
2217 else
2218 {
2219 setpcmark();
2220#ifdef FEAT_GUI
2221 need_mouse_correct = TRUE;
2222#endif
2223
2224#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002225 /* split window or create new tab page first */
2226 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227 {
2228 if (win_split(0, 0) == FAIL)
2229 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002230 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002231 }
2232 else
2233#endif
2234 {
2235 /*
2236 * if 'hidden' set, only check for changed file when re-editing
2237 * the same buffer
2238 */
2239 other = TRUE;
2240 if (P_HID(curbuf))
2241 {
2242 p = fix_fname(alist_name(&ARGLIST[argn]));
2243 other = otherfile(p);
2244 vim_free(p);
2245 }
2246 if ((!P_HID(curbuf) || !other)
2247 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2248 return;
2249 }
2250
2251 curwin->w_arg_idx = argn;
2252 if (argn == ARGCOUNT - 1
2253#ifdef FEAT_WINDOWS
2254 && curwin->w_alist == &global_alist
2255#endif
2256 )
2257 arg_had_last = TRUE;
2258
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002259 /* Edit the file; always use the last known line number.
2260 * When it fails (e.g. Abort for already edited file) restore the
2261 * argument index. */
2262 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002263 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002264 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2265 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002266 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002268 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269 setmark('\'');
2270 }
2271}
2272
2273/*
2274 * ":next", and commands that behave like it.
2275 */
2276 void
2277ex_next(eap)
2278 exarg_T *eap;
2279{
2280 int i;
2281
2282 /*
2283 * check for changed buffer now, if this fails the argument list is not
2284 * redefined.
2285 */
2286 if ( P_HID(curbuf)
2287 || eap->cmdidx == CMD_snext
2288 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2289 {
2290 if (*eap->arg != NUL) /* redefine file list */
2291 {
2292 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2293 return;
2294 i = 0;
2295 }
2296 else
2297 i = curwin->w_arg_idx + (int)eap->line2;
2298 do_argfile(eap, i);
2299 }
2300}
2301
2302#ifdef FEAT_LISTCMDS
2303/*
2304 * ":argedit"
2305 */
2306 void
2307ex_argedit(eap)
2308 exarg_T *eap;
2309{
2310 int fnum;
2311 int i;
2312 char_u *s;
2313
2314 /* Add the argument to the buffer list and get the buffer number. */
2315 fnum = buflist_add(eap->arg, BLN_LISTED);
2316
2317 /* Check if this argument is already in the argument list. */
2318 for (i = 0; i < ARGCOUNT; ++i)
2319 if (ARGLIST[i].ae_fnum == fnum)
2320 break;
2321 if (i == ARGCOUNT)
2322 {
2323 /* Can't find it, add it to the argument list. */
2324 s = vim_strsave(eap->arg);
2325 if (s == NULL)
2326 return;
2327 i = alist_add_list(1, &s,
2328 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2329 if (i < 0)
2330 return;
2331 curwin->w_arg_idx = i;
2332 }
2333
2334 alist_check_arg_idx();
2335
2336 /* Edit the argument. */
2337 do_argfile(eap, i);
2338}
2339
2340/*
2341 * ":argadd"
2342 */
2343 void
2344ex_argadd(eap)
2345 exarg_T *eap;
2346{
2347 do_arglist(eap->arg, AL_ADD,
2348 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2349#ifdef FEAT_TITLE
2350 maketitle();
2351#endif
2352}
2353
2354/*
2355 * ":argdelete"
2356 */
2357 void
2358ex_argdelete(eap)
2359 exarg_T *eap;
2360{
2361 int i;
2362 int n;
2363
2364 if (eap->addr_count > 0)
2365 {
2366 /* ":1,4argdel": Delete all arguments in the range. */
2367 if (eap->line2 > ARGCOUNT)
2368 eap->line2 = ARGCOUNT;
2369 n = eap->line2 - eap->line1 + 1;
2370 if (*eap->arg != NUL || n <= 0)
2371 EMSG(_(e_invarg));
2372 else
2373 {
2374 for (i = eap->line1; i <= eap->line2; ++i)
2375 vim_free(ARGLIST[i - 1].ae_fname);
2376 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2377 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2378 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 if (curwin->w_arg_idx >= eap->line2)
2380 curwin->w_arg_idx -= n;
2381 else if (curwin->w_arg_idx > eap->line1)
2382 curwin->w_arg_idx = eap->line1;
2383 }
2384 }
2385 else if (*eap->arg == NUL)
2386 EMSG(_(e_argreq));
2387 else
2388 do_arglist(eap->arg, AL_DEL, 0);
2389#ifdef FEAT_TITLE
2390 maketitle();
2391#endif
2392}
2393
2394/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002395 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002396 */
2397 void
2398ex_listdo(eap)
2399 exarg_T *eap;
2400{
2401 int i;
2402#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002403 win_T *wp;
2404 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405#endif
2406 buf_T *buf;
2407 int next_fnum = 0;
2408#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2409 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002410#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002411 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412
2413#ifndef FEAT_WINDOWS
2414 if (eap->cmdidx == CMD_windo)
2415 {
2416 ex_ni(eap);
2417 return;
2418 }
2419#endif
2420
2421#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002422 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002423 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2424 * great speed improvement. */
2425 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426#endif
2427
2428 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002429 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430 || P_HID(curbuf)
2431 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2432 {
2433 /* start at the first argument/window/buffer */
2434 i = 0;
2435#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002436 wp = firstwin;
2437 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438#endif
2439 /* set pcmark now */
2440 if (eap->cmdidx == CMD_bufdo)
2441 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2442 else
2443 setpcmark();
2444 listcmd_busy = TRUE; /* avoids setting pcmark below */
2445
2446 while (!got_int)
2447 {
2448 if (eap->cmdidx == CMD_argdo)
2449 {
2450 /* go to argument "i" */
2451 if (i == ARGCOUNT)
2452 break;
2453 /* Don't call do_argfile() when already there, it will try
2454 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002455 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002456 {
2457 /* Clear 'shm' to avoid that the file message overwrites
2458 * any output from the command. */
2459 p_shm_save = vim_strsave(p_shm);
2460 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002462 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2463 vim_free(p_shm_save);
2464 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002465 if (curwin->w_arg_idx != i)
2466 break;
2467 ++i;
2468 }
2469#ifdef FEAT_WINDOWS
2470 else if (eap->cmdidx == CMD_windo)
2471 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002472 /* go to window "wp" */
2473 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002475 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002476 if (curwin != wp)
2477 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002478 wp = curwin->w_next;
2479 }
2480 else if (eap->cmdidx == CMD_tabdo)
2481 {
2482 /* go to window "tp" */
2483 if (!valid_tabpage(tp))
2484 break;
Bram Moolenaara8596c42012-06-13 14:28:20 +02002485 goto_tabpage_tp(tp, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002486 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487 }
2488#endif
2489 else if (eap->cmdidx == CMD_bufdo)
2490 {
2491 /* Remember the number of the next listed buffer, in case
2492 * ":bwipe" is used or autocommands do something strange. */
2493 next_fnum = -1;
2494 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2495 if (buf->b_p_bl)
2496 {
2497 next_fnum = buf->b_fnum;
2498 break;
2499 }
2500 }
2501
2502 /* execute the command */
2503 do_cmdline(eap->arg, eap->getline, eap->cookie,
2504 DOCMD_VERBOSE + DOCMD_NOWAIT);
2505
2506 if (eap->cmdidx == CMD_bufdo)
2507 {
2508 /* Done? */
2509 if (next_fnum < 0)
2510 break;
2511 /* Check if the buffer still exists. */
2512 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2513 if (buf->b_fnum == next_fnum)
2514 break;
2515 if (buf == NULL)
2516 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002517
2518 /* Go to the next buffer. Clear 'shm' to avoid that the file
2519 * message overwrites any output from the command. */
2520 p_shm_save = vim_strsave(p_shm);
2521 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002522 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002523 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2524 vim_free(p_shm_save);
2525
Bram Moolenaar071d4272004-06-13 20:20:40 +00002526 /* If autocommands took us elsewhere, quit here */
2527 if (curbuf->b_fnum != next_fnum)
2528 break;
2529 }
2530
2531 if (eap->cmdidx == CMD_windo)
2532 {
2533 validate_cursor(); /* cursor may have moved */
2534#ifdef FEAT_SCROLLBIND
2535 /* required when 'scrollbind' has been set */
2536 if (curwin->w_p_scb)
2537 do_check_scrollbind(TRUE);
2538#endif
2539 }
2540 }
2541 listcmd_busy = FALSE;
2542 }
2543
2544#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002545 if (save_ei != NULL)
2546 {
2547 au_event_restore(save_ei);
2548 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2549 curbuf->b_fname, TRUE, curbuf);
2550 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002551#endif
2552}
2553
2554/*
2555 * Add files[count] to the arglist of the current window after arg "after".
2556 * The file names in files[count] must have been allocated and are taken over.
2557 * Files[] itself is not taken over.
2558 * Returns index of first added argument. Returns -1 when failed (out of mem).
2559 */
2560 static int
2561alist_add_list(count, files, after)
2562 int count;
2563 char_u **files;
2564 int after; /* where to add: 0 = before first one */
2565{
2566 int i;
2567
2568 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2569 {
2570 if (after < 0)
2571 after = 0;
2572 if (after > ARGCOUNT)
2573 after = ARGCOUNT;
2574 if (after < ARGCOUNT)
2575 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2576 (ARGCOUNT - after) * sizeof(aentry_T));
2577 for (i = 0; i < count; ++i)
2578 {
2579 ARGLIST[after + i].ae_fname = files[i];
2580 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2581 }
2582 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583 if (curwin->w_arg_idx >= after)
2584 ++curwin->w_arg_idx;
2585 return after;
2586 }
2587
2588 for (i = 0; i < count; ++i)
2589 vim_free(files[i]);
2590 return -1;
2591}
2592
2593#endif /* FEAT_LISTCMDS */
2594
2595#ifdef FEAT_EVAL
2596/*
2597 * ":compiler[!] {name}"
2598 */
2599 void
2600ex_compiler(eap)
2601 exarg_T *eap;
2602{
2603 char_u *buf;
2604 char_u *old_cur_comp = NULL;
2605 char_u *p;
2606
2607 if (*eap->arg == NUL)
2608 {
2609 /* List all compiler scripts. */
2610 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2611 /* ) keep the indenter happy... */
2612 }
2613 else
2614 {
2615 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2616 if (buf != NULL)
2617 {
2618 if (eap->forceit)
2619 {
2620 /* ":compiler! {name}" sets global options */
2621 do_cmdline_cmd((char_u *)
2622 "command -nargs=* CompilerSet set <args>");
2623 }
2624 else
2625 {
2626 /* ":compiler! {name}" sets local options.
2627 * To remain backwards compatible "current_compiler" is always
2628 * used. A user's compiler plugin may set it, the distributed
2629 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002630 * "b:current_compiler" and restore "current_compiler".
2631 * Explicitly prepend "g:" to make it work in a function. */
2632 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633 if (old_cur_comp != NULL)
2634 old_cur_comp = vim_strsave(old_cur_comp);
2635 do_cmdline_cmd((char_u *)
2636 "command -nargs=* CompilerSet setlocal <args>");
2637 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002638 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002639 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640
2641 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002642 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2644 vim_free(buf);
2645
2646 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2647
2648 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002649 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650 if (p != NULL)
2651 set_internal_string_var((char_u *)"b:current_compiler", p);
2652
2653 /* Restore "current_compiler" for ":compiler {name}". */
2654 if (!eap->forceit)
2655 {
2656 if (old_cur_comp != NULL)
2657 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002658 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002659 old_cur_comp);
2660 vim_free(old_cur_comp);
2661 }
2662 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002663 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002664 }
2665 }
2666 }
2667}
2668#endif
2669
2670/*
2671 * ":runtime {name}"
2672 */
2673 void
2674ex_runtime(eap)
2675 exarg_T *eap;
2676{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002677 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678}
2679
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002680static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681
2682 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002683source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002685 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002687 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688}
2689
2690/*
2691 * Source the file "name" from all directories in 'runtimepath'.
2692 * "name" can contain wildcards.
2693 * When "all" is TRUE, source all files, otherwise only the first one.
2694 * return FAIL when no file could be sourced, OK otherwise.
2695 */
2696 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002697source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 char_u *name;
2699 int all;
2700{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002701 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702}
2703
2704/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002705 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2706 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2708 * used.
2709 * Returns OK when at least one match found, FAIL otherwise.
2710 */
2711 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002712do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002713 char_u *name;
2714 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002715 void (*callback)__ARGS((char_u *fname, void *ck));
2716 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717{
2718 char_u *rtp;
2719 char_u *np;
2720 char_u *buf;
2721 char_u *rtp_copy;
2722 char_u *tail;
2723 int num_files;
2724 char_u **files;
2725 int i;
2726 int did_one = FALSE;
2727#ifdef AMIGA
2728 struct Process *proc = (struct Process *)FindTask(0L);
2729 APTR save_winptr = proc->pr_WindowPtr;
2730
2731 /* Avoid a requester here for a volume that doesn't exist. */
2732 proc->pr_WindowPtr = (APTR)-1L;
2733#endif
2734
2735 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2736 * value. */
2737 rtp_copy = vim_strsave(p_rtp);
2738 buf = alloc(MAXPATHL);
2739 if (buf != NULL && rtp_copy != NULL)
2740 {
2741 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002742 {
2743 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002744 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002746 verbose_leave();
2747 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002748
Bram Moolenaar071d4272004-06-13 20:20:40 +00002749 /* Loop over all entries in 'runtimepath'. */
2750 rtp = rtp_copy;
2751 while (*rtp != NUL && (all || !did_one))
2752 {
2753 /* Copy the path from 'runtimepath' to buf[]. */
2754 copy_option_part(&rtp, buf, MAXPATHL, ",");
2755 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2756 {
2757 add_pathsep(buf);
2758 tail = buf + STRLEN(buf);
2759
2760 /* Loop over all patterns in "name" */
2761 np = name;
2762 while (*np != NUL && (all || !did_one))
2763 {
2764 /* Append the pattern from "name" to buf[]. */
2765 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2766 "\t ");
2767
2768 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002769 {
2770 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002771 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002772 verbose_leave();
2773 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002774
2775 /* Expand wildcards, invoke the callback for each match. */
2776 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2777 EW_FILE) == OK)
2778 {
2779 for (i = 0; i < num_files; ++i)
2780 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002781 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002782 did_one = TRUE;
2783 if (!all)
2784 break;
2785 }
2786 FreeWild(num_files, files);
2787 }
2788 }
2789 }
2790 }
2791 }
2792 vim_free(buf);
2793 vim_free(rtp_copy);
2794 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002795 {
2796 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002797 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002798 verbose_leave();
2799 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002800
2801#ifdef AMIGA
2802 proc->pr_WindowPtr = save_winptr;
2803#endif
2804
2805 return did_one ? OK : FAIL;
2806}
2807
2808#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2809/*
2810 * ":options"
2811 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812 void
2813ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002814 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002815{
2816 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2817}
2818#endif
2819
2820/*
2821 * ":source {fname}"
2822 */
2823 void
2824ex_source(eap)
2825 exarg_T *eap;
2826{
2827#ifdef FEAT_BROWSE
2828 if (cmdmod.browse)
2829 {
2830 char_u *fname = NULL;
2831
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002832 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002833 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2834 if (fname != NULL)
2835 {
2836 cmd_source(fname, eap);
2837 vim_free(fname);
2838 }
2839 }
2840 else
2841#endif
2842 cmd_source(eap->arg, eap);
2843}
2844
2845 static void
2846cmd_source(fname, eap)
2847 char_u *fname;
2848 exarg_T *eap;
2849{
2850 if (*fname == NUL)
2851 EMSG(_(e_argreq));
2852
Bram Moolenaar071d4272004-06-13 20:20:40 +00002853 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002854 /* ":source!": read Normal mdoe commands
2855 * Need to execute the commands directly. This is required at least
2856 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857 * - ":g" command busy
2858 * - after ":argdo", ":windo" or ":bufdo"
2859 * - another command follows
2860 * - inside a loop
2861 */
2862 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2863#ifdef FEAT_EVAL
2864 || eap->cstack->cs_idx >= 0
2865#endif
2866 );
2867
2868 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002869 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870 EMSG2(_(e_notopen), fname);
2871}
2872
2873/*
2874 * ":source" and associated commands.
2875 */
2876/*
2877 * Structure used to store info for each sourced file.
2878 * It is shared between do_source() and getsourceline().
2879 * This is required, because it needs to be handed to do_cmdline() and
2880 * sourcing can be done recursively.
2881 */
2882struct source_cookie
2883{
2884 FILE *fp; /* opened file for sourcing */
2885 char_u *nextline; /* if not NULL: line that was read ahead */
2886 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002887#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2889 int error; /* TRUE if LF found after CR-LF */
2890#endif
2891#ifdef FEAT_EVAL
2892 linenr_T breakpoint; /* next line with breakpoint or zero */
2893 char_u *fname; /* name of sourced file */
2894 int dbg_tick; /* debug_tick when breakpoint was set */
2895 int level; /* top nesting level of sourced file */
2896#endif
2897#ifdef FEAT_MBYTE
2898 vimconv_T conv; /* type of conversion */
2899#endif
2900};
2901
2902#ifdef FEAT_EVAL
2903/*
2904 * Return the address holding the next breakpoint line for a source cookie.
2905 */
2906 linenr_T *
2907source_breakpoint(cookie)
2908 void *cookie;
2909{
2910 return &((struct source_cookie *)cookie)->breakpoint;
2911}
2912
2913/*
2914 * Return the address holding the debug tick for a source cookie.
2915 */
2916 int *
2917source_dbg_tick(cookie)
2918 void *cookie;
2919{
2920 return &((struct source_cookie *)cookie)->dbg_tick;
2921}
2922
2923/*
2924 * Return the nesting level for a source cookie.
2925 */
2926 int
2927source_level(cookie)
2928 void *cookie;
2929{
2930 return ((struct source_cookie *)cookie)->level;
2931}
2932#endif
2933
2934static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2935
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002936#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2937# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938static FILE *fopen_noinh_readbin __ARGS((char *filename));
2939
2940/*
2941 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002942 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002943 */
2944 static FILE *
2945fopen_noinh_readbin(filename)
2946 char *filename;
2947{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002948# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002949 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2950# else
2951 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002952# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953
2954 if (fd_tmp == -1)
2955 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002956
2957# ifdef HAVE_FD_CLOEXEC
2958 {
2959 int fdflags = fcntl(fd_tmp, F_GETFD);
2960 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
2961 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
2962 }
2963# endif
2964
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965 return fdopen(fd_tmp, READBIN);
2966}
2967#endif
2968
2969
2970/*
2971 * do_source: Read the file "fname" and execute its lines as EX commands.
2972 *
2973 * This function may be called recursively!
2974 *
2975 * return FAIL if file could not be opened, OK otherwise
2976 */
2977 int
2978do_source(fname, check_other, is_vimrc)
2979 char_u *fname;
2980 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002981 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002982{
2983 struct source_cookie cookie;
2984 char_u *save_sourcing_name;
2985 linenr_T save_sourcing_lnum;
2986 char_u *p;
2987 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002988 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002989 int retval = FAIL;
2990#ifdef FEAT_EVAL
2991 scid_T save_current_SID;
2992 static scid_T last_current_SID = 0;
2993 void *save_funccalp;
2994 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002995 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002996# ifdef UNIX
2997 struct stat st;
2998 int stat_ok;
2999# endif
3000#endif
3001#ifdef STARTUPTIME
3002 struct timeval tv_rel;
3003 struct timeval tv_start;
3004#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003005#ifdef FEAT_PROFILE
3006 proftime_T wait_start;
3007#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008
Bram Moolenaar071d4272004-06-13 20:20:40 +00003009 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010 if (p == NULL)
3011 return retval;
3012 fname_exp = fix_fname(p);
3013 vim_free(p);
3014 if (fname_exp == NULL)
3015 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 if (mch_isdir(fname_exp))
3017 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003018 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003019 goto theend;
3020 }
3021
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003022#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003023 /* Apply SourceCmd autocommands, they should get the file and source it. */
3024 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3025 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3026 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003027 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003028# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003029 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003030# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003031 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003032# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003033 goto theend;
3034 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003035
3036 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003037 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3038#endif
3039
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003040#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3042#else
3043 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3044#endif
3045 if (cookie.fp == NULL && check_other)
3046 {
3047 /*
3048 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3049 * and ".exrc" by "_exrc" or vice versa.
3050 */
3051 p = gettail(fname_exp);
3052 if ((*p == '.' || *p == '_')
3053 && (STRICMP(p + 1, "vimrc") == 0
3054 || STRICMP(p + 1, "gvimrc") == 0
3055 || STRICMP(p + 1, "exrc") == 0))
3056 {
3057 if (*p == '_')
3058 *p = '.';
3059 else
3060 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003061#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3063#else
3064 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3065#endif
3066 }
3067 }
3068
3069 if (cookie.fp == NULL)
3070 {
3071 if (p_verbose > 0)
3072 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003073 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003075 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 else
3077 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003078 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003079 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003080 }
3081 goto theend;
3082 }
3083
3084 /*
3085 * The file exists.
3086 * - In verbose mode, give a message.
3087 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3088 */
3089 if (p_verbose > 1)
3090 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003091 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003093 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094 else
3095 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003096 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003097 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003099 if (is_vimrc == DOSO_VIMRC)
3100 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3101 else if (is_vimrc == DOSO_GVIMRC)
3102 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103
3104#ifdef USE_CRNL
3105 /* If no automatic file format: Set default to CR-NL. */
3106 if (*p_ffs == NUL)
3107 cookie.fileformat = EOL_DOS;
3108 else
3109 cookie.fileformat = EOL_UNKNOWN;
3110 cookie.error = FALSE;
3111#endif
3112
3113#ifdef USE_CR
3114 /* If no automatic file format: Set default to CR. */
3115 if (*p_ffs == NUL)
3116 cookie.fileformat = EOL_MAC;
3117 else
3118 cookie.fileformat = EOL_UNKNOWN;
3119 cookie.error = FALSE;
3120#endif
3121
3122 cookie.nextline = NULL;
3123 cookie.finished = FALSE;
3124
3125#ifdef FEAT_EVAL
3126 /*
3127 * Check if this script has a breakpoint.
3128 */
3129 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3130 cookie.fname = fname_exp;
3131 cookie.dbg_tick = debug_tick;
3132
3133 cookie.level = ex_nesting_level;
3134#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135
3136 /*
3137 * Keep the sourcing name/lnum, for recursive calls.
3138 */
3139 save_sourcing_name = sourcing_name;
3140 sourcing_name = fname_exp;
3141 save_sourcing_lnum = sourcing_lnum;
3142 sourcing_lnum = 0;
3143
Bram Moolenaar73881402009-02-04 16:50:47 +00003144#ifdef FEAT_MBYTE
3145 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3146
3147 /* Read the first line so we can check for a UTF-8 BOM. */
3148 firstline = getsourceline(0, (void *)&cookie, 0);
3149 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3150 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3151 {
3152 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3153 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3154 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003155 if (p == NULL)
3156 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003157 if (p != NULL)
3158 {
3159 vim_free(firstline);
3160 firstline = p;
3161 }
3162 }
3163#endif
3164
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003166 if (time_fd != NULL)
3167 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168#endif
3169
3170#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003171# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003172 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003173 prof_child_enter(&wait_start); /* entering a child now */
3174# endif
3175
3176 /* Don't use local function variables, if called from a function.
3177 * Also starts profiling timer for nested script. */
3178 save_funccalp = save_funccal();
3179
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180 /*
3181 * Check if this script was sourced before to finds its SID.
3182 * If it's new, generate a new SID.
3183 */
3184 save_current_SID = current_SID;
3185# ifdef UNIX
3186 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3187# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003188 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3189 {
3190 si = &SCRIPT_ITEM(current_SID);
3191 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192 && (
3193# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003194 /* Compare dev/ino when possible, it catches symbolic
3195 * links. Also compare file names, the inode may change
3196 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003197 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003198 && (si->sn_dev == st.st_dev
3199 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003200# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003201 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003202 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003203 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204 if (current_SID == 0)
3205 {
3206 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003207 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3208 == FAIL)
3209 goto almosttheend;
3210 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003212 ++script_items.ga_len;
3213 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3214# ifdef FEAT_PROFILE
3215 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003217 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003218 si = &SCRIPT_ITEM(current_SID);
3219 si->sn_name = fname_exp;
3220 fname_exp = NULL;
3221# ifdef UNIX
3222 if (stat_ok)
3223 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003224 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003225 si->sn_dev = st.st_dev;
3226 si->sn_ino = st.st_ino;
3227 }
3228 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003229 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003230# endif
3231
Bram Moolenaar071d4272004-06-13 20:20:40 +00003232 /* Allocate the local script variables to use for this script. */
3233 new_script_vars(current_SID);
3234 }
3235
Bram Moolenaar05159a02005-02-26 23:04:13 +00003236# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003237 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003238 {
3239 int forceit;
3240
3241 /* Check if we do profiling for this script. */
3242 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3243 {
3244 script_do_profile(si);
3245 si->sn_pr_force = forceit;
3246 }
3247 if (si->sn_prof_on)
3248 {
3249 ++si->sn_pr_count;
3250 profile_start(&si->sn_pr_start);
3251 profile_zero(&si->sn_pr_children);
3252 }
3253 }
3254# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255#endif
3256
3257 /*
3258 * Call do_cmdline, which will call getsourceline() to get the lines.
3259 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003260 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003263
3264#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003265 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003266 {
3267 /* Get "si" again, "script_items" may have been reallocated. */
3268 si = &SCRIPT_ITEM(current_SID);
3269 if (si->sn_prof_on)
3270 {
3271 profile_end(&si->sn_pr_start);
3272 profile_sub_wait(&wait_start, &si->sn_pr_start);
3273 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003274 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3275 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003276 }
3277 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278#endif
3279
3280 if (got_int)
3281 EMSG(_(e_interr));
3282 sourcing_name = save_sourcing_name;
3283 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284 if (p_verbose > 1)
3285 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003286 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003287 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003289 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003290 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291 }
3292#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003293 if (time_fd != NULL)
3294 {
3295 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3296 time_msg((char *)IObuff, &tv_start);
3297 time_pop(&tv_rel);
3298 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299#endif
3300
3301#ifdef FEAT_EVAL
3302 /*
3303 * After a "finish" in debug mode, need to break at first command of next
3304 * sourced file.
3305 */
3306 if (save_debug_break_level > ex_nesting_level
3307 && debug_break_level == ex_nesting_level)
3308 ++debug_break_level;
3309#endif
3310
Bram Moolenaar05159a02005-02-26 23:04:13 +00003311#ifdef FEAT_EVAL
3312almosttheend:
3313 current_SID = save_current_SID;
3314 restore_funccal(save_funccalp);
3315# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003316 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003317 prof_child_exit(&wait_start); /* leaving a child now */
3318# endif
3319#endif
3320 fclose(cookie.fp);
3321 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003322 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003323#ifdef FEAT_MBYTE
3324 convert_setup(&cookie.conv, NULL, NULL);
3325#endif
3326
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327theend:
3328 vim_free(fname_exp);
3329 return retval;
3330}
3331
3332#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003333
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334/*
3335 * ":scriptnames"
3336 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 void
3338ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003339 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340{
3341 int i;
3342
Bram Moolenaar05159a02005-02-26 23:04:13 +00003343 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3344 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003345 {
3346 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3347 NameBuff, MAXPATHL, TRUE);
3348 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003349 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003350}
3351
3352# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3353/*
3354 * Fix slashes in the list of script names for 'shellslash'.
3355 */
3356 void
3357scriptnames_slash_adjust()
3358{
3359 int i;
3360
Bram Moolenaar05159a02005-02-26 23:04:13 +00003361 for (i = 1; i <= script_items.ga_len; ++i)
3362 if (SCRIPT_ITEM(i).sn_name != NULL)
3363 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003364}
3365# endif
3366
3367/*
3368 * Get a pointer to a script name. Used for ":verbose set".
3369 */
3370 char_u *
3371get_scriptname(id)
3372 scid_T id;
3373{
3374 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003375 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003376 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003377 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003378 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003379 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003380 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003381 return (char_u *)_("environment variable");
3382 if (id == SID_ERROR)
3383 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003384 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003386
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003387# if defined(EXITFREE) || defined(PROTO)
3388 void
3389free_scriptnames()
3390{
3391 int i;
3392
3393 for (i = script_items.ga_len; i > 0; --i)
3394 vim_free(SCRIPT_ITEM(i).sn_name);
3395 ga_clear(&script_items);
3396}
3397# endif
3398
Bram Moolenaar071d4272004-06-13 20:20:40 +00003399#endif
3400
3401#if defined(USE_CR) || defined(PROTO)
3402
3403# if defined(__MSL__) && (__MSL__ >= 22)
3404/*
3405 * Newer version of the Metrowerks library handle DOS and UNIX files
3406 * without help.
3407 * Test with earlier versions, MSL 2.2 is the library supplied with
3408 * Codewarrior Pro 2.
3409 */
3410 char *
3411fgets_cr(s, n, stream)
3412 char *s;
3413 int n;
3414 FILE *stream;
3415{
3416 return fgets(s, n, stream);
3417}
3418# else
3419/*
3420 * Version of fgets() which also works for lines ending in a <CR> only
3421 * (Macintosh format).
3422 * For older versions of the Metrowerks library.
3423 * At least CodeWarrior 9 needed this code.
3424 */
3425 char *
3426fgets_cr(s, n, stream)
3427 char *s;
3428 int n;
3429 FILE *stream;
3430{
3431 int c = 0;
3432 int char_read = 0;
3433
3434 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3435 {
3436 c = fgetc(stream);
3437 s[char_read++] = c;
3438 /* If the file is in DOS format, we need to skip a NL after a CR. I
3439 * thought it was the other way around, but this appears to work... */
3440 if (c == '\n')
3441 {
3442 c = fgetc(stream);
3443 if (c != '\r')
3444 ungetc(c, stream);
3445 }
3446 }
3447
3448 s[char_read] = 0;
3449 if (char_read == 0)
3450 return NULL;
3451
3452 if (feof(stream) && char_read == 1)
3453 return NULL;
3454
3455 return s;
3456}
3457# endif
3458#endif
3459
3460/*
3461 * Get one full line from a sourced file.
3462 * Called by do_cmdline() when it's called from do_source().
3463 *
3464 * Return a pointer to the line in allocated memory.
3465 * Return NULL for end-of-file or some error.
3466 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003467 char_u *
3468getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003469 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003471 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003472{
3473 struct source_cookie *sp = (struct source_cookie *)cookie;
3474 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003475 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476
3477#ifdef FEAT_EVAL
3478 /* If breakpoints have been added/deleted need to check for it. */
3479 if (sp->dbg_tick < debug_tick)
3480 {
3481 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3482 sp->dbg_tick = debug_tick;
3483 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003484# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003485 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003486 script_line_end();
3487# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003488#endif
3489 /*
3490 * Get current line. If there is a read-ahead line, use it, otherwise get
3491 * one now.
3492 */
3493 if (sp->finished)
3494 line = NULL;
3495 else if (sp->nextline == NULL)
3496 line = get_one_sourceline(sp);
3497 else
3498 {
3499 line = sp->nextline;
3500 sp->nextline = NULL;
3501 ++sourcing_lnum;
3502 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003503#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003504 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003505 script_line_start();
3506#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003507
3508 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3509 * contain the 'C' flag. */
3510 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3511 {
3512 /* compensate for the one line read-ahead */
3513 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003514
3515 /* Get the next line and concatenate it when it starts with a
3516 * backslash. We always need to read the next line, keep it in
3517 * sp->nextline. */
3518 sp->nextline = get_one_sourceline(sp);
3519 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003521 garray_T ga;
3522
Bram Moolenaarb549a732012-02-22 18:29:33 +01003523 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003524 ga_concat(&ga, line);
3525 ga_concat(&ga, p + 1);
3526 for (;;)
3527 {
3528 vim_free(sp->nextline);
3529 sp->nextline = get_one_sourceline(sp);
3530 if (sp->nextline == NULL)
3531 break;
3532 p = skipwhite(sp->nextline);
3533 if (*p != '\\')
3534 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003535 /* Adjust the growsize to the current length to speed up
3536 * concatenating many lines. */
3537 if (ga.ga_len > 400)
3538 {
3539 if (ga.ga_len > 8000)
3540 ga.ga_growsize = 8000;
3541 else
3542 ga.ga_growsize = ga.ga_len;
3543 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003544 ga_concat(&ga, p + 1);
3545 }
3546 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003547 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003548 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003549 }
3550 }
3551
3552#ifdef FEAT_MBYTE
3553 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3554 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003555 char_u *s;
3556
Bram Moolenaar071d4272004-06-13 20:20:40 +00003557 /* Convert the encoding of the script line. */
3558 s = string_convert(&sp->conv, line, NULL);
3559 if (s != NULL)
3560 {
3561 vim_free(line);
3562 line = s;
3563 }
3564 }
3565#endif
3566
3567#ifdef FEAT_EVAL
3568 /* Did we encounter a breakpoint? */
3569 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3570 {
3571 dbg_breakpoint(sp->fname, sourcing_lnum);
3572 /* Find next breakpoint. */
3573 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3574 sp->dbg_tick = debug_tick;
3575 }
3576#endif
3577
3578 return line;
3579}
3580
3581 static char_u *
3582get_one_sourceline(sp)
3583 struct source_cookie *sp;
3584{
3585 garray_T ga;
3586 int len;
3587 int c;
3588 char_u *buf;
3589#ifdef USE_CRNL
3590 int has_cr; /* CR-LF found */
3591#endif
3592#ifdef USE_CR
3593 char_u *scan;
3594#endif
3595 int have_read = FALSE;
3596
3597 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003598 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003599
3600 /*
3601 * Loop until there is a finished line (or end-of-file).
3602 */
3603 sourcing_lnum++;
3604 for (;;)
3605 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003606 /* make room to read at least 120 (more) characters */
3607 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608 break;
3609 buf = (char_u *)ga.ga_data;
3610
3611#ifdef USE_CR
3612 if (sp->fileformat == EOL_MAC)
3613 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003614 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3615 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616 break;
3617 }
3618 else
3619#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003620 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3621 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003622 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003623 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003624#ifdef USE_CRNL
3625 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3626 * CTRL-Z by its own, or after a NL. */
3627 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3628 && sp->fileformat == EOL_DOS
3629 && buf[len - 1] == Ctrl_Z)
3630 {
3631 buf[len - 1] = NUL;
3632 break;
3633 }
3634#endif
3635
3636#ifdef USE_CR
3637 /* If the read doesn't stop on a new line, and there's
3638 * some CR then we assume a Mac format */
3639 if (sp->fileformat == EOL_UNKNOWN)
3640 {
3641 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3642 sp->fileformat = EOL_MAC;
3643 else
3644 sp->fileformat = EOL_UNIX;
3645 }
3646
3647 if (sp->fileformat == EOL_MAC)
3648 {
3649 scan = vim_strchr(buf, '\r');
3650
3651 if (scan != NULL)
3652 {
3653 *scan = '\n';
3654 if (*(scan + 1) != 0)
3655 {
3656 *(scan + 1) = 0;
3657 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3658 }
3659 }
3660 len = STRLEN(buf);
3661 }
3662#endif
3663
3664 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 ga.ga_len = len;
3666
3667 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003668 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669 continue;
3670
3671 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3672 {
3673#ifdef USE_CRNL
3674 has_cr = (len >= 2 && buf[len - 2] == '\r');
3675 if (sp->fileformat == EOL_UNKNOWN)
3676 {
3677 if (has_cr)
3678 sp->fileformat = EOL_DOS;
3679 else
3680 sp->fileformat = EOL_UNIX;
3681 }
3682
3683 if (sp->fileformat == EOL_DOS)
3684 {
3685 if (has_cr) /* replace trailing CR */
3686 {
3687 buf[len - 2] = '\n';
3688 --len;
3689 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 }
3691 else /* lines like ":map xx yy^M" will have failed */
3692 {
3693 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003694 {
3695 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003696 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003697 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003698 sp->error = TRUE;
3699 sp->fileformat = EOL_UNIX;
3700 }
3701 }
3702#endif
3703 /* The '\n' is escaped if there is an odd number of ^V's just
3704 * before it, first set "c" just before the 'V's and then check
3705 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3706 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3707 ;
3708 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3709 {
3710 sourcing_lnum++;
3711 continue;
3712 }
3713
3714 buf[len - 1] = NUL; /* remove the NL */
3715 }
3716
3717 /*
3718 * Check for ^C here now and then, so recursive :so can be broken.
3719 */
3720 line_breakcheck();
3721 break;
3722 }
3723
3724 if (have_read)
3725 return (char_u *)ga.ga_data;
3726
3727 vim_free(ga.ga_data);
3728 return NULL;
3729}
3730
Bram Moolenaar05159a02005-02-26 23:04:13 +00003731#if defined(FEAT_PROFILE) || defined(PROTO)
3732/*
3733 * Called when starting to read a script line.
3734 * "sourcing_lnum" must be correct!
3735 * When skipping lines it may not actually be executed, but we won't find out
3736 * until later and we need to store the time now.
3737 */
3738 void
3739script_line_start()
3740{
3741 scriptitem_T *si;
3742 sn_prl_T *pp;
3743
3744 if (current_SID <= 0 || current_SID > script_items.ga_len)
3745 return;
3746 si = &SCRIPT_ITEM(current_SID);
3747 if (si->sn_prof_on && sourcing_lnum >= 1)
3748 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003749 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003750 * here isn't counted. */
3751 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3752 si->sn_prl_idx = sourcing_lnum - 1;
3753 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3754 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3755 {
3756 /* Zero counters for a line that was not used before. */
3757 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3758 pp->snp_count = 0;
3759 profile_zero(&pp->sn_prl_total);
3760 profile_zero(&pp->sn_prl_self);
3761 ++si->sn_prl_ga.ga_len;
3762 }
3763 si->sn_prl_execed = FALSE;
3764 profile_start(&si->sn_prl_start);
3765 profile_zero(&si->sn_prl_children);
3766 profile_get_wait(&si->sn_prl_wait);
3767 }
3768}
3769
3770/*
3771 * Called when actually executing a function line.
3772 */
3773 void
3774script_line_exec()
3775{
3776 scriptitem_T *si;
3777
3778 if (current_SID <= 0 || current_SID > script_items.ga_len)
3779 return;
3780 si = &SCRIPT_ITEM(current_SID);
3781 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3782 si->sn_prl_execed = TRUE;
3783}
3784
3785/*
3786 * Called when done with a function line.
3787 */
3788 void
3789script_line_end()
3790{
3791 scriptitem_T *si;
3792 sn_prl_T *pp;
3793
3794 if (current_SID <= 0 || current_SID > script_items.ga_len)
3795 return;
3796 si = &SCRIPT_ITEM(current_SID);
3797 if (si->sn_prof_on && si->sn_prl_idx >= 0
3798 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3799 {
3800 if (si->sn_prl_execed)
3801 {
3802 pp = &PRL_ITEM(si, si->sn_prl_idx);
3803 ++pp->snp_count;
3804 profile_end(&si->sn_prl_start);
3805 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003806 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003807 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3808 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003809 }
3810 si->sn_prl_idx = -1;
3811 }
3812}
3813#endif
3814
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815/*
3816 * ":scriptencoding": Set encoding conversion for a sourced script.
3817 * Without the multi-byte feature it's simply ignored.
3818 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 void
3820ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003821 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822{
3823#ifdef FEAT_MBYTE
3824 struct source_cookie *sp;
3825 char_u *name;
3826
3827 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3828 {
3829 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3830 return;
3831 }
3832
3833 if (*eap->arg != NUL)
3834 {
3835 name = enc_canonize(eap->arg);
3836 if (name == NULL) /* out of memory */
3837 return;
3838 }
3839 else
3840 name = eap->arg;
3841
3842 /* Setup for conversion from the specified encoding to 'encoding'. */
3843 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3844 convert_setup(&sp->conv, name, p_enc);
3845
3846 if (name != eap->arg)
3847 vim_free(name);
3848#endif
3849}
3850
3851#if defined(FEAT_EVAL) || defined(PROTO)
3852/*
3853 * ":finish": Mark a sourced file as finished.
3854 */
3855 void
3856ex_finish(eap)
3857 exarg_T *eap;
3858{
3859 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3860 do_finish(eap, FALSE);
3861 else
3862 EMSG(_("E168: :finish used outside of a sourced file"));
3863}
3864
3865/*
3866 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3867 * Also called for a pending finish at the ":endtry" or after returning from
3868 * an extra do_cmdline(). "reanimate" is used in the latter case.
3869 */
3870 void
3871do_finish(eap, reanimate)
3872 exarg_T *eap;
3873 int reanimate;
3874{
3875 int idx;
3876
3877 if (reanimate)
3878 ((struct source_cookie *)getline_cookie(eap->getline,
3879 eap->cookie))->finished = FALSE;
3880
3881 /*
3882 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3883 * not in its finally clause (which then is to be executed next) is found.
3884 * In this case, make the ":finish" pending for execution at the ":endtry".
3885 * Otherwise, finish normally.
3886 */
3887 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3888 if (idx >= 0)
3889 {
3890 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3891 report_make_pending(CSTP_FINISH, NULL);
3892 }
3893 else
3894 ((struct source_cookie *)getline_cookie(eap->getline,
3895 eap->cookie))->finished = TRUE;
3896}
3897
3898
3899/*
3900 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3901 * message for missing ":endif".
3902 * Return FALSE when not sourcing a file.
3903 */
3904 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003905source_finished(fgetline, cookie)
3906 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003907 void *cookie;
3908{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003909 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003910 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003911 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003912}
3913#endif
3914
3915#if defined(FEAT_LISTCMDS) || defined(PROTO)
3916/*
3917 * ":checktime [buffer]"
3918 */
3919 void
3920ex_checktime(eap)
3921 exarg_T *eap;
3922{
3923 buf_T *buf;
3924 int save_no_check_timestamps = no_check_timestamps;
3925
3926 no_check_timestamps = 0;
3927 if (eap->addr_count == 0) /* default is all buffers */
3928 check_timestamps(FALSE);
3929 else
3930 {
3931 buf = buflist_findnr((int)eap->line2);
3932 if (buf != NULL) /* cannot happen? */
3933 (void)buf_check_timestamp(buf, FALSE);
3934 }
3935 no_check_timestamps = save_no_check_timestamps;
3936}
3937#endif
3938
Bram Moolenaar071d4272004-06-13 20:20:40 +00003939#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3940 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003941# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003942static char *get_locale_val __ARGS((int what));
3943
3944 static char *
3945get_locale_val(what)
3946 int what;
3947{
3948 char *loc;
3949
3950 /* Obtain the locale value from the libraries. For DJGPP this is
3951 * redefined and it doesn't use the arguments. */
3952 loc = setlocale(what, NULL);
3953
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003954# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955 if (loc != NULL)
3956 {
3957 char_u *p;
3958
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003959 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3960 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003961 p = vim_strchr(loc, '=');
3962 if (p != NULL)
3963 {
3964 loc = ++p;
3965 while (*p != NUL) /* remove trailing newline */
3966 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003967 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003968 {
3969 *p = NUL;
3970 break;
3971 }
3972 ++p;
3973 }
3974 }
3975 }
3976# endif
3977
3978 return loc;
3979}
3980#endif
3981
3982
3983#ifdef WIN32
3984/*
3985 * On MS-Windows locale names are strings like "German_Germany.1252", but
3986 * gettext expects "de". Try to translate one into another here for a few
3987 * supported languages.
3988 */
3989 static char_u *
3990gettext_lang(char_u *name)
3991{
3992 int i;
3993 static char *(mtable[]) = {
3994 "afrikaans", "af",
3995 "czech", "cs",
3996 "dutch", "nl",
3997 "german", "de",
3998 "english_united kingdom", "en_GB",
3999 "spanish", "es",
4000 "french", "fr",
4001 "italian", "it",
4002 "japanese", "ja",
4003 "korean", "ko",
4004 "norwegian", "no",
4005 "polish", "pl",
4006 "russian", "ru",
4007 "slovak", "sk",
4008 "swedish", "sv",
4009 "ukrainian", "uk",
4010 "chinese_china", "zh_CN",
4011 "chinese_taiwan", "zh_TW",
4012 NULL};
4013
4014 for (i = 0; mtable[i] != NULL; i += 2)
4015 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4016 return mtable[i + 1];
4017 return name;
4018}
4019#endif
4020
4021#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4022/*
4023 * Obtain the current messages language. Used to set the default for
4024 * 'helplang'. May return NULL or an empty string.
4025 */
4026 char_u *
4027get_mess_lang()
4028{
4029 char_u *p;
4030
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004031# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004032# if defined(LC_MESSAGES)
4033 p = (char_u *)get_locale_val(LC_MESSAGES);
4034# else
4035 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004036 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4037 * and LC_MONETARY may be set differently for a Japanese working in the
4038 * US. */
4039 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040# endif
4041# else
4042 p = mch_getenv((char_u *)"LC_ALL");
4043 if (p == NULL || *p == NUL)
4044 {
4045 p = mch_getenv((char_u *)"LC_MESSAGES");
4046 if (p == NULL || *p == NUL)
4047 p = mch_getenv((char_u *)"LANG");
4048 }
4049# endif
4050# ifdef WIN32
4051 p = gettext_lang(p);
4052# endif
4053 return p;
4054}
4055#endif
4056
Bram Moolenaardef9e822004-12-31 20:58:58 +00004057/* Complicated #if; matches with where get_mess_env() is used below. */
4058#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4059 && defined(LC_MESSAGES))) \
4060 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4061 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4062 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063static char_u *get_mess_env __ARGS((void));
4064
4065/*
4066 * Get the language used for messages from the environment.
4067 */
4068 static char_u *
4069get_mess_env()
4070{
4071 char_u *p;
4072
4073 p = mch_getenv((char_u *)"LC_ALL");
4074 if (p == NULL || *p == NUL)
4075 {
4076 p = mch_getenv((char_u *)"LC_MESSAGES");
4077 if (p == NULL || *p == NUL)
4078 {
4079 p = mch_getenv((char_u *)"LANG");
4080 if (p != NULL && VIM_ISDIGIT(*p))
4081 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004082# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004083 if (p == NULL || *p == NUL)
4084 p = (char_u *)get_locale_val(LC_CTYPE);
4085# endif
4086 }
4087 }
4088 return p;
4089}
4090#endif
4091
4092#if defined(FEAT_EVAL) || defined(PROTO)
4093
4094/*
4095 * Set the "v:lang" variable according to the current locale setting.
4096 * Also do "v:lc_time"and "v:ctype".
4097 */
4098 void
4099set_lang_var()
4100{
4101 char_u *loc;
4102
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004103# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104 loc = (char_u *)get_locale_val(LC_CTYPE);
4105# else
4106 /* setlocale() not supported: use the default value */
4107 loc = (char_u *)"C";
4108# endif
4109 set_vim_var_string(VV_CTYPE, loc, -1);
4110
4111 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4112 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004113# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 loc = (char_u *)get_locale_val(LC_MESSAGES);
4115# else
4116 loc = get_mess_env();
4117# endif
4118 set_vim_var_string(VV_LANG, loc, -1);
4119
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004120# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121 loc = (char_u *)get_locale_val(LC_TIME);
4122# endif
4123 set_vim_var_string(VV_LC_TIME, loc, -1);
4124}
4125#endif
4126
4127#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4128 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4129/*
4130 * ":language": Set the language (locale).
4131 */
4132 void
4133ex_language(eap)
4134 exarg_T *eap;
4135{
4136 char *loc;
4137 char_u *p;
4138 char_u *name;
4139 int what = LC_ALL;
4140 char *whatstr = "";
4141#ifdef LC_MESSAGES
4142# define VIM_LC_MESSAGES LC_MESSAGES
4143#else
4144# define VIM_LC_MESSAGES 6789
4145#endif
4146
4147 name = eap->arg;
4148
4149 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4150 * Allow abbreviation, but require at least 3 characters to avoid
4151 * confusion with a two letter language name "me" or "ct". */
4152 p = skiptowhite(eap->arg);
4153 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4154 {
4155 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4156 {
4157 what = VIM_LC_MESSAGES;
4158 name = skipwhite(p);
4159 whatstr = "messages ";
4160 }
4161 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4162 {
4163 what = LC_CTYPE;
4164 name = skipwhite(p);
4165 whatstr = "ctype ";
4166 }
4167 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4168 {
4169 what = LC_TIME;
4170 name = skipwhite(p);
4171 whatstr = "time ";
4172 }
4173 }
4174
4175 if (*name == NUL)
4176 {
4177#ifndef LC_MESSAGES
4178 if (what == VIM_LC_MESSAGES)
4179 p = get_mess_env();
4180 else
4181#endif
4182 p = (char_u *)setlocale(what, NULL);
4183 if (p == NULL || *p == NUL)
4184 p = (char_u *)"Unknown";
4185 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4186 }
4187 else
4188 {
4189#ifndef LC_MESSAGES
4190 if (what == VIM_LC_MESSAGES)
4191 loc = "";
4192 else
4193#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004194 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004195 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004196#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4197 /* Make sure strtod() uses a decimal point, not a comma. */
4198 setlocale(LC_NUMERIC, "C");
4199#endif
4200 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201 if (loc == NULL)
4202 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4203 else
4204 {
4205#ifdef HAVE_NL_MSG_CAT_CNTR
4206 /* Need to do this for GNU gettext, otherwise cached translations
4207 * will be used again. */
4208 extern int _nl_msg_cat_cntr;
4209
4210 ++_nl_msg_cat_cntr;
4211#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004212 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004213 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4214
4215 if (what != LC_TIME)
4216 {
4217 /* Tell gettext() what to translate to. It apparently doesn't
4218 * use the currently effective locale. Also do this when
4219 * FEAT_GETTEXT isn't defined, so that shell commands use this
4220 * value. */
4221 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004222 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004224# ifdef WIN32
4225 /* Apparently MS-Windows printf() may cause a crash when
4226 * we give it 8-bit text while it's expecting text in the
4227 * current locale. This call avoids that. */
4228 setlocale(LC_CTYPE, "C");
4229# endif
4230 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004231 if (what != LC_CTYPE)
4232 {
4233 char_u *mname;
4234#ifdef WIN32
4235 mname = gettext_lang(name);
4236#else
4237 mname = name;
4238#endif
4239 vim_setenv((char_u *)"LC_MESSAGES", mname);
4240#ifdef FEAT_MULTI_LANG
4241 set_helplang_default(mname);
4242#endif
4243 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004244 }
4245
4246# ifdef FEAT_EVAL
4247 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4248 set_lang_var();
4249# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004250# ifdef FEAT_TITLE
4251 maketitle();
4252# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253 }
4254 }
4255}
4256
4257# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004258
4259static char_u **locales = NULL; /* Array of all available locales */
4260static int did_init_locales = FALSE;
4261
4262static void init_locales __ARGS((void));
4263static char_u **find_locales __ARGS((void));
4264
4265/*
4266 * Lazy initialization of all available locales.
4267 */
4268 static void
4269init_locales()
4270{
4271 if (!did_init_locales)
4272 {
4273 did_init_locales = TRUE;
4274 locales = find_locales();
4275 }
4276}
4277
4278/* Return an array of strings for all available locales + NULL for the
4279 * last element. Return NULL in case of error. */
4280 static char_u **
4281find_locales()
4282{
4283 garray_T locales_ga;
4284 char_u *loc;
4285
4286 /* Find all available locales by running command "locale -a". If this
4287 * doesn't work we won't have completion. */
4288 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
4289 NULL, SHELL_SILENT);
4290 if (locale_a == NULL)
4291 return NULL;
4292 ga_init2(&locales_ga, sizeof(char_u *), 20);
4293
4294 /* Transform locale_a string where each locale is separated by "\n"
4295 * into an array of locale strings. */
4296 loc = (char_u *)strtok((char *)locale_a, "\n");
4297
4298 while (loc != NULL)
4299 {
4300 if (ga_grow(&locales_ga, 1) == FAIL)
4301 break;
4302 loc = vim_strsave(loc);
4303 if (loc == NULL)
4304 break;
4305
4306 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4307 loc = (char_u *)strtok(NULL, "\n");
4308 }
4309 vim_free(locale_a);
4310 if (ga_grow(&locales_ga, 1) == FAIL)
4311 {
4312 ga_clear(&locales_ga);
4313 return NULL;
4314 }
4315 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4316 return (char_u **)locales_ga.ga_data;
4317}
4318
4319# if defined(EXITFREE) || defined(PROTO)
4320 void
4321free_locales()
4322{
4323 int i;
4324 if (locales != NULL)
4325 {
4326 for (i = 0; locales[i] != NULL; i++)
4327 vim_free(locales[i]);
4328 vim_free(locales);
4329 locales = NULL;
4330 }
4331}
4332# endif
4333
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334/*
4335 * Function given to ExpandGeneric() to obtain the possible arguments of the
4336 * ":language" command.
4337 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004338 char_u *
4339get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004340 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341 int idx;
4342{
4343 if (idx == 0)
4344 return (char_u *)"messages";
4345 if (idx == 1)
4346 return (char_u *)"ctype";
4347 if (idx == 2)
4348 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004349
4350 init_locales();
4351 if (locales == NULL)
4352 return NULL;
4353 return locales[idx - 3];
4354}
4355
4356/*
4357 * Function given to ExpandGeneric() to obtain the available locales.
4358 */
4359 char_u *
4360get_locales(xp, idx)
4361 expand_T *xp UNUSED;
4362 int idx;
4363{
4364 init_locales();
4365 if (locales == NULL)
4366 return NULL;
4367 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004368}
4369# endif
4370
4371#endif