blob: 05baa7e99eb5cd8d871d18ec2a6be42f48ca1040 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
17static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
18
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
71
72/*
73 * do_debug(): Debug mode.
74 * Repeatedly get Ex commands, until told to continue normal execution.
75 */
76 void
77do_debug(cmd)
78 char_u *cmd;
79{
80 int save_msg_scroll = msg_scroll;
81 int save_State = State;
82 int save_did_emsg = did_emsg;
83 int save_cmd_silent = cmd_silent;
84 int save_msg_silent = msg_silent;
85 int save_emsg_silent = emsg_silent;
86 int save_redir_off = redir_off;
87 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000088 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000089 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000090# ifdef FEAT_EX_EXTRA
91 int save_ex_normal_busy;
92# endif
93 int n;
94 char_u *cmdline = NULL;
95 char_u *p;
96 char *tail = NULL;
97 static int last_cmd = 0;
98#define CMD_CONT 1
99#define CMD_NEXT 2
100#define CMD_STEP 3
101#define CMD_FINISH 4
102#define CMD_QUIT 5
103#define CMD_INTERRUPT 6
104
105#ifdef ALWAYS_USE_GUI
106 /* Can't do this when there is no terminal for input/output. */
107 if (!gui.in_use)
108 {
109 /* Break as soon as possible. */
110 debug_break_level = 9999;
111 return;
112 }
113#endif
114
115 /* Make sure we are in raw mode and start termcap mode. Might have side
116 * effects... */
117 settmode(TMODE_RAW);
118 starttermcap();
119
120 ++RedrawingDisabled; /* don't redisplay the window */
121 ++no_wait_return; /* don't wait for return */
122 did_emsg = FALSE; /* don't use error from debugged stuff */
123 cmd_silent = FALSE; /* display commands */
124 msg_silent = FALSE; /* display messages */
125 emsg_silent = FALSE; /* display error messages */
126 redir_off = TRUE; /* don't redirect debug commands */
127
128 State = NORMAL;
129#ifdef FEAT_SNIFF
130 want_sniff_request = 0; /* No K_SNIFF wanted */
131#endif
132
133 if (!debug_did_msg)
134 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
135 if (sourcing_name != NULL)
136 msg(sourcing_name);
137 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000138 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141
142 /*
143 * Repeat getting a command and executing it.
144 */
145 for (;;)
146 {
147 msg_scroll = TRUE;
148 need_wait_return = FALSE;
149#ifdef FEAT_SNIFF
150 ProcessSniffRequests();
151#endif
152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157# ifdef FEAT_EX_EXTRA
158 save_ex_normal_busy = ex_normal_busy;
159 ex_normal_busy = 0;
160# endif
161 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000164 typeahead_saved = TRUE;
165 save_ignore_script = ignore_script;
166 ignore_script = TRUE;
167 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000169 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000171 if (typeahead_saved)
172 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000174 ignore_script = save_ignore_script;
175 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176# ifdef FEAT_EX_EXTRA
177 ex_normal_busy = save_ex_normal_busy;
178# endif
179
180 cmdline_row = msg_row;
181 if (cmdline != NULL)
182 {
183 /* If this is a debug command, set "last_cmd".
184 * If not, reset "last_cmd".
185 * For a blank line use previous command. */
186 p = skipwhite(cmdline);
187 if (*p != NUL)
188 {
189 switch (*p)
190 {
191 case 'c': last_cmd = CMD_CONT;
192 tail = "ont";
193 break;
194 case 'n': last_cmd = CMD_NEXT;
195 tail = "ext";
196 break;
197 case 's': last_cmd = CMD_STEP;
198 tail = "tep";
199 break;
200 case 'f': last_cmd = CMD_FINISH;
201 tail = "inish";
202 break;
203 case 'q': last_cmd = CMD_QUIT;
204 tail = "uit";
205 break;
206 case 'i': last_cmd = CMD_INTERRUPT;
207 tail = "nterrupt";
208 break;
209 default: last_cmd = 0;
210 }
211 if (last_cmd != 0)
212 {
213 /* Check that the tail matches. */
214 ++p;
215 while (*p != NUL && *p == *tail)
216 {
217 ++p;
218 ++tail;
219 }
220 if (ASCII_ISALPHA(*p))
221 last_cmd = 0;
222 }
223 }
224
225 if (last_cmd != 0)
226 {
227 /* Execute debug command: decided where to break next and
228 * return. */
229 switch (last_cmd)
230 {
231 case CMD_CONT:
232 debug_break_level = -1;
233 break;
234 case CMD_NEXT:
235 debug_break_level = ex_nesting_level;
236 break;
237 case CMD_STEP:
238 debug_break_level = 9999;
239 break;
240 case CMD_FINISH:
241 debug_break_level = ex_nesting_level - 1;
242 break;
243 case CMD_QUIT:
244 got_int = TRUE;
245 debug_break_level = -1;
246 break;
247 case CMD_INTERRUPT:
248 got_int = TRUE;
249 debug_break_level = 9999;
250 /* Do not repeat ">interrupt" cmd, continue stepping. */
251 last_cmd = CMD_STEP;
252 break;
253 }
254 break;
255 }
256
257 /* don't debug this command */
258 n = debug_break_level;
259 debug_break_level = -1;
260 (void)do_cmdline(cmdline, getexline, NULL,
261 DOCMD_VERBOSE|DOCMD_EXCRESET);
262 debug_break_level = n;
263
264 vim_free(cmdline);
265 }
266 lines_left = Rows - 1;
267 }
268 vim_free(cmdline);
269
270 --RedrawingDisabled;
271 --no_wait_return;
272 redraw_all_later(NOT_VALID);
273 need_wait_return = FALSE;
274 msg_scroll = save_msg_scroll;
275 lines_left = Rows - 1;
276 State = save_State;
277 did_emsg = save_did_emsg;
278 cmd_silent = save_cmd_silent;
279 msg_silent = save_msg_silent;
280 emsg_silent = save_emsg_silent;
281 redir_off = save_redir_off;
282
283 /* Only print the message again when typing a command before coming back
284 * here. */
285 debug_did_msg = TRUE;
286}
287
288/*
289 * ":debug".
290 */
291 void
292ex_debug(eap)
293 exarg_T *eap;
294{
295 int debug_break_level_save = debug_break_level;
296
297 debug_break_level = 9999;
298 do_cmdline_cmd(eap->arg);
299 debug_break_level = debug_break_level_save;
300}
301
302static char_u *debug_breakpoint_name = NULL;
303static linenr_T debug_breakpoint_lnum;
304
305/*
306 * When debugging or a breakpoint is set on a skipped command, no debug prompt
307 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
308 * debug_skipped_name is then set to the source name in the breakpoint case. If
309 * a skipped command decides itself that a debug prompt should be displayed, it
310 * can do so by calling dbg_check_skipped().
311 */
312static int debug_skipped;
313static char_u *debug_skipped_name;
314
315/*
316 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
317 * at or below the break level. But only when the line is actually
318 * executed. Return TRUE and set breakpoint_name for skipped commands that
319 * decide to execute something themselves.
320 * Called from do_one_cmd() before executing a command.
321 */
322 void
323dbg_check_breakpoint(eap)
324 exarg_T *eap;
325{
326 char_u *p;
327
328 debug_skipped = FALSE;
329 if (debug_breakpoint_name != NULL)
330 {
331 if (!eap->skip)
332 {
333 /* replace K_SNR with "<SNR>" */
334 if (debug_breakpoint_name[0] == K_SPECIAL
335 && debug_breakpoint_name[1] == KS_EXTRA
336 && debug_breakpoint_name[2] == (int)KE_SNR)
337 p = (char_u *)"<SNR>";
338 else
339 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000340 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
341 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 debug_breakpoint_name + (*p == NUL ? 0 : 3),
343 (long)debug_breakpoint_lnum);
344 debug_breakpoint_name = NULL;
345 do_debug(eap->cmd);
346 }
347 else
348 {
349 debug_skipped = TRUE;
350 debug_skipped_name = debug_breakpoint_name;
351 debug_breakpoint_name = NULL;
352 }
353 }
354 else if (ex_nesting_level <= debug_break_level)
355 {
356 if (!eap->skip)
357 do_debug(eap->cmd);
358 else
359 {
360 debug_skipped = TRUE;
361 debug_skipped_name = NULL;
362 }
363 }
364}
365
366/*
367 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
368 * set. Return TRUE when the debug mode is entered this time.
369 */
370 int
371dbg_check_skipped(eap)
372 exarg_T *eap;
373{
374 int prev_got_int;
375
376 if (debug_skipped)
377 {
378 /*
379 * Save the value of got_int and reset it. We don't want a previous
380 * interruption cause flushing the input buffer.
381 */
382 prev_got_int = got_int;
383 got_int = FALSE;
384 debug_breakpoint_name = debug_skipped_name;
385 /* eap->skip is TRUE */
386 eap->skip = FALSE;
387 (void)dbg_check_breakpoint(eap);
388 eap->skip = TRUE;
389 got_int |= prev_got_int;
390 return TRUE;
391 }
392 return FALSE;
393}
394
395/*
396 * The list of breakpoints: dbg_breakp.
397 * This is a grow-array of structs.
398 */
399struct debuggy
400{
401 int dbg_nr; /* breakpoint number */
402 int dbg_type; /* DBG_FUNC or DBG_FILE */
403 char_u *dbg_name; /* function or file name */
404 regprog_T *dbg_prog; /* regexp program */
405 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000406 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407};
408
409static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000410#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
411#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412static int last_breakp = 0; /* nr of last defined breakpoint */
413
Bram Moolenaar05159a02005-02-26 23:04:13 +0000414#ifdef FEAT_PROFILE
415/* Profiling uses file and func names similar to breakpoints. */
416static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
417#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418#define DBG_FUNC 1
419#define DBG_FILE 2
420
Bram Moolenaar05159a02005-02-26 23:04:13 +0000421static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
422static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, garray_T *gap, int *fp));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423
424/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000425 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
426 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
427 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428 * Returns FAIL for failure.
429 */
430 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000431dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000433 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000434{
435 char_u *p = arg;
436 char_u *q;
437 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000438 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439
Bram Moolenaar05159a02005-02-26 23:04:13 +0000440 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000442 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443
444 /* Find "func" or "file". */
445 if (STRNCMP(p, "func", 4) == 0)
446 bp->dbg_type = DBG_FUNC;
447 else if (STRNCMP(p, "file", 4) == 0)
448 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000449 else if (
450#ifdef FEAT_PROFILE
451 gap != &prof_ga &&
452#endif
453 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000454 {
455 if (curbuf->b_ffname == NULL)
456 {
457 EMSG(_(e_noname));
458 return FAIL;
459 }
460 bp->dbg_type = DBG_FILE;
461 here = TRUE;
462 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463 else
464 {
465 EMSG2(_(e_invarg2), p);
466 return FAIL;
467 }
468 p = skipwhite(p + 4);
469
470 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000471 if (here)
472 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000473 else if (
474#ifdef FEAT_PROFILE
475 gap != &prof_ga &&
476#endif
477 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000478 {
479 bp->dbg_lnum = getdigits(&p);
480 p = skipwhite(p);
481 }
482 else
483 bp->dbg_lnum = 0;
484
485 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000486 if ((!here && *p == NUL)
487 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
489 {
490 EMSG2(_(e_invarg2), arg);
491 return FAIL;
492 }
493
494 if (bp->dbg_type == DBG_FUNC)
495 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000496 else if (here)
497 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 else
499 {
500 /* Expand the file name in the same way as do_source(). This means
501 * doing it twice, so that $DIR/file gets expanded when $DIR is
502 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 if (q == NULL)
505 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507 vim_free(q);
508 if (p == NULL)
509 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000510 if (*p != '*')
511 {
512 bp->dbg_name = fix_fname(p);
513 vim_free(p);
514 }
515 else
516 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517 }
518
519 if (bp->dbg_name == NULL)
520 return FAIL;
521 return OK;
522}
523
524/*
525 * ":breakadd".
526 */
527 void
528ex_breakadd(eap)
529 exarg_T *eap;
530{
531 struct debuggy *bp;
532 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534
Bram Moolenaar05159a02005-02-26 23:04:13 +0000535 gap = &dbg_breakp;
536#ifdef FEAT_PROFILE
537 if (eap->cmdidx == CMD_profile)
538 gap = &prof_ga;
539#endif
540
541 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000543 bp = &DEBUGGY(gap, gap->ga_len);
544 bp->dbg_forceit = eap->forceit;
545
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
547 if (pat != NULL)
548 {
549 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
550 vim_free(pat);
551 }
552 if (pat == NULL || bp->dbg_prog == NULL)
553 vim_free(bp->dbg_name);
554 else
555 {
556 if (bp->dbg_lnum == 0) /* default line number is 1 */
557 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000558#ifdef FEAT_PROFILE
559 if (eap->cmdidx != CMD_profile)
560#endif
561 {
562 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
563 ++debug_tick;
564 }
565 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 }
567 }
568}
569
570/*
571 * ":debuggreedy".
572 */
573 void
574ex_debuggreedy(eap)
575 exarg_T *eap;
576{
577 if (eap->addr_count == 0 || eap->line2 != 0)
578 debug_greedy = TRUE;
579 else
580 debug_greedy = FALSE;
581}
582
583/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000584 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585 */
586 void
587ex_breakdel(eap)
588 exarg_T *eap;
589{
590 struct debuggy *bp, *bpi;
591 int nr;
592 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000593 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 int i;
595 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000596 garray_T *gap;
597
598 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000599 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200600 {
601#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000602 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200603#else
604 ex_ni(eap);
605 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000606#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200607 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608
609 if (vim_isdigit(*eap->arg))
610 {
611 /* ":breakdel {nr}" */
612 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000613 for (i = 0; i < gap->ga_len; ++i)
614 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 {
616 todel = i;
617 break;
618 }
619 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000620 else if (*eap->arg == '*')
621 {
622 todel = 0;
623 del_all = TRUE;
624 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 else
626 {
627 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000628 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000630 bp = &DEBUGGY(gap, gap->ga_len);
631 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000633 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 if (bp->dbg_type == bpi->dbg_type
635 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
636 && (bp->dbg_lnum == bpi->dbg_lnum
637 || (bp->dbg_lnum == 0
638 && (best_lnum == 0
639 || bpi->dbg_lnum < best_lnum))))
640 {
641 todel = i;
642 best_lnum = bpi->dbg_lnum;
643 }
644 }
645 vim_free(bp->dbg_name);
646 }
647
648 if (todel < 0)
649 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
650 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000651 {
652 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000653 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000654 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200655 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000656 --gap->ga_len;
657 if (todel < gap->ga_len)
658 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
659 (gap->ga_len - todel) * sizeof(struct debuggy));
660#ifdef FEAT_PROFILE
661 if (eap->cmdidx == CMD_breakdel)
662#endif
663 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000664 if (!del_all)
665 break;
666 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000667
668 /* If all breakpoints were removed clear the array. */
669 if (gap->ga_len == 0)
670 ga_clear(gap);
671 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672}
673
674/*
675 * ":breaklist".
676 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677 void
678ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000679 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680{
681 struct debuggy *bp;
682 int i;
683
684 if (dbg_breakp.ga_len == 0)
685 MSG(_("No breakpoints defined"));
686 else
687 for (i = 0; i < dbg_breakp.ga_len; ++i)
688 {
689 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200690 if (bp->dbg_type == DBG_FILE)
691 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 smsg((char_u *)_("%3d %s %s line %ld"),
693 bp->dbg_nr,
694 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200695 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 (long)bp->dbg_lnum);
697 }
698}
699
700/*
701 * Find a breakpoint for a function or sourced file.
702 * Returns line number at which to break; zero when no matching breakpoint.
703 */
704 linenr_T
705dbg_find_breakpoint(file, fname, after)
706 int file; /* TRUE for a file, FALSE for a function */
707 char_u *fname; /* file or function name */
708 linenr_T after; /* after this line number */
709{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000710 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
711}
712
713#if defined(FEAT_PROFILE) || defined(PROTO)
714/*
715 * Return TRUE if profiling is on for a function or sourced file.
716 */
717 int
718has_profiling(file, fname, fp)
719 int file; /* TRUE for a file, FALSE for a function */
720 char_u *fname; /* file or function name */
721 int *fp; /* return: forceit */
722{
723 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
724 != (linenr_T)0);
725}
726#endif
727
728/*
729 * Common code for dbg_find_breakpoint() and has_profiling().
730 */
731 static linenr_T
732debuggy_find(file, fname, after, gap, fp)
733 int file; /* TRUE for a file, FALSE for a function */
734 char_u *fname; /* file or function name */
735 linenr_T after; /* after this line number */
736 garray_T *gap; /* either &dbg_breakp or &prof_ga */
737 int *fp; /* if not NULL: return forceit */
738{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 struct debuggy *bp;
740 int i;
741 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742 char_u *name = fname;
743 int prev_got_int;
744
Bram Moolenaar05159a02005-02-26 23:04:13 +0000745 /* Return quickly when there are no breakpoints. */
746 if (gap->ga_len == 0)
747 return (linenr_T)0;
748
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 /* Replace K_SNR in function name with "<SNR>". */
750 if (!file && fname[0] == K_SPECIAL)
751 {
752 name = alloc((unsigned)STRLEN(fname) + 3);
753 if (name == NULL)
754 name = fname;
755 else
756 {
757 STRCPY(name, "<SNR>");
758 STRCPY(name + 5, fname + 3);
759 }
760 }
761
Bram Moolenaar05159a02005-02-26 23:04:13 +0000762 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000764 /* Skip entries that are not useful or are for a line that is beyond
765 * an already found breakpoint. */
766 bp = &DEBUGGY(gap, i);
767 if (((bp->dbg_type == DBG_FILE) == file && (
768#ifdef FEAT_PROFILE
769 gap == &prof_ga ||
770#endif
771 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000772 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000774 * Save the value of got_int and reset it. We don't want a
775 * previous interruption cancel matching, only hitting CTRL-C
776 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777 */
778 prev_got_int = got_int;
779 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100780 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000781 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000783 if (fp != NULL)
784 *fp = bp->dbg_forceit;
785 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786 got_int |= prev_got_int;
787 }
788 }
789 if (name != fname)
790 vim_free(name);
791
792 return lnum;
793}
794
795/*
796 * Called when a breakpoint was encountered.
797 */
798 void
799dbg_breakpoint(name, lnum)
800 char_u *name;
801 linenr_T lnum;
802{
803 /* We need to check if this line is actually executed in do_one_cmd() */
804 debug_breakpoint_name = name;
805 debug_breakpoint_lnum = lnum;
806}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000807
808
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000809# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000810/*
811 * Store the current time in "tm".
812 */
813 void
814profile_start(tm)
815 proftime_T *tm;
816{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000817# ifdef WIN3264
818 QueryPerformanceCounter(tm);
819# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000820 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000821# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000822}
823
824/*
825 * Compute the elapsed time from "tm" till now and store in "tm".
826 */
827 void
828profile_end(tm)
829 proftime_T *tm;
830{
831 proftime_T now;
832
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000833# ifdef WIN3264
834 QueryPerformanceCounter(&now);
835 tm->QuadPart = now.QuadPart - tm->QuadPart;
836# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000837 gettimeofday(&now, NULL);
838 tm->tv_usec = now.tv_usec - tm->tv_usec;
839 tm->tv_sec = now.tv_sec - tm->tv_sec;
840 if (tm->tv_usec < 0)
841 {
842 tm->tv_usec += 1000000;
843 --tm->tv_sec;
844 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000845# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000846}
847
848/*
849 * Subtract the time "tm2" from "tm".
850 */
851 void
852profile_sub(tm, tm2)
853 proftime_T *tm, *tm2;
854{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000855# ifdef WIN3264
856 tm->QuadPart -= tm2->QuadPart;
857# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000858 tm->tv_usec -= tm2->tv_usec;
859 tm->tv_sec -= tm2->tv_sec;
860 if (tm->tv_usec < 0)
861 {
862 tm->tv_usec += 1000000;
863 --tm->tv_sec;
864 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000865# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000866}
867
868/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000869 * Return a string that represents the time in "tm".
870 * Uses a static buffer!
871 */
872 char *
873profile_msg(tm)
874 proftime_T *tm;
875{
876 static char buf[50];
877
878# ifdef WIN3264
879 LARGE_INTEGER fr;
880
881 QueryPerformanceFrequency(&fr);
882 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
883# else
884 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000885# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000886 return buf;
887}
888
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000889/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000890 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000891 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000892 void
893profile_setlimit(msec, tm)
894 long msec;
895 proftime_T *tm;
896{
897 if (msec <= 0) /* no limit */
898 profile_zero(tm);
899 else
900 {
901# ifdef WIN3264
902 LARGE_INTEGER fr;
903
904 QueryPerformanceCounter(tm);
905 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000906 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000907# else
908 long usec;
909
910 gettimeofday(tm, NULL);
911 usec = (long)tm->tv_usec + (long)msec * 1000;
912 tm->tv_usec = usec % 1000000L;
913 tm->tv_sec += usec / 1000000L;
914# endif
915 }
916}
917
918/*
919 * Return TRUE if the current time is past "tm".
920 */
921 int
922profile_passed_limit(tm)
923 proftime_T *tm;
924{
925 proftime_T now;
926
927# ifdef WIN3264
928 if (tm->QuadPart == 0) /* timer was not set */
929 return FALSE;
930 QueryPerformanceCounter(&now);
931 return (now.QuadPart > tm->QuadPart);
932# else
933 if (tm->tv_sec == 0) /* timer was not set */
934 return FALSE;
935 gettimeofday(&now, NULL);
936 return (now.tv_sec > tm->tv_sec
937 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
938# endif
939}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000940
941/*
942 * Set the time in "tm" to zero.
943 */
944 void
945profile_zero(tm)
946 proftime_T *tm;
947{
948# ifdef WIN3264
949 tm->QuadPart = 0;
950# else
951 tm->tv_usec = 0;
952 tm->tv_sec = 0;
953# endif
954}
955
Bram Moolenaar76929292008-01-06 19:07:36 +0000956# endif /* FEAT_PROFILE || FEAT_RELTIME */
957
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200958#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
959# if defined(HAVE_MATH_H)
960# include <math.h>
961# endif
962
963/*
964 * Divide the time "tm" by "count" and store in "tm2".
965 */
966 void
967profile_divide(tm, count, tm2)
968 proftime_T *tm;
969 proftime_T *tm2;
970 int count;
971{
972 if (count == 0)
973 profile_zero(tm2);
974 else
975 {
976# ifdef WIN3264
977 tm2->QuadPart = tm->QuadPart / count;
978# else
979 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
980
981 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +0200982 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200983# endif
984 }
985}
986#endif
987
Bram Moolenaar76929292008-01-06 19:07:36 +0000988# if defined(FEAT_PROFILE) || defined(PROTO)
989/*
990 * Functions for profiling.
991 */
992static void script_do_profile __ARGS((scriptitem_T *si));
993static void script_dump_profile __ARGS((FILE *fd));
994static proftime_T prof_wait_time;
995
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000996/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000997 * Add the time "tm2" to "tm".
998 */
999 void
1000profile_add(tm, tm2)
1001 proftime_T *tm, *tm2;
1002{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001003# ifdef WIN3264
1004 tm->QuadPart += tm2->QuadPart;
1005# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001006 tm->tv_usec += tm2->tv_usec;
1007 tm->tv_sec += tm2->tv_sec;
1008 if (tm->tv_usec >= 1000000)
1009 {
1010 tm->tv_usec -= 1000000;
1011 ++tm->tv_sec;
1012 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001013# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001014}
1015
1016/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001017 * Add the "self" time from the total time and the children's time.
1018 */
1019 void
1020profile_self(self, total, children)
1021 proftime_T *self, *total, *children;
1022{
1023 /* Check that the result won't be negative. Can happen with recursive
1024 * calls. */
1025#ifdef WIN3264
1026 if (total->QuadPart <= children->QuadPart)
1027 return;
1028#else
1029 if (total->tv_sec < children->tv_sec
1030 || (total->tv_sec == children->tv_sec
1031 && total->tv_usec <= children->tv_usec))
1032 return;
1033#endif
1034 profile_add(self, total);
1035 profile_sub(self, children);
1036}
1037
1038/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001039 * Get the current waittime.
1040 */
1041 void
1042profile_get_wait(tm)
1043 proftime_T *tm;
1044{
1045 *tm = prof_wait_time;
1046}
1047
1048/*
1049 * Subtract the passed waittime since "tm" from "tma".
1050 */
1051 void
1052profile_sub_wait(tm, tma)
1053 proftime_T *tm, *tma;
1054{
1055 proftime_T tm3 = prof_wait_time;
1056
1057 profile_sub(&tm3, tm);
1058 profile_sub(tma, &tm3);
1059}
1060
1061/*
1062 * Return TRUE if "tm1" and "tm2" are equal.
1063 */
1064 int
1065profile_equal(tm1, tm2)
1066 proftime_T *tm1, *tm2;
1067{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001068# ifdef WIN3264
1069 return (tm1->QuadPart == tm2->QuadPart);
1070# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001071 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001072# endif
1073}
1074
1075/*
1076 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1077 */
1078 int
1079profile_cmp(tm1, tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001080 const proftime_T *tm1, *tm2;
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001081{
1082# ifdef WIN3264
1083 return (int)(tm2->QuadPart - tm1->QuadPart);
1084# else
1085 if (tm1->tv_sec == tm2->tv_sec)
1086 return tm2->tv_usec - tm1->tv_usec;
1087 return tm2->tv_sec - tm1->tv_sec;
1088# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001089}
1090
Bram Moolenaar05159a02005-02-26 23:04:13 +00001091static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001092static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001093
1094/*
1095 * ":profile cmd args"
1096 */
1097 void
1098ex_profile(eap)
1099 exarg_T *eap;
1100{
1101 char_u *e;
1102 int len;
1103
1104 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001105 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001106 e = skipwhite(e);
1107
1108 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1109 {
1110 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001111 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001112 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001113 profile_zero(&prof_wait_time);
1114 set_vim_var_nr(VV_PROFILING, 1L);
1115 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001116 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001117 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001118 else if (STRCMP(eap->arg, "pause") == 0)
1119 {
1120 if (do_profiling == PROF_YES)
1121 profile_start(&pause_time);
1122 do_profiling = PROF_PAUSED;
1123 }
1124 else if (STRCMP(eap->arg, "continue") == 0)
1125 {
1126 if (do_profiling == PROF_PAUSED)
1127 {
1128 profile_end(&pause_time);
1129 profile_add(&prof_wait_time, &pause_time);
1130 }
1131 do_profiling = PROF_YES;
1132 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001133 else
1134 {
1135 /* The rest is similar to ":breakadd". */
1136 ex_breakadd(eap);
1137 }
1138}
1139
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001140/* Command line expansion for :profile. */
1141static enum
1142{
1143 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001144 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001145} pexpand_what;
1146
1147static char *pexpand_cmds[] = {
1148 "start",
1149#define PROFCMD_START 0
1150 "pause",
1151#define PROFCMD_PAUSE 1
1152 "continue",
1153#define PROFCMD_CONTINUE 2
1154 "func",
1155#define PROFCMD_FUNC 3
1156 "file",
1157#define PROFCMD_FILE 4
1158 NULL
1159#define PROFCMD_LAST 5
1160};
1161
1162/*
1163 * Function given to ExpandGeneric() to obtain the profile command
1164 * specific expansion.
1165 */
1166 char_u *
1167get_profile_name(xp, idx)
1168 expand_T *xp UNUSED;
1169 int idx;
1170{
1171 switch (pexpand_what)
1172 {
1173 case PEXP_SUBCMD:
1174 return (char_u *)pexpand_cmds[idx];
1175 /* case PEXP_FUNC: TODO */
1176 default:
1177 return NULL;
1178 }
1179}
1180
1181/*
1182 * Handle command line completion for :profile command.
1183 */
1184 void
1185set_context_in_profile_cmd(xp, arg)
1186 expand_T *xp;
1187 char_u *arg;
1188{
1189 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001190
1191 /* Default: expand subcommands. */
1192 xp->xp_context = EXPAND_PROFILE;
1193 pexpand_what = PEXP_SUBCMD;
1194 xp->xp_pattern = arg;
1195
1196 end_subcmd = skiptowhite(arg);
1197 if (*end_subcmd == NUL)
1198 return;
1199
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001200 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001201 {
1202 xp->xp_context = EXPAND_FILES;
1203 xp->xp_pattern = skipwhite(end_subcmd);
1204 return;
1205 }
1206
1207 /* TODO: expand function names after "func" */
1208 xp->xp_context = EXPAND_NOTHING;
1209}
1210
Bram Moolenaar05159a02005-02-26 23:04:13 +00001211/*
1212 * Dump the profiling info.
1213 */
1214 void
1215profile_dump()
1216{
1217 FILE *fd;
1218
1219 if (profile_fname != NULL)
1220 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001221 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001222 if (fd == NULL)
1223 EMSG2(_(e_notopen), profile_fname);
1224 else
1225 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001226 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001227 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001228 fclose(fd);
1229 }
1230 }
1231}
1232
1233/*
1234 * Start profiling script "fp".
1235 */
1236 static void
1237script_do_profile(si)
1238 scriptitem_T *si;
1239{
1240 si->sn_pr_count = 0;
1241 profile_zero(&si->sn_pr_total);
1242 profile_zero(&si->sn_pr_self);
1243
1244 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1245 si->sn_prl_idx = -1;
1246 si->sn_prof_on = TRUE;
1247 si->sn_pr_nest = 0;
1248}
1249
1250/*
1251 * save time when starting to invoke another script or function.
1252 */
1253 void
1254script_prof_save(tm)
1255 proftime_T *tm; /* place to store wait time */
1256{
1257 scriptitem_T *si;
1258
1259 if (current_SID > 0 && current_SID <= script_items.ga_len)
1260 {
1261 si = &SCRIPT_ITEM(current_SID);
1262 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1263 profile_start(&si->sn_pr_child);
1264 }
1265 profile_get_wait(tm);
1266}
1267
1268/*
1269 * Count time spent in children after invoking another script or function.
1270 */
1271 void
1272script_prof_restore(tm)
1273 proftime_T *tm;
1274{
1275 scriptitem_T *si;
1276
1277 if (current_SID > 0 && current_SID <= script_items.ga_len)
1278 {
1279 si = &SCRIPT_ITEM(current_SID);
1280 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1281 {
1282 profile_end(&si->sn_pr_child);
1283 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1284 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1285 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1286 }
1287 }
1288}
1289
1290static proftime_T inchar_time;
1291
1292/*
1293 * Called when starting to wait for the user to type a character.
1294 */
1295 void
1296prof_inchar_enter()
1297{
1298 profile_start(&inchar_time);
1299}
1300
1301/*
1302 * Called when finished waiting for the user to type a character.
1303 */
1304 void
1305prof_inchar_exit()
1306{
1307 profile_end(&inchar_time);
1308 profile_add(&prof_wait_time, &inchar_time);
1309}
1310
1311/*
1312 * Dump the profiling results for all scripts in file "fd".
1313 */
1314 static void
1315script_dump_profile(fd)
1316 FILE *fd;
1317{
1318 int id;
1319 scriptitem_T *si;
1320 int i;
1321 FILE *sfd;
1322 sn_prl_T *pp;
1323
1324 for (id = 1; id <= script_items.ga_len; ++id)
1325 {
1326 si = &SCRIPT_ITEM(id);
1327 if (si->sn_prof_on)
1328 {
1329 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1330 if (si->sn_pr_count == 1)
1331 fprintf(fd, "Sourced 1 time\n");
1332 else
1333 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1334 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1335 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1336 fprintf(fd, "\n");
1337 fprintf(fd, "count total (s) self (s)\n");
1338
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001339 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001340 if (sfd == NULL)
1341 fprintf(fd, "Cannot open file!\n");
1342 else
1343 {
1344 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1345 {
1346 if (vim_fgets(IObuff, IOSIZE, sfd))
1347 break;
1348 pp = &PRL_ITEM(si, i);
1349 if (pp->snp_count > 0)
1350 {
1351 fprintf(fd, "%5d ", pp->snp_count);
1352 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1353 fprintf(fd, " ");
1354 else
1355 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1356 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1357 }
1358 else
1359 fprintf(fd, " ");
1360 fprintf(fd, "%s", IObuff);
1361 }
1362 fclose(sfd);
1363 }
1364 fprintf(fd, "\n");
1365 }
1366 }
1367}
1368
1369/*
1370 * Return TRUE when a function defined in the current script should be
1371 * profiled.
1372 */
1373 int
1374prof_def_func()
1375{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001376 if (current_SID > 0)
1377 return SCRIPT_ITEM(current_SID).sn_pr_force;
1378 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001379}
1380
1381# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001382#endif
1383
1384/*
1385 * If 'autowrite' option set, try to write the file.
1386 * Careful: autocommands may make "buf" invalid!
1387 *
1388 * return FAIL for failure, OK otherwise
1389 */
1390 int
1391autowrite(buf, forceit)
1392 buf_T *buf;
1393 int forceit;
1394{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001395 int r;
1396
Bram Moolenaar071d4272004-06-13 20:20:40 +00001397 if (!(p_aw || p_awa) || !p_write
1398#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001399 /* never autowrite a "nofile" or "nowrite" buffer */
1400 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001401#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001402 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001403 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001404 r = buf_write_all(buf, forceit);
1405
1406 /* Writing may succeed but the buffer still changed, e.g., when there is a
1407 * conversion error. We do want to return FAIL then. */
1408 if (buf_valid(buf) && bufIsChanged(buf))
1409 r = FAIL;
1410 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001411}
1412
1413/*
1414 * flush all buffers, except the ones that are readonly
1415 */
1416 void
1417autowrite_all()
1418{
1419 buf_T *buf;
1420
1421 if (!(p_aw || p_awa) || !p_write)
1422 return;
1423 for (buf = firstbuf; buf; buf = buf->b_next)
1424 if (bufIsChanged(buf) && !buf->b_p_ro)
1425 {
1426 (void)buf_write_all(buf, FALSE);
1427#ifdef FEAT_AUTOCMD
1428 /* an autocommand may have deleted the buffer */
1429 if (!buf_valid(buf))
1430 buf = firstbuf;
1431#endif
1432 }
1433}
1434
1435/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001436 * Return TRUE if buffer was changed and cannot be abandoned.
1437 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001438 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001439 int
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001440check_changed(buf, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001441 buf_T *buf;
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001442 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001443{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001444 int forceit = (flags & CCGD_FORCEIT);
1445
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446 if ( !forceit
1447 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001448 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1449 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001450 {
1451#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1452 if ((p_confirm || cmdmod.confirm) && p_write)
1453 {
1454 buf_T *buf2;
1455 int count = 0;
1456
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001457 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001458 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1459 if (bufIsChanged(buf2)
1460 && (buf2->b_ffname != NULL
1461# ifdef FEAT_BROWSE
1462 || cmdmod.browse
1463# endif
1464 ))
1465 ++count;
1466# ifdef FEAT_AUTOCMD
1467 if (!buf_valid(buf))
1468 /* Autocommand deleted buffer, oops! It's not changed now. */
1469 return FALSE;
1470# endif
1471 dialog_changed(buf, count > 1);
1472# ifdef FEAT_AUTOCMD
1473 if (!buf_valid(buf))
1474 /* Autocommand deleted buffer, oops! It's not changed now. */
1475 return FALSE;
1476# endif
1477 return bufIsChanged(buf);
1478 }
1479#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001480 if (flags & CCGD_EXCMD)
1481 EMSG(_(e_nowrtmsg));
1482 else
1483 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001484 return TRUE;
1485 }
1486 return FALSE;
1487}
1488
1489#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1490
1491#if defined(FEAT_BROWSE) || defined(PROTO)
1492/*
1493 * When wanting to write a file without a file name, ask the user for a name.
1494 */
1495 void
1496browse_save_fname(buf)
1497 buf_T *buf;
1498{
1499 if (buf->b_fname == NULL)
1500 {
1501 char_u *fname;
1502
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001503 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1504 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001505 if (fname != NULL)
1506 {
1507 if (setfname(buf, fname, NULL, TRUE) == OK)
1508 buf->b_flags |= BF_NOTEDITED;
1509 vim_free(fname);
1510 }
1511 }
1512}
1513#endif
1514
1515/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001516 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001517 * Must check 'write' option first!
1518 */
1519 void
1520dialog_changed(buf, checkall)
1521 buf_T *buf;
1522 int checkall; /* may abandon all changed buffers */
1523{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001524 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001525 int ret;
1526 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001527 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001528
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001529 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530 (buf->b_fname != NULL) ?
1531 buf->b_fname : (char_u *)_("Untitled"));
1532 if (checkall)
1533 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1534 else
1535 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1536
Bram Moolenaar8218f602012-04-25 17:32:18 +02001537 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1538 * function. */
1539 ea.append = ea.forceit = FALSE;
1540
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541 if (ret == VIM_YES)
1542 {
1543#ifdef FEAT_BROWSE
1544 /* May get file name, when there is none */
1545 browse_save_fname(buf);
1546#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001547 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1548 buf->b_fname, buf->b_ffname, FALSE) == OK)
1549 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550 (void)buf_write_all(buf, FALSE);
1551 }
1552 else if (ret == VIM_NO)
1553 {
1554 unchanged(buf, TRUE);
1555 }
1556 else if (ret == VIM_ALL)
1557 {
1558 /*
1559 * Write all modified files that can be written.
1560 * Skip readonly buffers, these need to be confirmed
1561 * individually.
1562 */
1563 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1564 {
1565 if (bufIsChanged(buf2)
1566 && (buf2->b_ffname != NULL
1567#ifdef FEAT_BROWSE
1568 || cmdmod.browse
1569#endif
1570 )
1571 && !buf2->b_p_ro)
1572 {
1573#ifdef FEAT_BROWSE
1574 /* May get file name, when there is none */
1575 browse_save_fname(buf2);
1576#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001577 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1578 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1579 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001580 (void)buf_write_all(buf2, FALSE);
1581#ifdef FEAT_AUTOCMD
1582 /* an autocommand may have deleted the buffer */
1583 if (!buf_valid(buf2))
1584 buf2 = firstbuf;
1585#endif
1586 }
1587 }
1588 }
1589 else if (ret == VIM_DISCARDALL)
1590 {
1591 /*
1592 * mark all buffers as unchanged
1593 */
1594 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1595 unchanged(buf2, TRUE);
1596 }
1597}
1598#endif
1599
1600/*
1601 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1602 * hidden, autowriting it or unloading it.
1603 */
1604 int
1605can_abandon(buf, forceit)
1606 buf_T *buf;
1607 int forceit;
1608{
1609 return ( P_HID(buf)
1610 || !bufIsChanged(buf)
1611 || buf->b_nwindows > 1
1612 || autowrite(buf, forceit) == OK
1613 || forceit);
1614}
1615
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001616static void add_bufnum __ARGS((int *bufnrs, int *bufnump, int nr));
1617
1618/*
1619 * Add a buffer number to "bufnrs", unless it's already there.
1620 */
1621 static void
1622add_bufnum(bufnrs, bufnump, nr)
1623 int *bufnrs;
1624 int *bufnump;
1625 int nr;
1626{
1627 int i;
1628
1629 for (i = 0; i < *bufnump; ++i)
1630 if (bufnrs[i] == nr)
1631 return;
1632 bufnrs[*bufnump] = nr;
1633 *bufnump = *bufnump + 1;
1634}
1635
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636/*
1637 * Return TRUE if any buffer was changed and cannot be abandoned.
1638 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001639 * When "unload" is true the current buffer is unloaded instead of making it
1640 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001641 */
1642 int
Bram Moolenaar027387f2016-01-02 22:25:52 +01001643check_changed_any(hidden, unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001644 int hidden; /* Only check hidden buffers */
Bram Moolenaar027387f2016-01-02 22:25:52 +01001645 int unload;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001646{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001647 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648 buf_T *buf;
1649 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001650 int i;
1651 int bufnum = 0;
1652 int bufcount = 0;
1653 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001655 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001656 win_T *wp;
1657#endif
1658
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001659 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1660 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001662 if (bufcount == 0)
1663 return FALSE;
1664
1665 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1666 if (bufnrs == NULL)
1667 return FALSE;
1668
1669 /* curbuf */
1670 bufnrs[bufnum++] = curbuf->b_fnum;
1671#ifdef FEAT_WINDOWS
1672 /* buf in curtab */
1673 FOR_ALL_WINDOWS(wp)
1674 if (wp->w_buffer != curbuf)
1675 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1676
1677 /* buf in other tab */
1678 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1679 if (tp != curtab)
1680 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1681 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1682#endif
1683 /* any other buf */
1684 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1685 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1686
1687 for (i = 0; i < bufnum; ++i)
1688 {
1689 buf = buflist_findnr(bufnrs[i]);
1690 if (buf == NULL)
1691 continue;
1692 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1693 {
1694 /* Try auto-writing the buffer. If this fails but the buffer no
1695 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001696 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1697 | CCGD_MULTWIN
1698 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001699 break; /* didn't save - still changes */
1700 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001701 }
1702
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001703 if (i >= bufnum)
1704 goto theend;
1705
1706 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001707 exiting = FALSE;
1708#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1709 /*
1710 * When ":confirm" used, don't give an error message.
1711 */
1712 if (!(p_confirm || cmdmod.confirm))
1713#endif
1714 {
1715 /* There must be a wait_return for this message, do_buffer()
1716 * may cause a redraw. But wait_return() is a no-op when vgetc()
1717 * is busy (Quit used from window menu), then make sure we don't
1718 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001719 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720 {
1721 msg_row = cmdline_row;
1722 msg_col = 0;
1723 msg_didout = FALSE;
1724 }
1725 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001726 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001727 {
1728 save = no_wait_return;
1729 no_wait_return = FALSE;
1730 wait_return(FALSE);
1731 no_wait_return = save;
1732 }
1733 }
1734
1735#ifdef FEAT_WINDOWS
1736 /* Try to find a window that contains the buffer. */
1737 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001738 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739 if (wp->w_buffer == buf)
1740 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001741 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742# ifdef FEAT_AUTOCMD
1743 /* Paranoia: did autocms wipe out the buffer with changes? */
1744 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001745 {
1746 goto theend;
1747 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001749 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001751buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752#endif
1753
1754 /* Open the changed buffer in the current window. */
1755 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001756 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001758theend:
1759 vim_free(bufnrs);
1760 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761}
1762
1763/*
1764 * return FAIL if there is no file name, OK if there is one
1765 * give error message for FAIL
1766 */
1767 int
1768check_fname()
1769{
1770 if (curbuf->b_ffname == NULL)
1771 {
1772 EMSG(_(e_noname));
1773 return FAIL;
1774 }
1775 return OK;
1776}
1777
1778/*
1779 * flush the contents of a buffer, unless it has no file name
1780 *
1781 * return FAIL for failure, OK otherwise
1782 */
1783 int
1784buf_write_all(buf, forceit)
1785 buf_T *buf;
1786 int forceit;
1787{
1788 int retval;
1789#ifdef FEAT_AUTOCMD
1790 buf_T *old_curbuf = curbuf;
1791#endif
1792
1793 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1794 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1795 FALSE, forceit, TRUE, FALSE));
1796#ifdef FEAT_AUTOCMD
1797 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001798 {
1799 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001801 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802#endif
1803 return retval;
1804}
1805
1806/*
1807 * Code to handle the argument list.
1808 */
1809
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001810static char_u *do_one_arg __ARGS((char_u *str));
1811static int do_arglist __ARGS((char_u *str, int what, int after));
1812static void alist_check_arg_idx __ARGS((void));
1813static int editing_arg_idx __ARGS((win_T *win));
1814#ifdef FEAT_LISTCMDS
1815static int alist_add_list __ARGS((int count, char_u **files, int after));
1816#endif
1817#define AL_SET 1
1818#define AL_ADD 2
1819#define AL_DEL 3
1820
Bram Moolenaar071d4272004-06-13 20:20:40 +00001821/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001822 * Isolate one argument, taking backticks.
1823 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824 * Return a pointer to the start of the next argument.
1825 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001826 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827do_one_arg(str)
1828 char_u *str;
1829{
1830 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831 int inbacktick;
1832
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833 inbacktick = FALSE;
1834 for (p = str; *str; ++str)
1835 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001836 /* When the backslash is used for escaping the special meaning of a
1837 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 if (rem_backslash(str))
1839 {
1840 *p++ = *str++;
1841 *p++ = *str;
1842 }
1843 else
1844 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001845 /* An item ends at a space not in backticks */
1846 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001848 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001850 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851 }
1852 }
1853 str = skipwhite(str);
1854 *p = NUL;
1855
1856 return str;
1857}
1858
Bram Moolenaar86b68352004-12-27 21:59:20 +00001859/*
1860 * Separate the arguments in "str" and return a list of pointers in the
1861 * growarray "gap".
1862 */
1863 int
1864get_arglist(gap, str)
1865 garray_T *gap;
1866 char_u *str;
1867{
1868 ga_init2(gap, (int)sizeof(char_u *), 20);
1869 while (*str != NUL)
1870 {
1871 if (ga_grow(gap, 1) == FAIL)
1872 {
1873 ga_clear(gap);
1874 return FAIL;
1875 }
1876 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1877
1878 /* Isolate one argument, change it in-place, put a NUL after it. */
1879 str = do_one_arg(str);
1880 }
1881 return OK;
1882}
1883
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001884#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001885/*
1886 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001887 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001888 * Return FAIL or OK.
1889 */
1890 int
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001891get_arglist_exp(str, fcountp, fnamesp, wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001892 char_u *str;
1893 int *fcountp;
1894 char_u ***fnamesp;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001895 int wig;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001896{
1897 garray_T ga;
1898 int i;
1899
1900 if (get_arglist(&ga, str) == FAIL)
1901 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001902 if (wig == TRUE)
1903 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1904 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1905 else
1906 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1907 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1908
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001909 ga_clear(&ga);
1910 return i;
1911}
1912#endif
1913
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1915/*
1916 * Redefine the argument list.
1917 */
1918 void
1919set_arglist(str)
1920 char_u *str;
1921{
1922 do_arglist(str, AL_SET, 0);
1923}
1924#endif
1925
1926/*
1927 * "what" == AL_SET: Redefine the argument list to 'str'.
1928 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1929 * "what" == AL_DEL: remove files in 'str' from the argument list.
1930 *
1931 * Return FAIL for failure, OK otherwise.
1932 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 static int
1934do_arglist(str, what, after)
1935 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001936 int what UNUSED;
1937 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938{
1939 garray_T new_ga;
1940 int exp_count;
1941 char_u **exp_files;
1942 int i;
1943#ifdef FEAT_LISTCMDS
1944 char_u *p;
1945 int match;
1946#endif
1947
1948 /*
1949 * Collect all file name arguments in "new_ga".
1950 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001951 if (get_arglist(&new_ga, str) == FAIL)
1952 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953
1954#ifdef FEAT_LISTCMDS
1955 if (what == AL_DEL)
1956 {
1957 regmatch_T regmatch;
1958 int didone;
1959
1960 /*
1961 * Delete the items: use each item as a regexp and find a match in the
1962 * argument list.
1963 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01001964 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1966 {
1967 p = ((char_u **)new_ga.ga_data)[i];
1968 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1969 if (p == NULL)
1970 break;
1971 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1972 if (regmatch.regprog == NULL)
1973 {
1974 vim_free(p);
1975 break;
1976 }
1977
1978 didone = FALSE;
1979 for (match = 0; match < ARGCOUNT; ++match)
1980 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1981 (colnr_T)0))
1982 {
1983 didone = TRUE;
1984 vim_free(ARGLIST[match].ae_fname);
1985 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1986 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1987 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988 if (curwin->w_arg_idx > match)
1989 --curwin->w_arg_idx;
1990 --match;
1991 }
1992
Bram Moolenaar473de612013-06-08 18:19:48 +02001993 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001994 vim_free(p);
1995 if (!didone)
1996 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1997 }
1998 ga_clear(&new_ga);
1999 }
2000 else
2001#endif
2002 {
2003 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2004 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2005 ga_clear(&new_ga);
2006 if (i == FAIL)
2007 return FAIL;
2008 if (exp_count == 0)
2009 {
2010 EMSG(_(e_nomatch));
2011 return FAIL;
2012 }
2013
2014#ifdef FEAT_LISTCMDS
2015 if (what == AL_ADD)
2016 {
2017 (void)alist_add_list(exp_count, exp_files, after);
2018 vim_free(exp_files);
2019 }
2020 else /* what == AL_SET */
2021#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002022 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023 }
2024
2025 alist_check_arg_idx();
2026
2027 return OK;
2028}
2029
2030/*
2031 * Check the validity of the arg_idx for each other window.
2032 */
2033 static void
2034alist_check_arg_idx()
2035{
2036#ifdef FEAT_WINDOWS
2037 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002038 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039
Bram Moolenaarf740b292006-02-16 22:11:02 +00002040 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002041 if (win->w_alist == curwin->w_alist)
2042 check_arg_idx(win);
2043#else
2044 check_arg_idx(curwin);
2045#endif
2046}
2047
2048/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002049 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002050 * index.
2051 */
2052 static int
2053editing_arg_idx(win)
2054 win_T *win;
2055{
2056 return !(win->w_arg_idx >= WARGCOUNT(win)
2057 || (win->w_buffer->b_fnum
2058 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2059 && (win->w_buffer->b_ffname == NULL
2060 || !(fullpathcmp(
2061 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2062 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2063}
2064
2065/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002066 * Check if window "win" is editing the w_arg_idx file in its argument list.
2067 */
2068 void
2069check_arg_idx(win)
2070 win_T *win;
2071{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002072 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073 {
2074 /* We are not editing the current entry in the argument list.
2075 * Set "arg_had_last" if we are editing the last one. */
2076 win->w_arg_idx_invalid = TRUE;
2077 if (win->w_arg_idx != WARGCOUNT(win) - 1
2078 && arg_had_last == FALSE
2079#ifdef FEAT_WINDOWS
2080 && ALIST(win) == &global_alist
2081#endif
2082 && GARGCOUNT > 0
2083 && win->w_arg_idx < GARGCOUNT
2084 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2085 || (win->w_buffer->b_ffname != NULL
2086 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2087 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2088 arg_had_last = TRUE;
2089 }
2090 else
2091 {
2092 /* We are editing the current entry in the argument list.
2093 * Set "arg_had_last" if it's also the last one */
2094 win->w_arg_idx_invalid = FALSE;
2095 if (win->w_arg_idx == WARGCOUNT(win) - 1
2096#ifdef FEAT_WINDOWS
2097 && win->w_alist == &global_alist
2098#endif
2099 )
2100 arg_had_last = TRUE;
2101 }
2102}
2103
2104/*
2105 * ":args", ":argslocal" and ":argsglobal".
2106 */
2107 void
2108ex_args(eap)
2109 exarg_T *eap;
2110{
2111 int i;
2112
2113 if (eap->cmdidx != CMD_args)
2114 {
2115#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2116 alist_unlink(ALIST(curwin));
2117 if (eap->cmdidx == CMD_argglobal)
2118 ALIST(curwin) = &global_alist;
2119 else /* eap->cmdidx == CMD_arglocal */
2120 alist_new();
2121#else
2122 ex_ni(eap);
2123 return;
2124#endif
2125 }
2126
2127 if (!ends_excmd(*eap->arg))
2128 {
2129 /*
2130 * ":args file ..": define new argument list, handle like ":next"
2131 * Also for ":argslocal file .." and ":argsglobal file ..".
2132 */
2133 ex_next(eap);
2134 }
2135 else
2136#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2137 if (eap->cmdidx == CMD_args)
2138#endif
2139 {
2140 /*
2141 * ":args": list arguments.
2142 */
2143 if (ARGCOUNT > 0)
2144 {
2145 /* Overwrite the command, for a short list there is no scrolling
2146 * required and no wait_return(). */
2147 gotocmdline(TRUE);
2148 for (i = 0; i < ARGCOUNT; ++i)
2149 {
2150 if (i == curwin->w_arg_idx)
2151 msg_putchar('[');
2152 msg_outtrans(alist_name(&ARGLIST[i]));
2153 if (i == curwin->w_arg_idx)
2154 msg_putchar(']');
2155 msg_putchar(' ');
2156 }
2157 }
2158 }
2159#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2160 else if (eap->cmdidx == CMD_arglocal)
2161 {
2162 garray_T *gap = &curwin->w_alist->al_ga;
2163
2164 /*
2165 * ":argslocal": make a local copy of the global argument list.
2166 */
2167 if (ga_grow(gap, GARGCOUNT) == OK)
2168 for (i = 0; i < GARGCOUNT; ++i)
2169 if (GARGLIST[i].ae_fname != NULL)
2170 {
2171 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2172 vim_strsave(GARGLIST[i].ae_fname);
2173 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2174 GARGLIST[i].ae_fnum;
2175 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002176 }
2177 }
2178#endif
2179}
2180
2181/*
2182 * ":previous", ":sprevious", ":Next" and ":sNext".
2183 */
2184 void
2185ex_previous(eap)
2186 exarg_T *eap;
2187{
2188 /* If past the last one already, go to the last one. */
2189 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2190 do_argfile(eap, ARGCOUNT - 1);
2191 else
2192 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2193}
2194
2195/*
2196 * ":rewind", ":first", ":sfirst" and ":srewind".
2197 */
2198 void
2199ex_rewind(eap)
2200 exarg_T *eap;
2201{
2202 do_argfile(eap, 0);
2203}
2204
2205/*
2206 * ":last" and ":slast".
2207 */
2208 void
2209ex_last(eap)
2210 exarg_T *eap;
2211{
2212 do_argfile(eap, ARGCOUNT - 1);
2213}
2214
2215/*
2216 * ":argument" and ":sargument".
2217 */
2218 void
2219ex_argument(eap)
2220 exarg_T *eap;
2221{
2222 int i;
2223
2224 if (eap->addr_count > 0)
2225 i = eap->line2 - 1;
2226 else
2227 i = curwin->w_arg_idx;
2228 do_argfile(eap, i);
2229}
2230
2231/*
2232 * Edit file "argn" of the argument lists.
2233 */
2234 void
2235do_argfile(eap, argn)
2236 exarg_T *eap;
2237 int argn;
2238{
2239 int other;
2240 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002241 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002242
2243 if (argn < 0 || argn >= ARGCOUNT)
2244 {
2245 if (ARGCOUNT <= 1)
2246 EMSG(_("E163: There is only one file to edit"));
2247 else if (argn < 0)
2248 EMSG(_("E164: Cannot go before first file"));
2249 else
2250 EMSG(_("E165: Cannot go beyond last file"));
2251 }
2252 else
2253 {
2254 setpcmark();
2255#ifdef FEAT_GUI
2256 need_mouse_correct = TRUE;
2257#endif
2258
2259#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002260 /* split window or create new tab page first */
2261 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262 {
2263 if (win_split(0, 0) == FAIL)
2264 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002265 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 }
2267 else
2268#endif
2269 {
2270 /*
2271 * if 'hidden' set, only check for changed file when re-editing
2272 * the same buffer
2273 */
2274 other = TRUE;
2275 if (P_HID(curbuf))
2276 {
2277 p = fix_fname(alist_name(&ARGLIST[argn]));
2278 other = otherfile(p);
2279 vim_free(p);
2280 }
2281 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002282 && check_changed(curbuf, CCGD_AW
2283 | (other ? 0 : CCGD_MULTWIN)
2284 | (eap->forceit ? CCGD_FORCEIT : 0)
2285 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 return;
2287 }
2288
2289 curwin->w_arg_idx = argn;
2290 if (argn == ARGCOUNT - 1
2291#ifdef FEAT_WINDOWS
2292 && curwin->w_alist == &global_alist
2293#endif
2294 )
2295 arg_had_last = TRUE;
2296
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002297 /* Edit the file; always use the last known line number.
2298 * When it fails (e.g. Abort for already edited file) restore the
2299 * argument index. */
2300 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002302 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2303 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002304 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002306 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307 setmark('\'');
2308 }
2309}
2310
2311/*
2312 * ":next", and commands that behave like it.
2313 */
2314 void
2315ex_next(eap)
2316 exarg_T *eap;
2317{
2318 int i;
2319
2320 /*
2321 * check for changed buffer now, if this fails the argument list is not
2322 * redefined.
2323 */
2324 if ( P_HID(curbuf)
2325 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002326 || !check_changed(curbuf, CCGD_AW
2327 | (eap->forceit ? CCGD_FORCEIT : 0)
2328 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329 {
2330 if (*eap->arg != NUL) /* redefine file list */
2331 {
2332 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2333 return;
2334 i = 0;
2335 }
2336 else
2337 i = curwin->w_arg_idx + (int)eap->line2;
2338 do_argfile(eap, i);
2339 }
2340}
2341
2342#ifdef FEAT_LISTCMDS
2343/*
2344 * ":argedit"
2345 */
2346 void
2347ex_argedit(eap)
2348 exarg_T *eap;
2349{
2350 int fnum;
2351 int i;
2352 char_u *s;
2353
2354 /* Add the argument to the buffer list and get the buffer number. */
2355 fnum = buflist_add(eap->arg, BLN_LISTED);
2356
2357 /* Check if this argument is already in the argument list. */
2358 for (i = 0; i < ARGCOUNT; ++i)
2359 if (ARGLIST[i].ae_fnum == fnum)
2360 break;
2361 if (i == ARGCOUNT)
2362 {
2363 /* Can't find it, add it to the argument list. */
2364 s = vim_strsave(eap->arg);
2365 if (s == NULL)
2366 return;
2367 i = alist_add_list(1, &s,
2368 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2369 if (i < 0)
2370 return;
2371 curwin->w_arg_idx = i;
2372 }
2373
2374 alist_check_arg_idx();
2375
2376 /* Edit the argument. */
2377 do_argfile(eap, i);
2378}
2379
2380/*
2381 * ":argadd"
2382 */
2383 void
2384ex_argadd(eap)
2385 exarg_T *eap;
2386{
2387 do_arglist(eap->arg, AL_ADD,
2388 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2389#ifdef FEAT_TITLE
2390 maketitle();
2391#endif
2392}
2393
2394/*
2395 * ":argdelete"
2396 */
2397 void
2398ex_argdelete(eap)
2399 exarg_T *eap;
2400{
2401 int i;
2402 int n;
2403
2404 if (eap->addr_count > 0)
2405 {
2406 /* ":1,4argdel": Delete all arguments in the range. */
2407 if (eap->line2 > ARGCOUNT)
2408 eap->line2 = ARGCOUNT;
2409 n = eap->line2 - eap->line1 + 1;
2410 if (*eap->arg != NUL || n <= 0)
2411 EMSG(_(e_invarg));
2412 else
2413 {
2414 for (i = eap->line1; i <= eap->line2; ++i)
2415 vim_free(ARGLIST[i - 1].ae_fname);
2416 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2417 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2418 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002419 if (curwin->w_arg_idx >= eap->line2)
2420 curwin->w_arg_idx -= n;
2421 else if (curwin->w_arg_idx > eap->line1)
2422 curwin->w_arg_idx = eap->line1;
2423 }
2424 }
2425 else if (*eap->arg == NUL)
2426 EMSG(_(e_argreq));
2427 else
2428 do_arglist(eap->arg, AL_DEL, 0);
2429#ifdef FEAT_TITLE
2430 maketitle();
2431#endif
2432}
2433
2434/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002435 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002436 */
2437 void
2438ex_listdo(eap)
2439 exarg_T *eap;
2440{
2441 int i;
2442#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002443 win_T *wp;
2444 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002445#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002446 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 int next_fnum = 0;
2448#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2449 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002451 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002452#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002453 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002454 int qf_idx;
2455#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456
2457#ifndef FEAT_WINDOWS
2458 if (eap->cmdidx == CMD_windo)
2459 {
2460 ex_ni(eap);
2461 return;
2462 }
2463#endif
2464
2465#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002466 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002467 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2468 * great speed improvement. */
2469 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002471#ifdef FEAT_CLIPBOARD
2472 start_global_changes();
2473#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474
2475 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002476 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002478 || !check_changed(curbuf, CCGD_AW
2479 | (eap->forceit ? CCGD_FORCEIT : 0)
2480 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002483 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002485 wp = firstwin;
2486 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002488 switch (eap->cmdidx)
2489 {
2490#ifdef FEAT_WINDOWS
2491 case CMD_windo:
2492 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2493 i++;
2494 break;
2495 case CMD_tabdo:
2496 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2497 i++;
2498 break;
2499#endif
2500 case CMD_argdo:
2501 i = eap->line1 - 1;
2502 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002503 default:
2504 break;
2505 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002506 /* set pcmark now */
2507 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002508 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002509 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002510 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002511 || !buf->b_p_bl); buf = buf->b_next)
2512 if (buf->b_fnum > eap->line2)
2513 {
2514 buf = NULL;
2515 break;
2516 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002517 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002518 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002519 }
2520#ifdef FEAT_QUICKFIX
2521 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2522 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2523 {
2524 qf_size = qf_get_size(eap);
2525 if (qf_size <= 0 || eap->line1 > qf_size)
2526 buf = NULL;
2527 else
2528 {
2529 ex_cc(eap);
2530
2531 buf = curbuf;
2532 i = eap->line1 - 1;
2533 if (eap->addr_count <= 0)
2534 /* default is all the quickfix/location list entries */
2535 eap->line2 = qf_size;
2536 }
2537 }
2538#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539 else
2540 setpcmark();
2541 listcmd_busy = TRUE; /* avoids setting pcmark below */
2542
Bram Moolenaare25bb902015-02-27 20:33:37 +01002543 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002544 {
2545 if (eap->cmdidx == CMD_argdo)
2546 {
2547 /* go to argument "i" */
2548 if (i == ARGCOUNT)
2549 break;
2550 /* Don't call do_argfile() when already there, it will try
2551 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002552 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002553 {
2554 /* Clear 'shm' to avoid that the file message overwrites
2555 * any output from the command. */
2556 p_shm_save = vim_strsave(p_shm);
2557 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002559 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2560 vim_free(p_shm_save);
2561 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562 if (curwin->w_arg_idx != i)
2563 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 }
2565#ifdef FEAT_WINDOWS
2566 else if (eap->cmdidx == CMD_windo)
2567 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002568 /* go to window "wp" */
2569 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002571 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002572 if (curwin != wp)
2573 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002574 wp = curwin->w_next;
2575 }
2576 else if (eap->cmdidx == CMD_tabdo)
2577 {
2578 /* go to window "tp" */
2579 if (!valid_tabpage(tp))
2580 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002581 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002582 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583 }
2584#endif
2585 else if (eap->cmdidx == CMD_bufdo)
2586 {
2587 /* Remember the number of the next listed buffer, in case
2588 * ":bwipe" is used or autocommands do something strange. */
2589 next_fnum = -1;
2590 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2591 if (buf->b_p_bl)
2592 {
2593 next_fnum = buf->b_fnum;
2594 break;
2595 }
2596 }
2597
Bram Moolenaara162bc52015-01-07 16:54:21 +01002598 ++i;
2599
Bram Moolenaar071d4272004-06-13 20:20:40 +00002600 /* execute the command */
2601 do_cmdline(eap->arg, eap->getline, eap->cookie,
2602 DOCMD_VERBOSE + DOCMD_NOWAIT);
2603
2604 if (eap->cmdidx == CMD_bufdo)
2605 {
2606 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002607 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002608 break;
2609 /* Check if the buffer still exists. */
2610 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2611 if (buf->b_fnum == next_fnum)
2612 break;
2613 if (buf == NULL)
2614 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002615
2616 /* Go to the next buffer. Clear 'shm' to avoid that the file
2617 * message overwrites any output from the command. */
2618 p_shm_save = vim_strsave(p_shm);
2619 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002621 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2622 vim_free(p_shm_save);
2623
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002624 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002625 if (curbuf->b_fnum != next_fnum)
2626 break;
2627 }
2628
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002629#ifdef FEAT_QUICKFIX
2630 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2631 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2632 {
2633 if (i >= qf_size || i >= eap->line2)
2634 break;
2635
2636 qf_idx = qf_get_cur_idx(eap);
2637
2638 ex_cnext(eap);
2639
2640 /* If jumping to the next quickfix entry fails, quit here */
2641 if (qf_get_cur_idx(eap) == qf_idx)
2642 break;
2643 }
2644#endif
2645
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646 if (eap->cmdidx == CMD_windo)
2647 {
2648 validate_cursor(); /* cursor may have moved */
2649#ifdef FEAT_SCROLLBIND
2650 /* required when 'scrollbind' has been set */
2651 if (curwin->w_p_scb)
2652 do_check_scrollbind(TRUE);
2653#endif
2654 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002655
2656#ifdef FEAT_WINDOWS
2657 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2658 if (i+1 > eap->line2)
2659 break;
2660#endif
2661 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2662 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002663 }
2664 listcmd_busy = FALSE;
2665 }
2666
2667#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002668 if (save_ei != NULL)
2669 {
2670 au_event_restore(save_ei);
2671 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2672 curbuf->b_fname, TRUE, curbuf);
2673 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002675#ifdef FEAT_CLIPBOARD
2676 end_global_changes();
2677#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678}
2679
2680/*
2681 * Add files[count] to the arglist of the current window after arg "after".
2682 * The file names in files[count] must have been allocated and are taken over.
2683 * Files[] itself is not taken over.
2684 * Returns index of first added argument. Returns -1 when failed (out of mem).
2685 */
2686 static int
2687alist_add_list(count, files, after)
2688 int count;
2689 char_u **files;
2690 int after; /* where to add: 0 = before first one */
2691{
2692 int i;
2693
2694 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2695 {
2696 if (after < 0)
2697 after = 0;
2698 if (after > ARGCOUNT)
2699 after = ARGCOUNT;
2700 if (after < ARGCOUNT)
2701 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2702 (ARGCOUNT - after) * sizeof(aentry_T));
2703 for (i = 0; i < count; ++i)
2704 {
2705 ARGLIST[after + i].ae_fname = files[i];
2706 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2707 }
2708 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709 if (curwin->w_arg_idx >= after)
2710 ++curwin->w_arg_idx;
2711 return after;
2712 }
2713
2714 for (i = 0; i < count; ++i)
2715 vim_free(files[i]);
2716 return -1;
2717}
2718
2719#endif /* FEAT_LISTCMDS */
2720
2721#ifdef FEAT_EVAL
2722/*
2723 * ":compiler[!] {name}"
2724 */
2725 void
2726ex_compiler(eap)
2727 exarg_T *eap;
2728{
2729 char_u *buf;
2730 char_u *old_cur_comp = NULL;
2731 char_u *p;
2732
2733 if (*eap->arg == NUL)
2734 {
2735 /* List all compiler scripts. */
2736 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2737 /* ) keep the indenter happy... */
2738 }
2739 else
2740 {
2741 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2742 if (buf != NULL)
2743 {
2744 if (eap->forceit)
2745 {
2746 /* ":compiler! {name}" sets global options */
2747 do_cmdline_cmd((char_u *)
2748 "command -nargs=* CompilerSet set <args>");
2749 }
2750 else
2751 {
2752 /* ":compiler! {name}" sets local options.
2753 * To remain backwards compatible "current_compiler" is always
2754 * used. A user's compiler plugin may set it, the distributed
2755 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002756 * "b:current_compiler" and restore "current_compiler".
2757 * Explicitly prepend "g:" to make it work in a function. */
2758 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759 if (old_cur_comp != NULL)
2760 old_cur_comp = vim_strsave(old_cur_comp);
2761 do_cmdline_cmd((char_u *)
2762 "command -nargs=* CompilerSet setlocal <args>");
2763 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002764 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002765 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766
2767 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002768 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2770 vim_free(buf);
2771
2772 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2773
2774 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002775 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 if (p != NULL)
2777 set_internal_string_var((char_u *)"b:current_compiler", p);
2778
2779 /* Restore "current_compiler" for ":compiler {name}". */
2780 if (!eap->forceit)
2781 {
2782 if (old_cur_comp != NULL)
2783 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002784 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785 old_cur_comp);
2786 vim_free(old_cur_comp);
2787 }
2788 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002789 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002790 }
2791 }
2792 }
2793}
2794#endif
2795
2796/*
2797 * ":runtime {name}"
2798 */
2799 void
2800ex_runtime(eap)
2801 exarg_T *eap;
2802{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002803 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804}
2805
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002806static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807
2808 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002809source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002810 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002811 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002813 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814}
2815
2816/*
2817 * Source the file "name" from all directories in 'runtimepath'.
2818 * "name" can contain wildcards.
2819 * When "all" is TRUE, source all files, otherwise only the first one.
2820 * return FAIL when no file could be sourced, OK otherwise.
2821 */
2822 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002823source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824 char_u *name;
2825 int all;
2826{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002827 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002828}
2829
2830/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002831 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2832 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002833 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2834 * used.
2835 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002836 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002837 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2838 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002839 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840 */
2841 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002842do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 char_u *name;
2844 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002845 void (*callback)__ARGS((char_u *fname, void *ck));
2846 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002847{
2848 char_u *rtp;
2849 char_u *np;
2850 char_u *buf;
2851 char_u *rtp_copy;
2852 char_u *tail;
2853 int num_files;
2854 char_u **files;
2855 int i;
2856 int did_one = FALSE;
2857#ifdef AMIGA
2858 struct Process *proc = (struct Process *)FindTask(0L);
2859 APTR save_winptr = proc->pr_WindowPtr;
2860
2861 /* Avoid a requester here for a volume that doesn't exist. */
2862 proc->pr_WindowPtr = (APTR)-1L;
2863#endif
2864
2865 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2866 * value. */
2867 rtp_copy = vim_strsave(p_rtp);
2868 buf = alloc(MAXPATHL);
2869 if (buf != NULL && rtp_copy != NULL)
2870 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002871 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002872 {
2873 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002874 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002875 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002876 verbose_leave();
2877 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002878
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879 /* Loop over all entries in 'runtimepath'. */
2880 rtp = rtp_copy;
2881 while (*rtp != NUL && (all || !did_one))
2882 {
2883 /* Copy the path from 'runtimepath' to buf[]. */
2884 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002885 if (name == NULL)
2886 {
2887 (*callback)(buf, (void *) &cookie);
2888 if (!did_one)
2889 did_one = (cookie == NULL);
2890 }
2891 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892 {
2893 add_pathsep(buf);
2894 tail = buf + STRLEN(buf);
2895
2896 /* Loop over all patterns in "name" */
2897 np = name;
2898 while (*np != NUL && (all || !did_one))
2899 {
2900 /* Append the pattern from "name" to buf[]. */
2901 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2902 "\t ");
2903
2904 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002905 {
2906 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002907 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002908 verbose_leave();
2909 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910
2911 /* Expand wildcards, invoke the callback for each match. */
2912 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2913 EW_FILE) == OK)
2914 {
2915 for (i = 0; i < num_files; ++i)
2916 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002917 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002918 did_one = TRUE;
2919 if (!all)
2920 break;
2921 }
2922 FreeWild(num_files, files);
2923 }
2924 }
2925 }
2926 }
2927 }
2928 vim_free(buf);
2929 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002930 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002931 {
2932 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002933 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002934 verbose_leave();
2935 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936
2937#ifdef AMIGA
2938 proc->pr_WindowPtr = save_winptr;
2939#endif
2940
2941 return did_one ? OK : FAIL;
2942}
2943
2944#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2945/*
2946 * ":options"
2947 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948 void
2949ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002950 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951{
2952 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2953}
2954#endif
2955
2956/*
2957 * ":source {fname}"
2958 */
2959 void
2960ex_source(eap)
2961 exarg_T *eap;
2962{
2963#ifdef FEAT_BROWSE
2964 if (cmdmod.browse)
2965 {
2966 char_u *fname = NULL;
2967
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002968 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002969 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2970 if (fname != NULL)
2971 {
2972 cmd_source(fname, eap);
2973 vim_free(fname);
2974 }
2975 }
2976 else
2977#endif
2978 cmd_source(eap->arg, eap);
2979}
2980
2981 static void
2982cmd_source(fname, eap)
2983 char_u *fname;
2984 exarg_T *eap;
2985{
2986 if (*fname == NUL)
2987 EMSG(_(e_argreq));
2988
Bram Moolenaar071d4272004-06-13 20:20:40 +00002989 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002990 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002991 * Need to execute the commands directly. This is required at least
2992 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002993 * - ":g" command busy
2994 * - after ":argdo", ":windo" or ":bufdo"
2995 * - another command follows
2996 * - inside a loop
2997 */
2998 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2999#ifdef FEAT_EVAL
3000 || eap->cstack->cs_idx >= 0
3001#endif
3002 );
3003
3004 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003005 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003006 EMSG2(_(e_notopen), fname);
3007}
3008
3009/*
3010 * ":source" and associated commands.
3011 */
3012/*
3013 * Structure used to store info for each sourced file.
3014 * It is shared between do_source() and getsourceline().
3015 * This is required, because it needs to be handed to do_cmdline() and
3016 * sourcing can be done recursively.
3017 */
3018struct source_cookie
3019{
3020 FILE *fp; /* opened file for sourcing */
3021 char_u *nextline; /* if not NULL: line that was read ahead */
3022 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003023#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003024 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3025 int error; /* TRUE if LF found after CR-LF */
3026#endif
3027#ifdef FEAT_EVAL
3028 linenr_T breakpoint; /* next line with breakpoint or zero */
3029 char_u *fname; /* name of sourced file */
3030 int dbg_tick; /* debug_tick when breakpoint was set */
3031 int level; /* top nesting level of sourced file */
3032#endif
3033#ifdef FEAT_MBYTE
3034 vimconv_T conv; /* type of conversion */
3035#endif
3036};
3037
3038#ifdef FEAT_EVAL
3039/*
3040 * Return the address holding the next breakpoint line for a source cookie.
3041 */
3042 linenr_T *
3043source_breakpoint(cookie)
3044 void *cookie;
3045{
3046 return &((struct source_cookie *)cookie)->breakpoint;
3047}
3048
3049/*
3050 * Return the address holding the debug tick for a source cookie.
3051 */
3052 int *
3053source_dbg_tick(cookie)
3054 void *cookie;
3055{
3056 return &((struct source_cookie *)cookie)->dbg_tick;
3057}
3058
3059/*
3060 * Return the nesting level for a source cookie.
3061 */
3062 int
3063source_level(cookie)
3064 void *cookie;
3065{
3066 return ((struct source_cookie *)cookie)->level;
3067}
3068#endif
3069
3070static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
3071
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003072#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3073# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074static FILE *fopen_noinh_readbin __ARGS((char *filename));
3075
3076/*
3077 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003078 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003079 */
3080 static FILE *
3081fopen_noinh_readbin(filename)
3082 char *filename;
3083{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003084# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003085 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3086# else
3087 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003088# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089
3090 if (fd_tmp == -1)
3091 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003092
3093# ifdef HAVE_FD_CLOEXEC
3094 {
3095 int fdflags = fcntl(fd_tmp, F_GETFD);
3096 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003097 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003098 }
3099# endif
3100
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101 return fdopen(fd_tmp, READBIN);
3102}
3103#endif
3104
3105
3106/*
3107 * do_source: Read the file "fname" and execute its lines as EX commands.
3108 *
3109 * This function may be called recursively!
3110 *
3111 * return FAIL if file could not be opened, OK otherwise
3112 */
3113 int
3114do_source(fname, check_other, is_vimrc)
3115 char_u *fname;
3116 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003117 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003118{
3119 struct source_cookie cookie;
3120 char_u *save_sourcing_name;
3121 linenr_T save_sourcing_lnum;
3122 char_u *p;
3123 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003124 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003125 int retval = FAIL;
3126#ifdef FEAT_EVAL
3127 scid_T save_current_SID;
3128 static scid_T last_current_SID = 0;
3129 void *save_funccalp;
3130 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003131 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132# ifdef UNIX
3133 struct stat st;
3134 int stat_ok;
3135# endif
3136#endif
3137#ifdef STARTUPTIME
3138 struct timeval tv_rel;
3139 struct timeval tv_start;
3140#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003141#ifdef FEAT_PROFILE
3142 proftime_T wait_start;
3143#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146 if (p == NULL)
3147 return retval;
3148 fname_exp = fix_fname(p);
3149 vim_free(p);
3150 if (fname_exp == NULL)
3151 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152 if (mch_isdir(fname_exp))
3153 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003154 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003155 goto theend;
3156 }
3157
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003158#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003159 /* Apply SourceCmd autocommands, they should get the file and source it. */
3160 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3161 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3162 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003163 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003164# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003165 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003166# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003167 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003168# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003169 goto theend;
3170 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003171
3172 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003173 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3174#endif
3175
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003176#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003177 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3178#else
3179 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3180#endif
3181 if (cookie.fp == NULL && check_other)
3182 {
3183 /*
3184 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3185 * and ".exrc" by "_exrc" or vice versa.
3186 */
3187 p = gettail(fname_exp);
3188 if ((*p == '.' || *p == '_')
3189 && (STRICMP(p + 1, "vimrc") == 0
3190 || STRICMP(p + 1, "gvimrc") == 0
3191 || STRICMP(p + 1, "exrc") == 0))
3192 {
3193 if (*p == '_')
3194 *p = '.';
3195 else
3196 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003197#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3199#else
3200 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3201#endif
3202 }
3203 }
3204
3205 if (cookie.fp == NULL)
3206 {
3207 if (p_verbose > 0)
3208 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003209 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003211 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 else
3213 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003214 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003215 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 }
3217 goto theend;
3218 }
3219
3220 /*
3221 * The file exists.
3222 * - In verbose mode, give a message.
3223 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3224 */
3225 if (p_verbose > 1)
3226 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003227 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003229 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003230 else
3231 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003232 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003233 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003235 if (is_vimrc == DOSO_VIMRC)
3236 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3237 else if (is_vimrc == DOSO_GVIMRC)
3238 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003239
3240#ifdef USE_CRNL
3241 /* If no automatic file format: Set default to CR-NL. */
3242 if (*p_ffs == NUL)
3243 cookie.fileformat = EOL_DOS;
3244 else
3245 cookie.fileformat = EOL_UNKNOWN;
3246 cookie.error = FALSE;
3247#endif
3248
3249#ifdef USE_CR
3250 /* If no automatic file format: Set default to CR. */
3251 if (*p_ffs == NUL)
3252 cookie.fileformat = EOL_MAC;
3253 else
3254 cookie.fileformat = EOL_UNKNOWN;
3255 cookie.error = FALSE;
3256#endif
3257
3258 cookie.nextline = NULL;
3259 cookie.finished = FALSE;
3260
3261#ifdef FEAT_EVAL
3262 /*
3263 * Check if this script has a breakpoint.
3264 */
3265 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3266 cookie.fname = fname_exp;
3267 cookie.dbg_tick = debug_tick;
3268
3269 cookie.level = ex_nesting_level;
3270#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271
3272 /*
3273 * Keep the sourcing name/lnum, for recursive calls.
3274 */
3275 save_sourcing_name = sourcing_name;
3276 sourcing_name = fname_exp;
3277 save_sourcing_lnum = sourcing_lnum;
3278 sourcing_lnum = 0;
3279
Bram Moolenaar73881402009-02-04 16:50:47 +00003280#ifdef FEAT_MBYTE
3281 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3282
3283 /* Read the first line so we can check for a UTF-8 BOM. */
3284 firstline = getsourceline(0, (void *)&cookie, 0);
3285 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3286 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3287 {
3288 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3289 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3290 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003291 if (p == NULL)
3292 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003293 if (p != NULL)
3294 {
3295 vim_free(firstline);
3296 firstline = p;
3297 }
3298 }
3299#endif
3300
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003302 if (time_fd != NULL)
3303 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003304#endif
3305
3306#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003307# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003308 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003309 prof_child_enter(&wait_start); /* entering a child now */
3310# endif
3311
3312 /* Don't use local function variables, if called from a function.
3313 * Also starts profiling timer for nested script. */
3314 save_funccalp = save_funccal();
3315
Bram Moolenaar071d4272004-06-13 20:20:40 +00003316 /*
3317 * Check if this script was sourced before to finds its SID.
3318 * If it's new, generate a new SID.
3319 */
3320 save_current_SID = current_SID;
3321# ifdef UNIX
3322 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3323# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003324 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3325 {
3326 si = &SCRIPT_ITEM(current_SID);
3327 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328 && (
3329# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003330 /* Compare dev/ino when possible, it catches symbolic
3331 * links. Also compare file names, the inode may change
3332 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003333 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003334 && (si->sn_dev == st.st_dev
3335 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003337 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003339 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 if (current_SID == 0)
3341 {
3342 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003343 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3344 == FAIL)
3345 goto almosttheend;
3346 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003347 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003348 ++script_items.ga_len;
3349 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3350# ifdef FEAT_PROFILE
3351 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003353 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003354 si = &SCRIPT_ITEM(current_SID);
3355 si->sn_name = fname_exp;
3356 fname_exp = NULL;
3357# ifdef UNIX
3358 if (stat_ok)
3359 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003360 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003361 si->sn_dev = st.st_dev;
3362 si->sn_ino = st.st_ino;
3363 }
3364 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003365 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003366# endif
3367
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368 /* Allocate the local script variables to use for this script. */
3369 new_script_vars(current_SID);
3370 }
3371
Bram Moolenaar05159a02005-02-26 23:04:13 +00003372# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003373 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003374 {
3375 int forceit;
3376
3377 /* Check if we do profiling for this script. */
3378 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3379 {
3380 script_do_profile(si);
3381 si->sn_pr_force = forceit;
3382 }
3383 if (si->sn_prof_on)
3384 {
3385 ++si->sn_pr_count;
3386 profile_start(&si->sn_pr_start);
3387 profile_zero(&si->sn_pr_children);
3388 }
3389 }
3390# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003391#endif
3392
3393 /*
3394 * Call do_cmdline, which will call getsourceline() to get the lines.
3395 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003396 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003397 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003398 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003399
3400#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003401 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003402 {
3403 /* Get "si" again, "script_items" may have been reallocated. */
3404 si = &SCRIPT_ITEM(current_SID);
3405 if (si->sn_prof_on)
3406 {
3407 profile_end(&si->sn_pr_start);
3408 profile_sub_wait(&wait_start, &si->sn_pr_start);
3409 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003410 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3411 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003412 }
3413 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414#endif
3415
3416 if (got_int)
3417 EMSG(_(e_interr));
3418 sourcing_name = save_sourcing_name;
3419 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003420 if (p_verbose > 1)
3421 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003422 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003423 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003424 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003425 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003426 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427 }
3428#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003429 if (time_fd != NULL)
3430 {
3431 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3432 time_msg((char *)IObuff, &tv_start);
3433 time_pop(&tv_rel);
3434 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003435#endif
3436
3437#ifdef FEAT_EVAL
3438 /*
3439 * After a "finish" in debug mode, need to break at first command of next
3440 * sourced file.
3441 */
3442 if (save_debug_break_level > ex_nesting_level
3443 && debug_break_level == ex_nesting_level)
3444 ++debug_break_level;
3445#endif
3446
Bram Moolenaar05159a02005-02-26 23:04:13 +00003447#ifdef FEAT_EVAL
3448almosttheend:
3449 current_SID = save_current_SID;
3450 restore_funccal(save_funccalp);
3451# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003452 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003453 prof_child_exit(&wait_start); /* leaving a child now */
3454# endif
3455#endif
3456 fclose(cookie.fp);
3457 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003458 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003459#ifdef FEAT_MBYTE
3460 convert_setup(&cookie.conv, NULL, NULL);
3461#endif
3462
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463theend:
3464 vim_free(fname_exp);
3465 return retval;
3466}
3467
3468#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003469
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470/*
3471 * ":scriptnames"
3472 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003473 void
3474ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003475 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476{
3477 int i;
3478
Bram Moolenaar05159a02005-02-26 23:04:13 +00003479 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3480 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003481 {
3482 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3483 NameBuff, MAXPATHL, TRUE);
3484 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003485 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003486}
3487
3488# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3489/*
3490 * Fix slashes in the list of script names for 'shellslash'.
3491 */
3492 void
3493scriptnames_slash_adjust()
3494{
3495 int i;
3496
Bram Moolenaar05159a02005-02-26 23:04:13 +00003497 for (i = 1; i <= script_items.ga_len; ++i)
3498 if (SCRIPT_ITEM(i).sn_name != NULL)
3499 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003500}
3501# endif
3502
3503/*
3504 * Get a pointer to a script name. Used for ":verbose set".
3505 */
3506 char_u *
3507get_scriptname(id)
3508 scid_T id;
3509{
3510 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003511 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003512 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003513 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003515 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003516 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003517 return (char_u *)_("environment variable");
3518 if (id == SID_ERROR)
3519 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003520 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003521}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003522
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003523# if defined(EXITFREE) || defined(PROTO)
3524 void
3525free_scriptnames()
3526{
3527 int i;
3528
3529 for (i = script_items.ga_len; i > 0; --i)
3530 vim_free(SCRIPT_ITEM(i).sn_name);
3531 ga_clear(&script_items);
3532}
3533# endif
3534
Bram Moolenaar071d4272004-06-13 20:20:40 +00003535#endif
3536
3537#if defined(USE_CR) || defined(PROTO)
3538
3539# if defined(__MSL__) && (__MSL__ >= 22)
3540/*
3541 * Newer version of the Metrowerks library handle DOS and UNIX files
3542 * without help.
3543 * Test with earlier versions, MSL 2.2 is the library supplied with
3544 * Codewarrior Pro 2.
3545 */
3546 char *
3547fgets_cr(s, n, stream)
3548 char *s;
3549 int n;
3550 FILE *stream;
3551{
3552 return fgets(s, n, stream);
3553}
3554# else
3555/*
3556 * Version of fgets() which also works for lines ending in a <CR> only
3557 * (Macintosh format).
3558 * For older versions of the Metrowerks library.
3559 * At least CodeWarrior 9 needed this code.
3560 */
3561 char *
3562fgets_cr(s, n, stream)
3563 char *s;
3564 int n;
3565 FILE *stream;
3566{
3567 int c = 0;
3568 int char_read = 0;
3569
3570 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3571 {
3572 c = fgetc(stream);
3573 s[char_read++] = c;
3574 /* If the file is in DOS format, we need to skip a NL after a CR. I
3575 * thought it was the other way around, but this appears to work... */
3576 if (c == '\n')
3577 {
3578 c = fgetc(stream);
3579 if (c != '\r')
3580 ungetc(c, stream);
3581 }
3582 }
3583
3584 s[char_read] = 0;
3585 if (char_read == 0)
3586 return NULL;
3587
3588 if (feof(stream) && char_read == 1)
3589 return NULL;
3590
3591 return s;
3592}
3593# endif
3594#endif
3595
3596/*
3597 * Get one full line from a sourced file.
3598 * Called by do_cmdline() when it's called from do_source().
3599 *
3600 * Return a pointer to the line in allocated memory.
3601 * Return NULL for end-of-file or some error.
3602 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003603 char_u *
3604getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003605 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003606 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003607 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608{
3609 struct source_cookie *sp = (struct source_cookie *)cookie;
3610 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003611 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612
3613#ifdef FEAT_EVAL
3614 /* If breakpoints have been added/deleted need to check for it. */
3615 if (sp->dbg_tick < debug_tick)
3616 {
3617 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3618 sp->dbg_tick = debug_tick;
3619 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003620# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003621 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003622 script_line_end();
3623# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003624#endif
3625 /*
3626 * Get current line. If there is a read-ahead line, use it, otherwise get
3627 * one now.
3628 */
3629 if (sp->finished)
3630 line = NULL;
3631 else if (sp->nextline == NULL)
3632 line = get_one_sourceline(sp);
3633 else
3634 {
3635 line = sp->nextline;
3636 sp->nextline = NULL;
3637 ++sourcing_lnum;
3638 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003639#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003640 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003641 script_line_start();
3642#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003643
3644 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3645 * contain the 'C' flag. */
3646 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3647 {
3648 /* compensate for the one line read-ahead */
3649 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003650
3651 /* Get the next line and concatenate it when it starts with a
3652 * backslash. We always need to read the next line, keep it in
3653 * sp->nextline. */
3654 sp->nextline = get_one_sourceline(sp);
3655 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003656 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003657 garray_T ga;
3658
Bram Moolenaarb549a732012-02-22 18:29:33 +01003659 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003660 ga_concat(&ga, line);
3661 ga_concat(&ga, p + 1);
3662 for (;;)
3663 {
3664 vim_free(sp->nextline);
3665 sp->nextline = get_one_sourceline(sp);
3666 if (sp->nextline == NULL)
3667 break;
3668 p = skipwhite(sp->nextline);
3669 if (*p != '\\')
3670 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003671 /* Adjust the growsize to the current length to speed up
3672 * concatenating many lines. */
3673 if (ga.ga_len > 400)
3674 {
3675 if (ga.ga_len > 8000)
3676 ga.ga_growsize = 8000;
3677 else
3678 ga.ga_growsize = ga.ga_len;
3679 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003680 ga_concat(&ga, p + 1);
3681 }
3682 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003684 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685 }
3686 }
3687
3688#ifdef FEAT_MBYTE
3689 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3690 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003691 char_u *s;
3692
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693 /* Convert the encoding of the script line. */
3694 s = string_convert(&sp->conv, line, NULL);
3695 if (s != NULL)
3696 {
3697 vim_free(line);
3698 line = s;
3699 }
3700 }
3701#endif
3702
3703#ifdef FEAT_EVAL
3704 /* Did we encounter a breakpoint? */
3705 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3706 {
3707 dbg_breakpoint(sp->fname, sourcing_lnum);
3708 /* Find next breakpoint. */
3709 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3710 sp->dbg_tick = debug_tick;
3711 }
3712#endif
3713
3714 return line;
3715}
3716
3717 static char_u *
3718get_one_sourceline(sp)
3719 struct source_cookie *sp;
3720{
3721 garray_T ga;
3722 int len;
3723 int c;
3724 char_u *buf;
3725#ifdef USE_CRNL
3726 int has_cr; /* CR-LF found */
3727#endif
3728#ifdef USE_CR
3729 char_u *scan;
3730#endif
3731 int have_read = FALSE;
3732
3733 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003734 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735
3736 /*
3737 * Loop until there is a finished line (or end-of-file).
3738 */
3739 sourcing_lnum++;
3740 for (;;)
3741 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003742 /* make room to read at least 120 (more) characters */
3743 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003744 break;
3745 buf = (char_u *)ga.ga_data;
3746
3747#ifdef USE_CR
3748 if (sp->fileformat == EOL_MAC)
3749 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003750 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3751 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003752 break;
3753 }
3754 else
3755#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003756 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3757 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003759 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003760#ifdef USE_CRNL
3761 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3762 * CTRL-Z by its own, or after a NL. */
3763 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3764 && sp->fileformat == EOL_DOS
3765 && buf[len - 1] == Ctrl_Z)
3766 {
3767 buf[len - 1] = NUL;
3768 break;
3769 }
3770#endif
3771
3772#ifdef USE_CR
3773 /* If the read doesn't stop on a new line, and there's
3774 * some CR then we assume a Mac format */
3775 if (sp->fileformat == EOL_UNKNOWN)
3776 {
3777 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3778 sp->fileformat = EOL_MAC;
3779 else
3780 sp->fileformat = EOL_UNIX;
3781 }
3782
3783 if (sp->fileformat == EOL_MAC)
3784 {
3785 scan = vim_strchr(buf, '\r');
3786
3787 if (scan != NULL)
3788 {
3789 *scan = '\n';
3790 if (*(scan + 1) != 0)
3791 {
3792 *(scan + 1) = 0;
3793 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3794 }
3795 }
3796 len = STRLEN(buf);
3797 }
3798#endif
3799
3800 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003801 ga.ga_len = len;
3802
3803 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003804 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003805 continue;
3806
3807 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3808 {
3809#ifdef USE_CRNL
3810 has_cr = (len >= 2 && buf[len - 2] == '\r');
3811 if (sp->fileformat == EOL_UNKNOWN)
3812 {
3813 if (has_cr)
3814 sp->fileformat = EOL_DOS;
3815 else
3816 sp->fileformat = EOL_UNIX;
3817 }
3818
3819 if (sp->fileformat == EOL_DOS)
3820 {
3821 if (has_cr) /* replace trailing CR */
3822 {
3823 buf[len - 2] = '\n';
3824 --len;
3825 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826 }
3827 else /* lines like ":map xx yy^M" will have failed */
3828 {
3829 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003830 {
3831 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003833 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003834 sp->error = TRUE;
3835 sp->fileformat = EOL_UNIX;
3836 }
3837 }
3838#endif
3839 /* The '\n' is escaped if there is an odd number of ^V's just
3840 * before it, first set "c" just before the 'V's and then check
3841 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3842 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3843 ;
3844 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3845 {
3846 sourcing_lnum++;
3847 continue;
3848 }
3849
3850 buf[len - 1] = NUL; /* remove the NL */
3851 }
3852
3853 /*
3854 * Check for ^C here now and then, so recursive :so can be broken.
3855 */
3856 line_breakcheck();
3857 break;
3858 }
3859
3860 if (have_read)
3861 return (char_u *)ga.ga_data;
3862
3863 vim_free(ga.ga_data);
3864 return NULL;
3865}
3866
Bram Moolenaar05159a02005-02-26 23:04:13 +00003867#if defined(FEAT_PROFILE) || defined(PROTO)
3868/*
3869 * Called when starting to read a script line.
3870 * "sourcing_lnum" must be correct!
3871 * When skipping lines it may not actually be executed, but we won't find out
3872 * until later and we need to store the time now.
3873 */
3874 void
3875script_line_start()
3876{
3877 scriptitem_T *si;
3878 sn_prl_T *pp;
3879
3880 if (current_SID <= 0 || current_SID > script_items.ga_len)
3881 return;
3882 si = &SCRIPT_ITEM(current_SID);
3883 if (si->sn_prof_on && sourcing_lnum >= 1)
3884 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003885 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003886 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02003887 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00003888 si->sn_prl_idx = sourcing_lnum - 1;
3889 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3890 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3891 {
3892 /* Zero counters for a line that was not used before. */
3893 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3894 pp->snp_count = 0;
3895 profile_zero(&pp->sn_prl_total);
3896 profile_zero(&pp->sn_prl_self);
3897 ++si->sn_prl_ga.ga_len;
3898 }
3899 si->sn_prl_execed = FALSE;
3900 profile_start(&si->sn_prl_start);
3901 profile_zero(&si->sn_prl_children);
3902 profile_get_wait(&si->sn_prl_wait);
3903 }
3904}
3905
3906/*
3907 * Called when actually executing a function line.
3908 */
3909 void
3910script_line_exec()
3911{
3912 scriptitem_T *si;
3913
3914 if (current_SID <= 0 || current_SID > script_items.ga_len)
3915 return;
3916 si = &SCRIPT_ITEM(current_SID);
3917 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3918 si->sn_prl_execed = TRUE;
3919}
3920
3921/*
3922 * Called when done with a function line.
3923 */
3924 void
3925script_line_end()
3926{
3927 scriptitem_T *si;
3928 sn_prl_T *pp;
3929
3930 if (current_SID <= 0 || current_SID > script_items.ga_len)
3931 return;
3932 si = &SCRIPT_ITEM(current_SID);
3933 if (si->sn_prof_on && si->sn_prl_idx >= 0
3934 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3935 {
3936 if (si->sn_prl_execed)
3937 {
3938 pp = &PRL_ITEM(si, si->sn_prl_idx);
3939 ++pp->snp_count;
3940 profile_end(&si->sn_prl_start);
3941 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003942 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003943 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3944 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003945 }
3946 si->sn_prl_idx = -1;
3947 }
3948}
3949#endif
3950
Bram Moolenaar071d4272004-06-13 20:20:40 +00003951/*
3952 * ":scriptencoding": Set encoding conversion for a sourced script.
3953 * Without the multi-byte feature it's simply ignored.
3954 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955 void
3956ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003957 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003958{
3959#ifdef FEAT_MBYTE
3960 struct source_cookie *sp;
3961 char_u *name;
3962
3963 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3964 {
3965 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3966 return;
3967 }
3968
3969 if (*eap->arg != NUL)
3970 {
3971 name = enc_canonize(eap->arg);
3972 if (name == NULL) /* out of memory */
3973 return;
3974 }
3975 else
3976 name = eap->arg;
3977
3978 /* Setup for conversion from the specified encoding to 'encoding'. */
3979 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3980 convert_setup(&sp->conv, name, p_enc);
3981
3982 if (name != eap->arg)
3983 vim_free(name);
3984#endif
3985}
3986
3987#if defined(FEAT_EVAL) || defined(PROTO)
3988/*
3989 * ":finish": Mark a sourced file as finished.
3990 */
3991 void
3992ex_finish(eap)
3993 exarg_T *eap;
3994{
3995 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3996 do_finish(eap, FALSE);
3997 else
3998 EMSG(_("E168: :finish used outside of a sourced file"));
3999}
4000
4001/*
4002 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4003 * Also called for a pending finish at the ":endtry" or after returning from
4004 * an extra do_cmdline(). "reanimate" is used in the latter case.
4005 */
4006 void
4007do_finish(eap, reanimate)
4008 exarg_T *eap;
4009 int reanimate;
4010{
4011 int idx;
4012
4013 if (reanimate)
4014 ((struct source_cookie *)getline_cookie(eap->getline,
4015 eap->cookie))->finished = FALSE;
4016
4017 /*
4018 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4019 * not in its finally clause (which then is to be executed next) is found.
4020 * In this case, make the ":finish" pending for execution at the ":endtry".
4021 * Otherwise, finish normally.
4022 */
4023 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4024 if (idx >= 0)
4025 {
4026 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4027 report_make_pending(CSTP_FINISH, NULL);
4028 }
4029 else
4030 ((struct source_cookie *)getline_cookie(eap->getline,
4031 eap->cookie))->finished = TRUE;
4032}
4033
4034
4035/*
4036 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4037 * message for missing ":endif".
4038 * Return FALSE when not sourcing a file.
4039 */
4040 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00004041source_finished(fgetline, cookie)
4042 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043 void *cookie;
4044{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004045 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004046 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004047 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004048}
4049#endif
4050
4051#if defined(FEAT_LISTCMDS) || defined(PROTO)
4052/*
4053 * ":checktime [buffer]"
4054 */
4055 void
4056ex_checktime(eap)
4057 exarg_T *eap;
4058{
4059 buf_T *buf;
4060 int save_no_check_timestamps = no_check_timestamps;
4061
4062 no_check_timestamps = 0;
4063 if (eap->addr_count == 0) /* default is all buffers */
4064 check_timestamps(FALSE);
4065 else
4066 {
4067 buf = buflist_findnr((int)eap->line2);
4068 if (buf != NULL) /* cannot happen? */
4069 (void)buf_check_timestamp(buf, FALSE);
4070 }
4071 no_check_timestamps = save_no_check_timestamps;
4072}
4073#endif
4074
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4076 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004077# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004078static char *get_locale_val __ARGS((int what));
4079
4080 static char *
4081get_locale_val(what)
4082 int what;
4083{
4084 char *loc;
4085
4086 /* Obtain the locale value from the libraries. For DJGPP this is
4087 * redefined and it doesn't use the arguments. */
4088 loc = setlocale(what, NULL);
4089
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004090# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004091 if (loc != NULL)
4092 {
4093 char_u *p;
4094
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004095 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4096 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097 p = vim_strchr(loc, '=');
4098 if (p != NULL)
4099 {
4100 loc = ++p;
4101 while (*p != NUL) /* remove trailing newline */
4102 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004103 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104 {
4105 *p = NUL;
4106 break;
4107 }
4108 ++p;
4109 }
4110 }
4111 }
4112# endif
4113
4114 return loc;
4115}
4116#endif
4117
4118
4119#ifdef WIN32
4120/*
4121 * On MS-Windows locale names are strings like "German_Germany.1252", but
4122 * gettext expects "de". Try to translate one into another here for a few
4123 * supported languages.
4124 */
4125 static char_u *
4126gettext_lang(char_u *name)
4127{
4128 int i;
4129 static char *(mtable[]) = {
4130 "afrikaans", "af",
4131 "czech", "cs",
4132 "dutch", "nl",
4133 "german", "de",
4134 "english_united kingdom", "en_GB",
4135 "spanish", "es",
4136 "french", "fr",
4137 "italian", "it",
4138 "japanese", "ja",
4139 "korean", "ko",
4140 "norwegian", "no",
4141 "polish", "pl",
4142 "russian", "ru",
4143 "slovak", "sk",
4144 "swedish", "sv",
4145 "ukrainian", "uk",
4146 "chinese_china", "zh_CN",
4147 "chinese_taiwan", "zh_TW",
4148 NULL};
4149
4150 for (i = 0; mtable[i] != NULL; i += 2)
4151 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4152 return mtable[i + 1];
4153 return name;
4154}
4155#endif
4156
4157#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4158/*
4159 * Obtain the current messages language. Used to set the default for
4160 * 'helplang'. May return NULL or an empty string.
4161 */
4162 char_u *
4163get_mess_lang()
4164{
4165 char_u *p;
4166
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004167# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168# if defined(LC_MESSAGES)
4169 p = (char_u *)get_locale_val(LC_MESSAGES);
4170# else
4171 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004172 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4173 * and LC_MONETARY may be set differently for a Japanese working in the
4174 * US. */
4175 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176# endif
4177# else
4178 p = mch_getenv((char_u *)"LC_ALL");
4179 if (p == NULL || *p == NUL)
4180 {
4181 p = mch_getenv((char_u *)"LC_MESSAGES");
4182 if (p == NULL || *p == NUL)
4183 p = mch_getenv((char_u *)"LANG");
4184 }
4185# endif
4186# ifdef WIN32
4187 p = gettext_lang(p);
4188# endif
4189 return p;
4190}
4191#endif
4192
Bram Moolenaardef9e822004-12-31 20:58:58 +00004193/* Complicated #if; matches with where get_mess_env() is used below. */
4194#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4195 && defined(LC_MESSAGES))) \
4196 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4197 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4198 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004199static char_u *get_mess_env __ARGS((void));
4200
4201/*
4202 * Get the language used for messages from the environment.
4203 */
4204 static char_u *
4205get_mess_env()
4206{
4207 char_u *p;
4208
4209 p = mch_getenv((char_u *)"LC_ALL");
4210 if (p == NULL || *p == NUL)
4211 {
4212 p = mch_getenv((char_u *)"LC_MESSAGES");
4213 if (p == NULL || *p == NUL)
4214 {
4215 p = mch_getenv((char_u *)"LANG");
4216 if (p != NULL && VIM_ISDIGIT(*p))
4217 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004218# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219 if (p == NULL || *p == NUL)
4220 p = (char_u *)get_locale_val(LC_CTYPE);
4221# endif
4222 }
4223 }
4224 return p;
4225}
4226#endif
4227
4228#if defined(FEAT_EVAL) || defined(PROTO)
4229
4230/*
4231 * Set the "v:lang" variable according to the current locale setting.
4232 * Also do "v:lc_time"and "v:ctype".
4233 */
4234 void
4235set_lang_var()
4236{
4237 char_u *loc;
4238
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004239# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004240 loc = (char_u *)get_locale_val(LC_CTYPE);
4241# else
4242 /* setlocale() not supported: use the default value */
4243 loc = (char_u *)"C";
4244# endif
4245 set_vim_var_string(VV_CTYPE, loc, -1);
4246
4247 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4248 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004249# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250 loc = (char_u *)get_locale_val(LC_MESSAGES);
4251# else
4252 loc = get_mess_env();
4253# endif
4254 set_vim_var_string(VV_LANG, loc, -1);
4255
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004256# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257 loc = (char_u *)get_locale_val(LC_TIME);
4258# endif
4259 set_vim_var_string(VV_LC_TIME, loc, -1);
4260}
4261#endif
4262
4263#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4264 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4265/*
4266 * ":language": Set the language (locale).
4267 */
4268 void
4269ex_language(eap)
4270 exarg_T *eap;
4271{
4272 char *loc;
4273 char_u *p;
4274 char_u *name;
4275 int what = LC_ALL;
4276 char *whatstr = "";
4277#ifdef LC_MESSAGES
4278# define VIM_LC_MESSAGES LC_MESSAGES
4279#else
4280# define VIM_LC_MESSAGES 6789
4281#endif
4282
4283 name = eap->arg;
4284
4285 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4286 * Allow abbreviation, but require at least 3 characters to avoid
4287 * confusion with a two letter language name "me" or "ct". */
4288 p = skiptowhite(eap->arg);
4289 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4290 {
4291 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4292 {
4293 what = VIM_LC_MESSAGES;
4294 name = skipwhite(p);
4295 whatstr = "messages ";
4296 }
4297 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4298 {
4299 what = LC_CTYPE;
4300 name = skipwhite(p);
4301 whatstr = "ctype ";
4302 }
4303 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4304 {
4305 what = LC_TIME;
4306 name = skipwhite(p);
4307 whatstr = "time ";
4308 }
4309 }
4310
4311 if (*name == NUL)
4312 {
4313#ifndef LC_MESSAGES
4314 if (what == VIM_LC_MESSAGES)
4315 p = get_mess_env();
4316 else
4317#endif
4318 p = (char_u *)setlocale(what, NULL);
4319 if (p == NULL || *p == NUL)
4320 p = (char_u *)"Unknown";
4321 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4322 }
4323 else
4324 {
4325#ifndef LC_MESSAGES
4326 if (what == VIM_LC_MESSAGES)
4327 loc = "";
4328 else
4329#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004330 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004331 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004332#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4333 /* Make sure strtod() uses a decimal point, not a comma. */
4334 setlocale(LC_NUMERIC, "C");
4335#endif
4336 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004337 if (loc == NULL)
4338 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4339 else
4340 {
4341#ifdef HAVE_NL_MSG_CAT_CNTR
4342 /* Need to do this for GNU gettext, otherwise cached translations
4343 * will be used again. */
4344 extern int _nl_msg_cat_cntr;
4345
4346 ++_nl_msg_cat_cntr;
4347#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004348 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4350
4351 if (what != LC_TIME)
4352 {
4353 /* Tell gettext() what to translate to. It apparently doesn't
4354 * use the currently effective locale. Also do this when
4355 * FEAT_GETTEXT isn't defined, so that shell commands use this
4356 * value. */
4357 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004358 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004360
4361 /* Clear $LANGUAGE because GNU gettext uses it. */
4362 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004363# ifdef WIN32
4364 /* Apparently MS-Windows printf() may cause a crash when
4365 * we give it 8-bit text while it's expecting text in the
4366 * current locale. This call avoids that. */
4367 setlocale(LC_CTYPE, "C");
4368# endif
4369 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370 if (what != LC_CTYPE)
4371 {
4372 char_u *mname;
4373#ifdef WIN32
4374 mname = gettext_lang(name);
4375#else
4376 mname = name;
4377#endif
4378 vim_setenv((char_u *)"LC_MESSAGES", mname);
4379#ifdef FEAT_MULTI_LANG
4380 set_helplang_default(mname);
4381#endif
4382 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004383 }
4384
4385# ifdef FEAT_EVAL
4386 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4387 set_lang_var();
4388# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004389# ifdef FEAT_TITLE
4390 maketitle();
4391# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004392 }
4393 }
4394}
4395
4396# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004397
4398static char_u **locales = NULL; /* Array of all available locales */
4399static int did_init_locales = FALSE;
4400
4401static void init_locales __ARGS((void));
4402static char_u **find_locales __ARGS((void));
4403
4404/*
4405 * Lazy initialization of all available locales.
4406 */
4407 static void
4408init_locales()
4409{
4410 if (!did_init_locales)
4411 {
4412 did_init_locales = TRUE;
4413 locales = find_locales();
4414 }
4415}
4416
4417/* Return an array of strings for all available locales + NULL for the
4418 * last element. Return NULL in case of error. */
4419 static char_u **
4420find_locales()
4421{
4422 garray_T locales_ga;
4423 char_u *loc;
4424
4425 /* Find all available locales by running command "locale -a". If this
4426 * doesn't work we won't have completion. */
4427 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004428 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004429 if (locale_a == NULL)
4430 return NULL;
4431 ga_init2(&locales_ga, sizeof(char_u *), 20);
4432
4433 /* Transform locale_a string where each locale is separated by "\n"
4434 * into an array of locale strings. */
4435 loc = (char_u *)strtok((char *)locale_a, "\n");
4436
4437 while (loc != NULL)
4438 {
4439 if (ga_grow(&locales_ga, 1) == FAIL)
4440 break;
4441 loc = vim_strsave(loc);
4442 if (loc == NULL)
4443 break;
4444
4445 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4446 loc = (char_u *)strtok(NULL, "\n");
4447 }
4448 vim_free(locale_a);
4449 if (ga_grow(&locales_ga, 1) == FAIL)
4450 {
4451 ga_clear(&locales_ga);
4452 return NULL;
4453 }
4454 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4455 return (char_u **)locales_ga.ga_data;
4456}
4457
4458# if defined(EXITFREE) || defined(PROTO)
4459 void
4460free_locales()
4461{
4462 int i;
4463 if (locales != NULL)
4464 {
4465 for (i = 0; locales[i] != NULL; i++)
4466 vim_free(locales[i]);
4467 vim_free(locales);
4468 locales = NULL;
4469 }
4470}
4471# endif
4472
Bram Moolenaar071d4272004-06-13 20:20:40 +00004473/*
4474 * Function given to ExpandGeneric() to obtain the possible arguments of the
4475 * ":language" command.
4476 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004477 char_u *
4478get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004479 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004480 int idx;
4481{
4482 if (idx == 0)
4483 return (char_u *)"messages";
4484 if (idx == 1)
4485 return (char_u *)"ctype";
4486 if (idx == 2)
4487 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004488
4489 init_locales();
4490 if (locales == NULL)
4491 return NULL;
4492 return locales[idx - 3];
4493}
4494
4495/*
4496 * Function given to ExpandGeneric() to obtain the available locales.
4497 */
4498 char_u *
4499get_locales(xp, idx)
4500 expand_T *xp UNUSED;
4501 int idx;
4502{
4503 init_locales();
4504 if (locales == NULL)
4505 return NULL;
4506 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507}
4508# endif
4509
4510#endif