blob: 0fcb6c7a71a64ffe3ab7fbc9534f223b7c055cad [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 Moolenaarc236c162008-07-13 17:41:49 +000014#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
Bram Moolenaar8c8de832008-06-24 22:58:06 +000015# include "vimio.h" /* for mch_open(), must be before vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +000016#endif
17
18#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000019#include "version.h"
20
21static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
22
Bram Moolenaar05159a02005-02-26 23:04:13 +000023#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000024/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000025 * For Unix also store the dev/ino, so that we don't have to stat() each
26 * script when going through the list. */
27typedef struct scriptitem_S
28{
29 char_u *sn_name;
30# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000031 int sn_dev_valid;
32 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000033 ino_t sn_ino;
34# endif
35# ifdef FEAT_PROFILE
36 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000037 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000038 proftime_T sn_pr_child; /* time set when going into first child */
39 int sn_pr_nest; /* nesting for sn_pr_child */
40 /* profiling the script as a whole */
41 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000042 proftime_T sn_pr_total; /* time spent in script + children */
43 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000044 proftime_T sn_pr_start; /* time at script start */
45 proftime_T sn_pr_children; /* time in children after script start */
46 /* profiling the script per line */
47 garray_T sn_prl_ga; /* things stored for every line */
48 proftime_T sn_prl_start; /* start time for current line */
49 proftime_T sn_prl_children; /* time spent in children for this line */
50 proftime_T sn_prl_wait; /* wait start time for current line */
51 int sn_prl_idx; /* index of line being timed; -1 if none */
52 int sn_prl_execed; /* line being timed was executed */
53# endif
54} scriptitem_T;
55
56static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
57#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
58
59# ifdef FEAT_PROFILE
60/* Struct used in sn_prl_ga for every line of a script. */
61typedef struct sn_prl_S
62{
63 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000064 proftime_T sn_prl_total; /* time spent in a line + children */
65 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000066} sn_prl_T;
67
68# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
69# endif
70#endif
71
Bram Moolenaar071d4272004-06-13 20:20:40 +000072#if defined(FEAT_EVAL) || defined(PROTO)
73static int debug_greedy = FALSE; /* batch mode debugging: don't save
74 and restore typeahead. */
75
76/*
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
79 */
80 void
81do_debug(cmd)
82 char_u *cmd;
83{
84 int save_msg_scroll = msg_scroll;
85 int save_State = State;
86 int save_did_emsg = did_emsg;
87 int save_cmd_silent = cmd_silent;
88 int save_msg_silent = msg_silent;
89 int save_emsg_silent = emsg_silent;
90 int save_redir_off = redir_off;
91 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000092 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000093 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094# ifdef FEAT_EX_EXTRA
95 int save_ex_normal_busy;
96# endif
97 int n;
98 char_u *cmdline = NULL;
99 char_u *p;
100 char *tail = NULL;
101 static int last_cmd = 0;
102#define CMD_CONT 1
103#define CMD_NEXT 2
104#define CMD_STEP 3
105#define CMD_FINISH 4
106#define CMD_QUIT 5
107#define CMD_INTERRUPT 6
108
109#ifdef ALWAYS_USE_GUI
110 /* Can't do this when there is no terminal for input/output. */
111 if (!gui.in_use)
112 {
113 /* Break as soon as possible. */
114 debug_break_level = 9999;
115 return;
116 }
117#endif
118
119 /* Make sure we are in raw mode and start termcap mode. Might have side
120 * effects... */
121 settmode(TMODE_RAW);
122 starttermcap();
123
124 ++RedrawingDisabled; /* don't redisplay the window */
125 ++no_wait_return; /* don't wait for return */
126 did_emsg = FALSE; /* don't use error from debugged stuff */
127 cmd_silent = FALSE; /* display commands */
128 msg_silent = FALSE; /* display messages */
129 emsg_silent = FALSE; /* display error messages */
130 redir_off = TRUE; /* don't redirect debug commands */
131
132 State = NORMAL;
133#ifdef FEAT_SNIFF
134 want_sniff_request = 0; /* No K_SNIFF wanted */
135#endif
136
137 if (!debug_did_msg)
138 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
139 if (sourcing_name != NULL)
140 msg(sourcing_name);
141 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000142 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000144 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145
146 /*
147 * Repeat getting a command and executing it.
148 */
149 for (;;)
150 {
151 msg_scroll = TRUE;
152 need_wait_return = FALSE;
153#ifdef FEAT_SNIFF
154 ProcessSniffRequests();
155#endif
156 /* Save the current typeahead buffer and replace it with an empty one.
157 * This makes sure we get input from the user here and don't interfere
158 * with the commands being executed. Reset "ex_normal_busy" to avoid
159 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000160 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161# ifdef FEAT_EX_EXTRA
162 save_ex_normal_busy = ex_normal_busy;
163 ex_normal_busy = 0;
164# endif
165 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000166 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000168 typeahead_saved = TRUE;
169 save_ignore_script = ignore_script;
170 ignore_script = TRUE;
171 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000173 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000175 if (typeahead_saved)
176 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000178 ignore_script = save_ignore_script;
179 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180# ifdef FEAT_EX_EXTRA
181 ex_normal_busy = save_ex_normal_busy;
182# endif
183
184 cmdline_row = msg_row;
185 if (cmdline != NULL)
186 {
187 /* If this is a debug command, set "last_cmd".
188 * If not, reset "last_cmd".
189 * For a blank line use previous command. */
190 p = skipwhite(cmdline);
191 if (*p != NUL)
192 {
193 switch (*p)
194 {
195 case 'c': last_cmd = CMD_CONT;
196 tail = "ont";
197 break;
198 case 'n': last_cmd = CMD_NEXT;
199 tail = "ext";
200 break;
201 case 's': last_cmd = CMD_STEP;
202 tail = "tep";
203 break;
204 case 'f': last_cmd = CMD_FINISH;
205 tail = "inish";
206 break;
207 case 'q': last_cmd = CMD_QUIT;
208 tail = "uit";
209 break;
210 case 'i': last_cmd = CMD_INTERRUPT;
211 tail = "nterrupt";
212 break;
213 default: last_cmd = 0;
214 }
215 if (last_cmd != 0)
216 {
217 /* Check that the tail matches. */
218 ++p;
219 while (*p != NUL && *p == *tail)
220 {
221 ++p;
222 ++tail;
223 }
224 if (ASCII_ISALPHA(*p))
225 last_cmd = 0;
226 }
227 }
228
229 if (last_cmd != 0)
230 {
231 /* Execute debug command: decided where to break next and
232 * return. */
233 switch (last_cmd)
234 {
235 case CMD_CONT:
236 debug_break_level = -1;
237 break;
238 case CMD_NEXT:
239 debug_break_level = ex_nesting_level;
240 break;
241 case CMD_STEP:
242 debug_break_level = 9999;
243 break;
244 case CMD_FINISH:
245 debug_break_level = ex_nesting_level - 1;
246 break;
247 case CMD_QUIT:
248 got_int = TRUE;
249 debug_break_level = -1;
250 break;
251 case CMD_INTERRUPT:
252 got_int = TRUE;
253 debug_break_level = 9999;
254 /* Do not repeat ">interrupt" cmd, continue stepping. */
255 last_cmd = CMD_STEP;
256 break;
257 }
258 break;
259 }
260
261 /* don't debug this command */
262 n = debug_break_level;
263 debug_break_level = -1;
264 (void)do_cmdline(cmdline, getexline, NULL,
265 DOCMD_VERBOSE|DOCMD_EXCRESET);
266 debug_break_level = n;
267
268 vim_free(cmdline);
269 }
270 lines_left = Rows - 1;
271 }
272 vim_free(cmdline);
273
274 --RedrawingDisabled;
275 --no_wait_return;
276 redraw_all_later(NOT_VALID);
277 need_wait_return = FALSE;
278 msg_scroll = save_msg_scroll;
279 lines_left = Rows - 1;
280 State = save_State;
281 did_emsg = save_did_emsg;
282 cmd_silent = save_cmd_silent;
283 msg_silent = save_msg_silent;
284 emsg_silent = save_emsg_silent;
285 redir_off = save_redir_off;
286
287 /* Only print the message again when typing a command before coming back
288 * here. */
289 debug_did_msg = TRUE;
290}
291
292/*
293 * ":debug".
294 */
295 void
296ex_debug(eap)
297 exarg_T *eap;
298{
299 int debug_break_level_save = debug_break_level;
300
301 debug_break_level = 9999;
302 do_cmdline_cmd(eap->arg);
303 debug_break_level = debug_break_level_save;
304}
305
306static char_u *debug_breakpoint_name = NULL;
307static linenr_T debug_breakpoint_lnum;
308
309/*
310 * When debugging or a breakpoint is set on a skipped command, no debug prompt
311 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
312 * debug_skipped_name is then set to the source name in the breakpoint case. If
313 * a skipped command decides itself that a debug prompt should be displayed, it
314 * can do so by calling dbg_check_skipped().
315 */
316static int debug_skipped;
317static char_u *debug_skipped_name;
318
319/*
320 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
321 * at or below the break level. But only when the line is actually
322 * executed. Return TRUE and set breakpoint_name for skipped commands that
323 * decide to execute something themselves.
324 * Called from do_one_cmd() before executing a command.
325 */
326 void
327dbg_check_breakpoint(eap)
328 exarg_T *eap;
329{
330 char_u *p;
331
332 debug_skipped = FALSE;
333 if (debug_breakpoint_name != NULL)
334 {
335 if (!eap->skip)
336 {
337 /* replace K_SNR with "<SNR>" */
338 if (debug_breakpoint_name[0] == K_SPECIAL
339 && debug_breakpoint_name[1] == KS_EXTRA
340 && debug_breakpoint_name[2] == (int)KE_SNR)
341 p = (char_u *)"<SNR>";
342 else
343 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000344 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
345 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000346 debug_breakpoint_name + (*p == NUL ? 0 : 3),
347 (long)debug_breakpoint_lnum);
348 debug_breakpoint_name = NULL;
349 do_debug(eap->cmd);
350 }
351 else
352 {
353 debug_skipped = TRUE;
354 debug_skipped_name = debug_breakpoint_name;
355 debug_breakpoint_name = NULL;
356 }
357 }
358 else if (ex_nesting_level <= debug_break_level)
359 {
360 if (!eap->skip)
361 do_debug(eap->cmd);
362 else
363 {
364 debug_skipped = TRUE;
365 debug_skipped_name = NULL;
366 }
367 }
368}
369
370/*
371 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
372 * set. Return TRUE when the debug mode is entered this time.
373 */
374 int
375dbg_check_skipped(eap)
376 exarg_T *eap;
377{
378 int prev_got_int;
379
380 if (debug_skipped)
381 {
382 /*
383 * Save the value of got_int and reset it. We don't want a previous
384 * interruption cause flushing the input buffer.
385 */
386 prev_got_int = got_int;
387 got_int = FALSE;
388 debug_breakpoint_name = debug_skipped_name;
389 /* eap->skip is TRUE */
390 eap->skip = FALSE;
391 (void)dbg_check_breakpoint(eap);
392 eap->skip = TRUE;
393 got_int |= prev_got_int;
394 return TRUE;
395 }
396 return FALSE;
397}
398
399/*
400 * The list of breakpoints: dbg_breakp.
401 * This is a grow-array of structs.
402 */
403struct debuggy
404{
405 int dbg_nr; /* breakpoint number */
406 int dbg_type; /* DBG_FUNC or DBG_FILE */
407 char_u *dbg_name; /* function or file name */
408 regprog_T *dbg_prog; /* regexp program */
409 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000410 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000411};
412
413static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000414#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
415#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416static int last_breakp = 0; /* nr of last defined breakpoint */
417
Bram Moolenaar05159a02005-02-26 23:04:13 +0000418#ifdef FEAT_PROFILE
419/* Profiling uses file and func names similar to breakpoints. */
420static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
421#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422#define DBG_FUNC 1
423#define DBG_FILE 2
424
Bram Moolenaar05159a02005-02-26 23:04:13 +0000425static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
426static 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 +0000427
428/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000429 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
430 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
431 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 * Returns FAIL for failure.
433 */
434 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000435dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000436 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000437 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438{
439 char_u *p = arg;
440 char_u *q;
441 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000442 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443
Bram Moolenaar05159a02005-02-26 23:04:13 +0000444 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000445 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000446 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000447
448 /* Find "func" or "file". */
449 if (STRNCMP(p, "func", 4) == 0)
450 bp->dbg_type = DBG_FUNC;
451 else if (STRNCMP(p, "file", 4) == 0)
452 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000453 else if (
454#ifdef FEAT_PROFILE
455 gap != &prof_ga &&
456#endif
457 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000458 {
459 if (curbuf->b_ffname == NULL)
460 {
461 EMSG(_(e_noname));
462 return FAIL;
463 }
464 bp->dbg_type = DBG_FILE;
465 here = TRUE;
466 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000467 else
468 {
469 EMSG2(_(e_invarg2), p);
470 return FAIL;
471 }
472 p = skipwhite(p + 4);
473
474 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000475 if (here)
476 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000477 else if (
478#ifdef FEAT_PROFILE
479 gap != &prof_ga &&
480#endif
481 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000482 {
483 bp->dbg_lnum = getdigits(&p);
484 p = skipwhite(p);
485 }
486 else
487 bp->dbg_lnum = 0;
488
489 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000490 if ((!here && *p == NUL)
491 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000492 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
493 {
494 EMSG2(_(e_invarg2), arg);
495 return FAIL;
496 }
497
498 if (bp->dbg_type == DBG_FUNC)
499 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000500 else if (here)
501 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000502 else
503 {
504 /* Expand the file name in the same way as do_source(). This means
505 * doing it twice, so that $DIR/file gets expanded when $DIR is
506 * "~/dir". */
507#ifdef RISCOS
508 q = mch_munge_fname(p);
509#else
510 q = expand_env_save(p);
511#endif
512 if (q == NULL)
513 return FAIL;
514#ifdef RISCOS
515 p = mch_munge_fname(q);
516#else
517 p = expand_env_save(q);
518#endif
519 vim_free(q);
520 if (p == NULL)
521 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000522 if (*p != '*')
523 {
524 bp->dbg_name = fix_fname(p);
525 vim_free(p);
526 }
527 else
528 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529 }
530
531 if (bp->dbg_name == NULL)
532 return FAIL;
533 return OK;
534}
535
536/*
537 * ":breakadd".
538 */
539 void
540ex_breakadd(eap)
541 exarg_T *eap;
542{
543 struct debuggy *bp;
544 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000545 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546
Bram Moolenaar05159a02005-02-26 23:04:13 +0000547 gap = &dbg_breakp;
548#ifdef FEAT_PROFILE
549 if (eap->cmdidx == CMD_profile)
550 gap = &prof_ga;
551#endif
552
553 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000555 bp = &DEBUGGY(gap, gap->ga_len);
556 bp->dbg_forceit = eap->forceit;
557
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
559 if (pat != NULL)
560 {
561 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
562 vim_free(pat);
563 }
564 if (pat == NULL || bp->dbg_prog == NULL)
565 vim_free(bp->dbg_name);
566 else
567 {
568 if (bp->dbg_lnum == 0) /* default line number is 1 */
569 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000570#ifdef FEAT_PROFILE
571 if (eap->cmdidx != CMD_profile)
572#endif
573 {
574 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
575 ++debug_tick;
576 }
577 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578 }
579 }
580}
581
582/*
583 * ":debuggreedy".
584 */
585 void
586ex_debuggreedy(eap)
587 exarg_T *eap;
588{
589 if (eap->addr_count == 0 || eap->line2 != 0)
590 debug_greedy = TRUE;
591 else
592 debug_greedy = FALSE;
593}
594
595/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000596 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 */
598 void
599ex_breakdel(eap)
600 exarg_T *eap;
601{
602 struct debuggy *bp, *bpi;
603 int nr;
604 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000605 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606 int i;
607 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000608 garray_T *gap;
609
610 gap = &dbg_breakp;
611#ifdef FEAT_PROFILE
612 if (eap->cmdidx == CMD_profdel)
613 gap = &prof_ga;
614#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615
616 if (vim_isdigit(*eap->arg))
617 {
618 /* ":breakdel {nr}" */
619 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000620 for (i = 0; i < gap->ga_len; ++i)
621 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 {
623 todel = i;
624 break;
625 }
626 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000627 else if (*eap->arg == '*')
628 {
629 todel = 0;
630 del_all = TRUE;
631 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 else
633 {
634 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000635 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000636 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000637 bp = &DEBUGGY(gap, gap->ga_len);
638 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000639 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000640 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641 if (bp->dbg_type == bpi->dbg_type
642 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
643 && (bp->dbg_lnum == bpi->dbg_lnum
644 || (bp->dbg_lnum == 0
645 && (best_lnum == 0
646 || bpi->dbg_lnum < best_lnum))))
647 {
648 todel = i;
649 best_lnum = bpi->dbg_lnum;
650 }
651 }
652 vim_free(bp->dbg_name);
653 }
654
655 if (todel < 0)
656 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
657 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000658 {
659 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000660 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000661 vim_free(DEBUGGY(gap, todel).dbg_name);
662 vim_free(DEBUGGY(gap, todel).dbg_prog);
663 --gap->ga_len;
664 if (todel < gap->ga_len)
665 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
666 (gap->ga_len - todel) * sizeof(struct debuggy));
667#ifdef FEAT_PROFILE
668 if (eap->cmdidx == CMD_breakdel)
669#endif
670 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000671 if (!del_all)
672 break;
673 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000674
675 /* If all breakpoints were removed clear the array. */
676 if (gap->ga_len == 0)
677 ga_clear(gap);
678 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679}
680
681/*
682 * ":breaklist".
683 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000684 void
685ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000686 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687{
688 struct debuggy *bp;
689 int i;
690
691 if (dbg_breakp.ga_len == 0)
692 MSG(_("No breakpoints defined"));
693 else
694 for (i = 0; i < dbg_breakp.ga_len; ++i)
695 {
696 bp = &BREAKP(i);
697 smsg((char_u *)_("%3d %s %s line %ld"),
698 bp->dbg_nr,
699 bp->dbg_type == DBG_FUNC ? "func" : "file",
700 bp->dbg_name,
701 (long)bp->dbg_lnum);
702 }
703}
704
705/*
706 * Find a breakpoint for a function or sourced file.
707 * Returns line number at which to break; zero when no matching breakpoint.
708 */
709 linenr_T
710dbg_find_breakpoint(file, fname, after)
711 int file; /* TRUE for a file, FALSE for a function */
712 char_u *fname; /* file or function name */
713 linenr_T after; /* after this line number */
714{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000715 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
716}
717
718#if defined(FEAT_PROFILE) || defined(PROTO)
719/*
720 * Return TRUE if profiling is on for a function or sourced file.
721 */
722 int
723has_profiling(file, fname, fp)
724 int file; /* TRUE for a file, FALSE for a function */
725 char_u *fname; /* file or function name */
726 int *fp; /* return: forceit */
727{
728 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
729 != (linenr_T)0);
730}
731#endif
732
733/*
734 * Common code for dbg_find_breakpoint() and has_profiling().
735 */
736 static linenr_T
737debuggy_find(file, fname, after, gap, fp)
738 int file; /* TRUE for a file, FALSE for a function */
739 char_u *fname; /* file or function name */
740 linenr_T after; /* after this line number */
741 garray_T *gap; /* either &dbg_breakp or &prof_ga */
742 int *fp; /* if not NULL: return forceit */
743{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000744 struct debuggy *bp;
745 int i;
746 linenr_T lnum = 0;
747 regmatch_T regmatch;
748 char_u *name = fname;
749 int prev_got_int;
750
Bram Moolenaar05159a02005-02-26 23:04:13 +0000751 /* Return quickly when there are no breakpoints. */
752 if (gap->ga_len == 0)
753 return (linenr_T)0;
754
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755 /* Replace K_SNR in function name with "<SNR>". */
756 if (!file && fname[0] == K_SPECIAL)
757 {
758 name = alloc((unsigned)STRLEN(fname) + 3);
759 if (name == NULL)
760 name = fname;
761 else
762 {
763 STRCPY(name, "<SNR>");
764 STRCPY(name + 5, fname + 3);
765 }
766 }
767
Bram Moolenaar05159a02005-02-26 23:04:13 +0000768 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000770 /* Skip entries that are not useful or are for a line that is beyond
771 * an already found breakpoint. */
772 bp = &DEBUGGY(gap, i);
773 if (((bp->dbg_type == DBG_FILE) == file && (
774#ifdef FEAT_PROFILE
775 gap == &prof_ga ||
776#endif
777 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778 {
779 regmatch.regprog = bp->dbg_prog;
780 regmatch.rm_ic = FALSE;
781 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000782 * Save the value of got_int and reset it. We don't want a
783 * previous interruption cancel matching, only hitting CTRL-C
784 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 */
786 prev_got_int = got_int;
787 got_int = FALSE;
788 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000789 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000791 if (fp != NULL)
792 *fp = bp->dbg_forceit;
793 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794 got_int |= prev_got_int;
795 }
796 }
797 if (name != fname)
798 vim_free(name);
799
800 return lnum;
801}
802
803/*
804 * Called when a breakpoint was encountered.
805 */
806 void
807dbg_breakpoint(name, lnum)
808 char_u *name;
809 linenr_T lnum;
810{
811 /* We need to check if this line is actually executed in do_one_cmd() */
812 debug_breakpoint_name = name;
813 debug_breakpoint_lnum = lnum;
814}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000815
816
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000817# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000818/*
819 * Store the current time in "tm".
820 */
821 void
822profile_start(tm)
823 proftime_T *tm;
824{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000825# ifdef WIN3264
826 QueryPerformanceCounter(tm);
827# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000828 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000829# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000830}
831
832/*
833 * Compute the elapsed time from "tm" till now and store in "tm".
834 */
835 void
836profile_end(tm)
837 proftime_T *tm;
838{
839 proftime_T now;
840
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000841# ifdef WIN3264
842 QueryPerformanceCounter(&now);
843 tm->QuadPart = now.QuadPart - tm->QuadPart;
844# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845 gettimeofday(&now, NULL);
846 tm->tv_usec = now.tv_usec - tm->tv_usec;
847 tm->tv_sec = now.tv_sec - tm->tv_sec;
848 if (tm->tv_usec < 0)
849 {
850 tm->tv_usec += 1000000;
851 --tm->tv_sec;
852 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000853# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000854}
855
856/*
857 * Subtract the time "tm2" from "tm".
858 */
859 void
860profile_sub(tm, tm2)
861 proftime_T *tm, *tm2;
862{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000863# ifdef WIN3264
864 tm->QuadPart -= tm2->QuadPart;
865# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000866 tm->tv_usec -= tm2->tv_usec;
867 tm->tv_sec -= tm2->tv_sec;
868 if (tm->tv_usec < 0)
869 {
870 tm->tv_usec += 1000000;
871 --tm->tv_sec;
872 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000873# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000874}
875
876/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000877 * Return a string that represents the time in "tm".
878 * Uses a static buffer!
879 */
880 char *
881profile_msg(tm)
882 proftime_T *tm;
883{
884 static char buf[50];
885
886# ifdef WIN3264
887 LARGE_INTEGER fr;
888
889 QueryPerformanceFrequency(&fr);
890 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
891# else
892 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000893# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000894 return buf;
895}
896
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000897/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000898 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000899 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000900 void
901profile_setlimit(msec, tm)
902 long msec;
903 proftime_T *tm;
904{
905 if (msec <= 0) /* no limit */
906 profile_zero(tm);
907 else
908 {
909# ifdef WIN3264
910 LARGE_INTEGER fr;
911
912 QueryPerformanceCounter(tm);
913 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000914 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000915# else
916 long usec;
917
918 gettimeofday(tm, NULL);
919 usec = (long)tm->tv_usec + (long)msec * 1000;
920 tm->tv_usec = usec % 1000000L;
921 tm->tv_sec += usec / 1000000L;
922# endif
923 }
924}
925
926/*
927 * Return TRUE if the current time is past "tm".
928 */
929 int
930profile_passed_limit(tm)
931 proftime_T *tm;
932{
933 proftime_T now;
934
935# ifdef WIN3264
936 if (tm->QuadPart == 0) /* timer was not set */
937 return FALSE;
938 QueryPerformanceCounter(&now);
939 return (now.QuadPart > tm->QuadPart);
940# else
941 if (tm->tv_sec == 0) /* timer was not set */
942 return FALSE;
943 gettimeofday(&now, NULL);
944 return (now.tv_sec > tm->tv_sec
945 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
946# endif
947}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000948
949/*
950 * Set the time in "tm" to zero.
951 */
952 void
953profile_zero(tm)
954 proftime_T *tm;
955{
956# ifdef WIN3264
957 tm->QuadPart = 0;
958# else
959 tm->tv_usec = 0;
960 tm->tv_sec = 0;
961# endif
962}
963
Bram Moolenaar76929292008-01-06 19:07:36 +0000964# endif /* FEAT_PROFILE || FEAT_RELTIME */
965
966# if defined(FEAT_PROFILE) || defined(PROTO)
967/*
968 * Functions for profiling.
969 */
970static void script_do_profile __ARGS((scriptitem_T *si));
971static void script_dump_profile __ARGS((FILE *fd));
972static proftime_T prof_wait_time;
973
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000974/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000975 * Add the time "tm2" to "tm".
976 */
977 void
978profile_add(tm, tm2)
979 proftime_T *tm, *tm2;
980{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000981# ifdef WIN3264
982 tm->QuadPart += tm2->QuadPart;
983# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000984 tm->tv_usec += tm2->tv_usec;
985 tm->tv_sec += tm2->tv_sec;
986 if (tm->tv_usec >= 1000000)
987 {
988 tm->tv_usec -= 1000000;
989 ++tm->tv_sec;
990 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000991# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000992}
993
994/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000995 * Add the "self" time from the total time and the children's time.
996 */
997 void
998profile_self(self, total, children)
999 proftime_T *self, *total, *children;
1000{
1001 /* Check that the result won't be negative. Can happen with recursive
1002 * calls. */
1003#ifdef WIN3264
1004 if (total->QuadPart <= children->QuadPart)
1005 return;
1006#else
1007 if (total->tv_sec < children->tv_sec
1008 || (total->tv_sec == children->tv_sec
1009 && total->tv_usec <= children->tv_usec))
1010 return;
1011#endif
1012 profile_add(self, total);
1013 profile_sub(self, children);
1014}
1015
1016/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001017 * Get the current waittime.
1018 */
1019 void
1020profile_get_wait(tm)
1021 proftime_T *tm;
1022{
1023 *tm = prof_wait_time;
1024}
1025
1026/*
1027 * Subtract the passed waittime since "tm" from "tma".
1028 */
1029 void
1030profile_sub_wait(tm, tma)
1031 proftime_T *tm, *tma;
1032{
1033 proftime_T tm3 = prof_wait_time;
1034
1035 profile_sub(&tm3, tm);
1036 profile_sub(tma, &tm3);
1037}
1038
1039/*
1040 * Return TRUE if "tm1" and "tm2" are equal.
1041 */
1042 int
1043profile_equal(tm1, tm2)
1044 proftime_T *tm1, *tm2;
1045{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001046# ifdef WIN3264
1047 return (tm1->QuadPart == tm2->QuadPart);
1048# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001049 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001050# endif
1051}
1052
1053/*
1054 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1055 */
1056 int
1057profile_cmp(tm1, tm2)
1058 proftime_T *tm1, *tm2;
1059{
1060# ifdef WIN3264
1061 return (int)(tm2->QuadPart - tm1->QuadPart);
1062# else
1063 if (tm1->tv_sec == tm2->tv_sec)
1064 return tm2->tv_usec - tm1->tv_usec;
1065 return tm2->tv_sec - tm1->tv_sec;
1066# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001067}
1068
Bram Moolenaar05159a02005-02-26 23:04:13 +00001069static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001070static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001071
1072/*
1073 * ":profile cmd args"
1074 */
1075 void
1076ex_profile(eap)
1077 exarg_T *eap;
1078{
1079 char_u *e;
1080 int len;
1081
1082 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001083 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001084 e = skipwhite(e);
1085
1086 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1087 {
1088 vim_free(profile_fname);
1089 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001090 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001091 profile_zero(&prof_wait_time);
1092 set_vim_var_nr(VV_PROFILING, 1L);
1093 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001094 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001095 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001096 else if (STRCMP(eap->arg, "pause") == 0)
1097 {
1098 if (do_profiling == PROF_YES)
1099 profile_start(&pause_time);
1100 do_profiling = PROF_PAUSED;
1101 }
1102 else if (STRCMP(eap->arg, "continue") == 0)
1103 {
1104 if (do_profiling == PROF_PAUSED)
1105 {
1106 profile_end(&pause_time);
1107 profile_add(&prof_wait_time, &pause_time);
1108 }
1109 do_profiling = PROF_YES;
1110 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001111 else
1112 {
1113 /* The rest is similar to ":breakadd". */
1114 ex_breakadd(eap);
1115 }
1116}
1117
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001118/* Command line expansion for :profile. */
1119static enum
1120{
1121 PEXP_SUBCMD, /* expand :profile sub-commands */
1122 PEXP_FUNC, /* expand :profile func {funcname} */
1123} pexpand_what;
1124
1125static char *pexpand_cmds[] = {
1126 "start",
1127#define PROFCMD_START 0
1128 "pause",
1129#define PROFCMD_PAUSE 1
1130 "continue",
1131#define PROFCMD_CONTINUE 2
1132 "func",
1133#define PROFCMD_FUNC 3
1134 "file",
1135#define PROFCMD_FILE 4
1136 NULL
1137#define PROFCMD_LAST 5
1138};
1139
1140/*
1141 * Function given to ExpandGeneric() to obtain the profile command
1142 * specific expansion.
1143 */
1144 char_u *
1145get_profile_name(xp, idx)
1146 expand_T *xp UNUSED;
1147 int idx;
1148{
1149 switch (pexpand_what)
1150 {
1151 case PEXP_SUBCMD:
1152 return (char_u *)pexpand_cmds[idx];
1153 /* case PEXP_FUNC: TODO */
1154 default:
1155 return NULL;
1156 }
1157}
1158
1159/*
1160 * Handle command line completion for :profile command.
1161 */
1162 void
1163set_context_in_profile_cmd(xp, arg)
1164 expand_T *xp;
1165 char_u *arg;
1166{
1167 char_u *end_subcmd;
1168 int len;
1169
1170 /* Default: expand subcommands. */
1171 xp->xp_context = EXPAND_PROFILE;
1172 pexpand_what = PEXP_SUBCMD;
1173 xp->xp_pattern = arg;
1174
1175 end_subcmd = skiptowhite(arg);
1176 if (*end_subcmd == NUL)
1177 return;
1178
1179 len = end_subcmd - arg;
1180 if (len == 5 && STRNCMP(arg, "start", 5) == 0)
1181 {
1182 xp->xp_context = EXPAND_FILES;
1183 xp->xp_pattern = skipwhite(end_subcmd);
1184 return;
1185 }
1186
1187 /* TODO: expand function names after "func" */
1188 xp->xp_context = EXPAND_NOTHING;
1189}
1190
Bram Moolenaar05159a02005-02-26 23:04:13 +00001191/*
1192 * Dump the profiling info.
1193 */
1194 void
1195profile_dump()
1196{
1197 FILE *fd;
1198
1199 if (profile_fname != NULL)
1200 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001201 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001202 if (fd == NULL)
1203 EMSG2(_(e_notopen), profile_fname);
1204 else
1205 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001206 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001207 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001208 fclose(fd);
1209 }
1210 }
1211}
1212
1213/*
1214 * Start profiling script "fp".
1215 */
1216 static void
1217script_do_profile(si)
1218 scriptitem_T *si;
1219{
1220 si->sn_pr_count = 0;
1221 profile_zero(&si->sn_pr_total);
1222 profile_zero(&si->sn_pr_self);
1223
1224 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1225 si->sn_prl_idx = -1;
1226 si->sn_prof_on = TRUE;
1227 si->sn_pr_nest = 0;
1228}
1229
1230/*
1231 * save time when starting to invoke another script or function.
1232 */
1233 void
1234script_prof_save(tm)
1235 proftime_T *tm; /* place to store wait time */
1236{
1237 scriptitem_T *si;
1238
1239 if (current_SID > 0 && current_SID <= script_items.ga_len)
1240 {
1241 si = &SCRIPT_ITEM(current_SID);
1242 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1243 profile_start(&si->sn_pr_child);
1244 }
1245 profile_get_wait(tm);
1246}
1247
1248/*
1249 * Count time spent in children after invoking another script or function.
1250 */
1251 void
1252script_prof_restore(tm)
1253 proftime_T *tm;
1254{
1255 scriptitem_T *si;
1256
1257 if (current_SID > 0 && current_SID <= script_items.ga_len)
1258 {
1259 si = &SCRIPT_ITEM(current_SID);
1260 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1261 {
1262 profile_end(&si->sn_pr_child);
1263 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1264 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1265 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1266 }
1267 }
1268}
1269
1270static proftime_T inchar_time;
1271
1272/*
1273 * Called when starting to wait for the user to type a character.
1274 */
1275 void
1276prof_inchar_enter()
1277{
1278 profile_start(&inchar_time);
1279}
1280
1281/*
1282 * Called when finished waiting for the user to type a character.
1283 */
1284 void
1285prof_inchar_exit()
1286{
1287 profile_end(&inchar_time);
1288 profile_add(&prof_wait_time, &inchar_time);
1289}
1290
1291/*
1292 * Dump the profiling results for all scripts in file "fd".
1293 */
1294 static void
1295script_dump_profile(fd)
1296 FILE *fd;
1297{
1298 int id;
1299 scriptitem_T *si;
1300 int i;
1301 FILE *sfd;
1302 sn_prl_T *pp;
1303
1304 for (id = 1; id <= script_items.ga_len; ++id)
1305 {
1306 si = &SCRIPT_ITEM(id);
1307 if (si->sn_prof_on)
1308 {
1309 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1310 if (si->sn_pr_count == 1)
1311 fprintf(fd, "Sourced 1 time\n");
1312 else
1313 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1314 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1315 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1316 fprintf(fd, "\n");
1317 fprintf(fd, "count total (s) self (s)\n");
1318
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001319 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001320 if (sfd == NULL)
1321 fprintf(fd, "Cannot open file!\n");
1322 else
1323 {
1324 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1325 {
1326 if (vim_fgets(IObuff, IOSIZE, sfd))
1327 break;
1328 pp = &PRL_ITEM(si, i);
1329 if (pp->snp_count > 0)
1330 {
1331 fprintf(fd, "%5d ", pp->snp_count);
1332 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1333 fprintf(fd, " ");
1334 else
1335 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1336 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1337 }
1338 else
1339 fprintf(fd, " ");
1340 fprintf(fd, "%s", IObuff);
1341 }
1342 fclose(sfd);
1343 }
1344 fprintf(fd, "\n");
1345 }
1346 }
1347}
1348
1349/*
1350 * Return TRUE when a function defined in the current script should be
1351 * profiled.
1352 */
1353 int
1354prof_def_func()
1355{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001356 if (current_SID > 0)
1357 return SCRIPT_ITEM(current_SID).sn_pr_force;
1358 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001359}
1360
1361# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001362#endif
1363
1364/*
1365 * If 'autowrite' option set, try to write the file.
1366 * Careful: autocommands may make "buf" invalid!
1367 *
1368 * return FAIL for failure, OK otherwise
1369 */
1370 int
1371autowrite(buf, forceit)
1372 buf_T *buf;
1373 int forceit;
1374{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001375 int r;
1376
Bram Moolenaar071d4272004-06-13 20:20:40 +00001377 if (!(p_aw || p_awa) || !p_write
1378#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001379 /* never autowrite a "nofile" or "nowrite" buffer */
1380 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001381#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001382 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001384 r = buf_write_all(buf, forceit);
1385
1386 /* Writing may succeed but the buffer still changed, e.g., when there is a
1387 * conversion error. We do want to return FAIL then. */
1388 if (buf_valid(buf) && bufIsChanged(buf))
1389 r = FAIL;
1390 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001391}
1392
1393/*
1394 * flush all buffers, except the ones that are readonly
1395 */
1396 void
1397autowrite_all()
1398{
1399 buf_T *buf;
1400
1401 if (!(p_aw || p_awa) || !p_write)
1402 return;
1403 for (buf = firstbuf; buf; buf = buf->b_next)
1404 if (bufIsChanged(buf) && !buf->b_p_ro)
1405 {
1406 (void)buf_write_all(buf, FALSE);
1407#ifdef FEAT_AUTOCMD
1408 /* an autocommand may have deleted the buffer */
1409 if (!buf_valid(buf))
1410 buf = firstbuf;
1411#endif
1412 }
1413}
1414
1415/*
1416 * return TRUE if buffer was changed and cannot be abandoned.
1417 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001418 int
1419check_changed(buf, checkaw, mult_win, forceit, allbuf)
1420 buf_T *buf;
1421 int checkaw; /* do autowrite if buffer was changed */
1422 int mult_win; /* check also when several wins for the buf */
1423 int forceit;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001424 int allbuf UNUSED; /* may write all buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425{
1426 if ( !forceit
1427 && bufIsChanged(buf)
1428 && (mult_win || buf->b_nwindows <= 1)
1429 && (!checkaw || autowrite(buf, forceit) == FAIL))
1430 {
1431#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1432 if ((p_confirm || cmdmod.confirm) && p_write)
1433 {
1434 buf_T *buf2;
1435 int count = 0;
1436
1437 if (allbuf)
1438 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1439 if (bufIsChanged(buf2)
1440 && (buf2->b_ffname != NULL
1441# ifdef FEAT_BROWSE
1442 || cmdmod.browse
1443# endif
1444 ))
1445 ++count;
1446# ifdef FEAT_AUTOCMD
1447 if (!buf_valid(buf))
1448 /* Autocommand deleted buffer, oops! It's not changed now. */
1449 return FALSE;
1450# endif
1451 dialog_changed(buf, count > 1);
1452# ifdef FEAT_AUTOCMD
1453 if (!buf_valid(buf))
1454 /* Autocommand deleted buffer, oops! It's not changed now. */
1455 return FALSE;
1456# endif
1457 return bufIsChanged(buf);
1458 }
1459#endif
1460 EMSG(_(e_nowrtmsg));
1461 return TRUE;
1462 }
1463 return FALSE;
1464}
1465
1466#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1467
1468#if defined(FEAT_BROWSE) || defined(PROTO)
1469/*
1470 * When wanting to write a file without a file name, ask the user for a name.
1471 */
1472 void
1473browse_save_fname(buf)
1474 buf_T *buf;
1475{
1476 if (buf->b_fname == NULL)
1477 {
1478 char_u *fname;
1479
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001480 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1481 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001482 if (fname != NULL)
1483 {
1484 if (setfname(buf, fname, NULL, TRUE) == OK)
1485 buf->b_flags |= BF_NOTEDITED;
1486 vim_free(fname);
1487 }
1488 }
1489}
1490#endif
1491
1492/*
1493 * Ask the user what to do when abondoning a changed buffer.
1494 * Must check 'write' option first!
1495 */
1496 void
1497dialog_changed(buf, checkall)
1498 buf_T *buf;
1499 int checkall; /* may abandon all changed buffers */
1500{
1501 char_u buff[IOSIZE];
1502 int ret;
1503 buf_T *buf2;
1504
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001505 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001506 (buf->b_fname != NULL) ?
1507 buf->b_fname : (char_u *)_("Untitled"));
1508 if (checkall)
1509 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1510 else
1511 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1512
1513 if (ret == VIM_YES)
1514 {
1515#ifdef FEAT_BROWSE
1516 /* May get file name, when there is none */
1517 browse_save_fname(buf);
1518#endif
1519 if (buf->b_fname != NULL) /* didn't hit Cancel */
1520 (void)buf_write_all(buf, FALSE);
1521 }
1522 else if (ret == VIM_NO)
1523 {
1524 unchanged(buf, TRUE);
1525 }
1526 else if (ret == VIM_ALL)
1527 {
1528 /*
1529 * Write all modified files that can be written.
1530 * Skip readonly buffers, these need to be confirmed
1531 * individually.
1532 */
1533 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1534 {
1535 if (bufIsChanged(buf2)
1536 && (buf2->b_ffname != NULL
1537#ifdef FEAT_BROWSE
1538 || cmdmod.browse
1539#endif
1540 )
1541 && !buf2->b_p_ro)
1542 {
1543#ifdef FEAT_BROWSE
1544 /* May get file name, when there is none */
1545 browse_save_fname(buf2);
1546#endif
1547 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1548 (void)buf_write_all(buf2, FALSE);
1549#ifdef FEAT_AUTOCMD
1550 /* an autocommand may have deleted the buffer */
1551 if (!buf_valid(buf2))
1552 buf2 = firstbuf;
1553#endif
1554 }
1555 }
1556 }
1557 else if (ret == VIM_DISCARDALL)
1558 {
1559 /*
1560 * mark all buffers as unchanged
1561 */
1562 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1563 unchanged(buf2, TRUE);
1564 }
1565}
1566#endif
1567
1568/*
1569 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1570 * hidden, autowriting it or unloading it.
1571 */
1572 int
1573can_abandon(buf, forceit)
1574 buf_T *buf;
1575 int forceit;
1576{
1577 return ( P_HID(buf)
1578 || !bufIsChanged(buf)
1579 || buf->b_nwindows > 1
1580 || autowrite(buf, forceit) == OK
1581 || forceit);
1582}
1583
1584/*
1585 * Return TRUE if any buffer was changed and cannot be abandoned.
1586 * That changed buffer becomes the current buffer.
1587 */
1588 int
1589check_changed_any(hidden)
1590 int hidden; /* Only check hidden buffers */
1591{
1592 buf_T *buf;
1593 int save;
1594#ifdef FEAT_WINDOWS
1595 win_T *wp;
1596#endif
1597
1598 for (;;)
1599 {
1600 /* check curbuf first: if it was changed we can't abandon it */
1601 if (!hidden && curbufIsChanged())
1602 buf = curbuf;
1603 else
1604 {
1605 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1606 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1607 break;
1608 }
1609 if (buf == NULL) /* No buffers changed */
1610 return FALSE;
1611
Bram Moolenaar373154b2007-02-13 05:19:30 +00001612 /* Try auto-writing the buffer. If this fails but the buffer no
1613 * longer exists it's not changed, that's OK. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1615 break; /* didn't save - still changes */
1616 }
1617
1618 exiting = FALSE;
1619#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1620 /*
1621 * When ":confirm" used, don't give an error message.
1622 */
1623 if (!(p_confirm || cmdmod.confirm))
1624#endif
1625 {
1626 /* There must be a wait_return for this message, do_buffer()
1627 * may cause a redraw. But wait_return() is a no-op when vgetc()
1628 * is busy (Quit used from window menu), then make sure we don't
1629 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001630 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001631 {
1632 msg_row = cmdline_row;
1633 msg_col = 0;
1634 msg_didout = FALSE;
1635 }
1636 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1637 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1638 buf->b_fname))
1639 {
1640 save = no_wait_return;
1641 no_wait_return = FALSE;
1642 wait_return(FALSE);
1643 no_wait_return = save;
1644 }
1645 }
1646
1647#ifdef FEAT_WINDOWS
1648 /* Try to find a window that contains the buffer. */
1649 if (buf != curbuf)
1650 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1651 if (wp->w_buffer == buf)
1652 {
1653 win_goto(wp);
1654# ifdef FEAT_AUTOCMD
1655 /* Paranoia: did autocms wipe out the buffer with changes? */
1656 if (!buf_valid(buf))
1657 return TRUE;
1658# endif
1659 break;
1660 }
1661#endif
1662
1663 /* Open the changed buffer in the current window. */
1664 if (buf != curbuf)
1665 set_curbuf(buf, DOBUF_GOTO);
1666
1667 return TRUE;
1668}
1669
1670/*
1671 * return FAIL if there is no file name, OK if there is one
1672 * give error message for FAIL
1673 */
1674 int
1675check_fname()
1676{
1677 if (curbuf->b_ffname == NULL)
1678 {
1679 EMSG(_(e_noname));
1680 return FAIL;
1681 }
1682 return OK;
1683}
1684
1685/*
1686 * flush the contents of a buffer, unless it has no file name
1687 *
1688 * return FAIL for failure, OK otherwise
1689 */
1690 int
1691buf_write_all(buf, forceit)
1692 buf_T *buf;
1693 int forceit;
1694{
1695 int retval;
1696#ifdef FEAT_AUTOCMD
1697 buf_T *old_curbuf = curbuf;
1698#endif
1699
1700 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1701 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1702 FALSE, forceit, TRUE, FALSE));
1703#ifdef FEAT_AUTOCMD
1704 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001705 {
1706 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001707 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001708 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001709#endif
1710 return retval;
1711}
1712
1713/*
1714 * Code to handle the argument list.
1715 */
1716
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001717static char_u *do_one_arg __ARGS((char_u *str));
1718static int do_arglist __ARGS((char_u *str, int what, int after));
1719static void alist_check_arg_idx __ARGS((void));
1720static int editing_arg_idx __ARGS((win_T *win));
1721#ifdef FEAT_LISTCMDS
1722static int alist_add_list __ARGS((int count, char_u **files, int after));
1723#endif
1724#define AL_SET 1
1725#define AL_ADD 2
1726#define AL_DEL 3
1727
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001729 * Isolate one argument, taking backticks.
1730 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001731 * Return a pointer to the start of the next argument.
1732 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001733 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734do_one_arg(str)
1735 char_u *str;
1736{
1737 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738 int inbacktick;
1739
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 inbacktick = FALSE;
1741 for (p = str; *str; ++str)
1742 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001743 /* When the backslash is used for escaping the special meaning of a
1744 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745 if (rem_backslash(str))
1746 {
1747 *p++ = *str++;
1748 *p++ = *str;
1749 }
1750 else
1751 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001752 /* An item ends at a space not in backticks */
1753 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001754 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001755 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001757 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001758 }
1759 }
1760 str = skipwhite(str);
1761 *p = NUL;
1762
1763 return str;
1764}
1765
Bram Moolenaar86b68352004-12-27 21:59:20 +00001766/*
1767 * Separate the arguments in "str" and return a list of pointers in the
1768 * growarray "gap".
1769 */
1770 int
1771get_arglist(gap, str)
1772 garray_T *gap;
1773 char_u *str;
1774{
1775 ga_init2(gap, (int)sizeof(char_u *), 20);
1776 while (*str != NUL)
1777 {
1778 if (ga_grow(gap, 1) == FAIL)
1779 {
1780 ga_clear(gap);
1781 return FAIL;
1782 }
1783 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1784
1785 /* Isolate one argument, change it in-place, put a NUL after it. */
1786 str = do_one_arg(str);
1787 }
1788 return OK;
1789}
1790
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001791#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001792/*
1793 * Parse a list of arguments (file names), expand them and return in
1794 * "fnames[fcountp]".
1795 * Return FAIL or OK.
1796 */
1797 int
1798get_arglist_exp(str, fcountp, fnamesp)
1799 char_u *str;
1800 int *fcountp;
1801 char_u ***fnamesp;
1802{
1803 garray_T ga;
1804 int i;
1805
1806 if (get_arglist(&ga, str) == FAIL)
1807 return FAIL;
1808 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1809 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1810 ga_clear(&ga);
1811 return i;
1812}
1813#endif
1814
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1816/*
1817 * Redefine the argument list.
1818 */
1819 void
1820set_arglist(str)
1821 char_u *str;
1822{
1823 do_arglist(str, AL_SET, 0);
1824}
1825#endif
1826
1827/*
1828 * "what" == AL_SET: Redefine the argument list to 'str'.
1829 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1830 * "what" == AL_DEL: remove files in 'str' from the argument list.
1831 *
1832 * Return FAIL for failure, OK otherwise.
1833 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001834 static int
1835do_arglist(str, what, after)
1836 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001837 int what UNUSED;
1838 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839{
1840 garray_T new_ga;
1841 int exp_count;
1842 char_u **exp_files;
1843 int i;
1844#ifdef FEAT_LISTCMDS
1845 char_u *p;
1846 int match;
1847#endif
1848
1849 /*
1850 * Collect all file name arguments in "new_ga".
1851 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001852 if (get_arglist(&new_ga, str) == FAIL)
1853 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854
1855#ifdef FEAT_LISTCMDS
1856 if (what == AL_DEL)
1857 {
1858 regmatch_T regmatch;
1859 int didone;
1860
1861 /*
1862 * Delete the items: use each item as a regexp and find a match in the
1863 * argument list.
1864 */
1865#ifdef CASE_INSENSITIVE_FILENAME
1866 regmatch.rm_ic = TRUE; /* Always ignore case */
1867#else
1868 regmatch.rm_ic = FALSE; /* Never ignore case */
1869#endif
1870 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1871 {
1872 p = ((char_u **)new_ga.ga_data)[i];
1873 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1874 if (p == NULL)
1875 break;
1876 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1877 if (regmatch.regprog == NULL)
1878 {
1879 vim_free(p);
1880 break;
1881 }
1882
1883 didone = FALSE;
1884 for (match = 0; match < ARGCOUNT; ++match)
1885 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1886 (colnr_T)0))
1887 {
1888 didone = TRUE;
1889 vim_free(ARGLIST[match].ae_fname);
1890 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1891 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1892 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 if (curwin->w_arg_idx > match)
1894 --curwin->w_arg_idx;
1895 --match;
1896 }
1897
1898 vim_free(regmatch.regprog);
1899 vim_free(p);
1900 if (!didone)
1901 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1902 }
1903 ga_clear(&new_ga);
1904 }
1905 else
1906#endif
1907 {
1908 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1909 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1910 ga_clear(&new_ga);
1911 if (i == FAIL)
1912 return FAIL;
1913 if (exp_count == 0)
1914 {
1915 EMSG(_(e_nomatch));
1916 return FAIL;
1917 }
1918
1919#ifdef FEAT_LISTCMDS
1920 if (what == AL_ADD)
1921 {
1922 (void)alist_add_list(exp_count, exp_files, after);
1923 vim_free(exp_files);
1924 }
1925 else /* what == AL_SET */
1926#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001927 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 }
1929
1930 alist_check_arg_idx();
1931
1932 return OK;
1933}
1934
1935/*
1936 * Check the validity of the arg_idx for each other window.
1937 */
1938 static void
1939alist_check_arg_idx()
1940{
1941#ifdef FEAT_WINDOWS
1942 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001943 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944
Bram Moolenaarf740b292006-02-16 22:11:02 +00001945 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001946 if (win->w_alist == curwin->w_alist)
1947 check_arg_idx(win);
1948#else
1949 check_arg_idx(curwin);
1950#endif
1951}
1952
1953/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001954 * Return TRUE if window "win" is editing then file at the current argument
1955 * index.
1956 */
1957 static int
1958editing_arg_idx(win)
1959 win_T *win;
1960{
1961 return !(win->w_arg_idx >= WARGCOUNT(win)
1962 || (win->w_buffer->b_fnum
1963 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1964 && (win->w_buffer->b_ffname == NULL
1965 || !(fullpathcmp(
1966 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1967 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1968}
1969
1970/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971 * Check if window "win" is editing the w_arg_idx file in its argument list.
1972 */
1973 void
1974check_arg_idx(win)
1975 win_T *win;
1976{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001977 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001978 {
1979 /* We are not editing the current entry in the argument list.
1980 * Set "arg_had_last" if we are editing the last one. */
1981 win->w_arg_idx_invalid = TRUE;
1982 if (win->w_arg_idx != WARGCOUNT(win) - 1
1983 && arg_had_last == FALSE
1984#ifdef FEAT_WINDOWS
1985 && ALIST(win) == &global_alist
1986#endif
1987 && GARGCOUNT > 0
1988 && win->w_arg_idx < GARGCOUNT
1989 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1990 || (win->w_buffer->b_ffname != NULL
1991 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1992 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1993 arg_had_last = TRUE;
1994 }
1995 else
1996 {
1997 /* We are editing the current entry in the argument list.
1998 * Set "arg_had_last" if it's also the last one */
1999 win->w_arg_idx_invalid = FALSE;
2000 if (win->w_arg_idx == WARGCOUNT(win) - 1
2001#ifdef FEAT_WINDOWS
2002 && win->w_alist == &global_alist
2003#endif
2004 )
2005 arg_had_last = TRUE;
2006 }
2007}
2008
2009/*
2010 * ":args", ":argslocal" and ":argsglobal".
2011 */
2012 void
2013ex_args(eap)
2014 exarg_T *eap;
2015{
2016 int i;
2017
2018 if (eap->cmdidx != CMD_args)
2019 {
2020#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2021 alist_unlink(ALIST(curwin));
2022 if (eap->cmdidx == CMD_argglobal)
2023 ALIST(curwin) = &global_alist;
2024 else /* eap->cmdidx == CMD_arglocal */
2025 alist_new();
2026#else
2027 ex_ni(eap);
2028 return;
2029#endif
2030 }
2031
2032 if (!ends_excmd(*eap->arg))
2033 {
2034 /*
2035 * ":args file ..": define new argument list, handle like ":next"
2036 * Also for ":argslocal file .." and ":argsglobal file ..".
2037 */
2038 ex_next(eap);
2039 }
2040 else
2041#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2042 if (eap->cmdidx == CMD_args)
2043#endif
2044 {
2045 /*
2046 * ":args": list arguments.
2047 */
2048 if (ARGCOUNT > 0)
2049 {
2050 /* Overwrite the command, for a short list there is no scrolling
2051 * required and no wait_return(). */
2052 gotocmdline(TRUE);
2053 for (i = 0; i < ARGCOUNT; ++i)
2054 {
2055 if (i == curwin->w_arg_idx)
2056 msg_putchar('[');
2057 msg_outtrans(alist_name(&ARGLIST[i]));
2058 if (i == curwin->w_arg_idx)
2059 msg_putchar(']');
2060 msg_putchar(' ');
2061 }
2062 }
2063 }
2064#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2065 else if (eap->cmdidx == CMD_arglocal)
2066 {
2067 garray_T *gap = &curwin->w_alist->al_ga;
2068
2069 /*
2070 * ":argslocal": make a local copy of the global argument list.
2071 */
2072 if (ga_grow(gap, GARGCOUNT) == OK)
2073 for (i = 0; i < GARGCOUNT; ++i)
2074 if (GARGLIST[i].ae_fname != NULL)
2075 {
2076 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2077 vim_strsave(GARGLIST[i].ae_fname);
2078 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2079 GARGLIST[i].ae_fnum;
2080 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081 }
2082 }
2083#endif
2084}
2085
2086/*
2087 * ":previous", ":sprevious", ":Next" and ":sNext".
2088 */
2089 void
2090ex_previous(eap)
2091 exarg_T *eap;
2092{
2093 /* If past the last one already, go to the last one. */
2094 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2095 do_argfile(eap, ARGCOUNT - 1);
2096 else
2097 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2098}
2099
2100/*
2101 * ":rewind", ":first", ":sfirst" and ":srewind".
2102 */
2103 void
2104ex_rewind(eap)
2105 exarg_T *eap;
2106{
2107 do_argfile(eap, 0);
2108}
2109
2110/*
2111 * ":last" and ":slast".
2112 */
2113 void
2114ex_last(eap)
2115 exarg_T *eap;
2116{
2117 do_argfile(eap, ARGCOUNT - 1);
2118}
2119
2120/*
2121 * ":argument" and ":sargument".
2122 */
2123 void
2124ex_argument(eap)
2125 exarg_T *eap;
2126{
2127 int i;
2128
2129 if (eap->addr_count > 0)
2130 i = eap->line2 - 1;
2131 else
2132 i = curwin->w_arg_idx;
2133 do_argfile(eap, i);
2134}
2135
2136/*
2137 * Edit file "argn" of the argument lists.
2138 */
2139 void
2140do_argfile(eap, argn)
2141 exarg_T *eap;
2142 int argn;
2143{
2144 int other;
2145 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002146 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147
2148 if (argn < 0 || argn >= ARGCOUNT)
2149 {
2150 if (ARGCOUNT <= 1)
2151 EMSG(_("E163: There is only one file to edit"));
2152 else if (argn < 0)
2153 EMSG(_("E164: Cannot go before first file"));
2154 else
2155 EMSG(_("E165: Cannot go beyond last file"));
2156 }
2157 else
2158 {
2159 setpcmark();
2160#ifdef FEAT_GUI
2161 need_mouse_correct = TRUE;
2162#endif
2163
2164#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002165 /* split window or create new tab page first */
2166 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002167 {
2168 if (win_split(0, 0) == FAIL)
2169 return;
2170# ifdef FEAT_SCROLLBIND
2171 curwin->w_p_scb = FALSE;
2172# endif
2173 }
2174 else
2175#endif
2176 {
2177 /*
2178 * if 'hidden' set, only check for changed file when re-editing
2179 * the same buffer
2180 */
2181 other = TRUE;
2182 if (P_HID(curbuf))
2183 {
2184 p = fix_fname(alist_name(&ARGLIST[argn]));
2185 other = otherfile(p);
2186 vim_free(p);
2187 }
2188 if ((!P_HID(curbuf) || !other)
2189 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2190 return;
2191 }
2192
2193 curwin->w_arg_idx = argn;
2194 if (argn == ARGCOUNT - 1
2195#ifdef FEAT_WINDOWS
2196 && curwin->w_alist == &global_alist
2197#endif
2198 )
2199 arg_had_last = TRUE;
2200
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002201 /* Edit the file; always use the last known line number.
2202 * When it fails (e.g. Abort for already edited file) restore the
2203 * argument index. */
2204 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002205 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002206 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2207 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002208 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002209 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002210 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211 setmark('\'');
2212 }
2213}
2214
2215/*
2216 * ":next", and commands that behave like it.
2217 */
2218 void
2219ex_next(eap)
2220 exarg_T *eap;
2221{
2222 int i;
2223
2224 /*
2225 * check for changed buffer now, if this fails the argument list is not
2226 * redefined.
2227 */
2228 if ( P_HID(curbuf)
2229 || eap->cmdidx == CMD_snext
2230 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2231 {
2232 if (*eap->arg != NUL) /* redefine file list */
2233 {
2234 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2235 return;
2236 i = 0;
2237 }
2238 else
2239 i = curwin->w_arg_idx + (int)eap->line2;
2240 do_argfile(eap, i);
2241 }
2242}
2243
2244#ifdef FEAT_LISTCMDS
2245/*
2246 * ":argedit"
2247 */
2248 void
2249ex_argedit(eap)
2250 exarg_T *eap;
2251{
2252 int fnum;
2253 int i;
2254 char_u *s;
2255
2256 /* Add the argument to the buffer list and get the buffer number. */
2257 fnum = buflist_add(eap->arg, BLN_LISTED);
2258
2259 /* Check if this argument is already in the argument list. */
2260 for (i = 0; i < ARGCOUNT; ++i)
2261 if (ARGLIST[i].ae_fnum == fnum)
2262 break;
2263 if (i == ARGCOUNT)
2264 {
2265 /* Can't find it, add it to the argument list. */
2266 s = vim_strsave(eap->arg);
2267 if (s == NULL)
2268 return;
2269 i = alist_add_list(1, &s,
2270 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2271 if (i < 0)
2272 return;
2273 curwin->w_arg_idx = i;
2274 }
2275
2276 alist_check_arg_idx();
2277
2278 /* Edit the argument. */
2279 do_argfile(eap, i);
2280}
2281
2282/*
2283 * ":argadd"
2284 */
2285 void
2286ex_argadd(eap)
2287 exarg_T *eap;
2288{
2289 do_arglist(eap->arg, AL_ADD,
2290 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2291#ifdef FEAT_TITLE
2292 maketitle();
2293#endif
2294}
2295
2296/*
2297 * ":argdelete"
2298 */
2299 void
2300ex_argdelete(eap)
2301 exarg_T *eap;
2302{
2303 int i;
2304 int n;
2305
2306 if (eap->addr_count > 0)
2307 {
2308 /* ":1,4argdel": Delete all arguments in the range. */
2309 if (eap->line2 > ARGCOUNT)
2310 eap->line2 = ARGCOUNT;
2311 n = eap->line2 - eap->line1 + 1;
2312 if (*eap->arg != NUL || n <= 0)
2313 EMSG(_(e_invarg));
2314 else
2315 {
2316 for (i = eap->line1; i <= eap->line2; ++i)
2317 vim_free(ARGLIST[i - 1].ae_fname);
2318 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2319 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2320 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321 if (curwin->w_arg_idx >= eap->line2)
2322 curwin->w_arg_idx -= n;
2323 else if (curwin->w_arg_idx > eap->line1)
2324 curwin->w_arg_idx = eap->line1;
2325 }
2326 }
2327 else if (*eap->arg == NUL)
2328 EMSG(_(e_argreq));
2329 else
2330 do_arglist(eap->arg, AL_DEL, 0);
2331#ifdef FEAT_TITLE
2332 maketitle();
2333#endif
2334}
2335
2336/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002337 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002338 */
2339 void
2340ex_listdo(eap)
2341 exarg_T *eap;
2342{
2343 int i;
2344#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002345 win_T *wp;
2346 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002347#endif
2348 buf_T *buf;
2349 int next_fnum = 0;
2350#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2351 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002353 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354
2355#ifndef FEAT_WINDOWS
2356 if (eap->cmdidx == CMD_windo)
2357 {
2358 ex_ni(eap);
2359 return;
2360 }
2361#endif
2362
2363#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002364 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002365 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2366 * great speed improvement. */
2367 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002368#endif
2369
2370 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002371 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 || P_HID(curbuf)
2373 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2374 {
2375 /* start at the first argument/window/buffer */
2376 i = 0;
2377#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002378 wp = firstwin;
2379 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380#endif
2381 /* set pcmark now */
2382 if (eap->cmdidx == CMD_bufdo)
2383 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2384 else
2385 setpcmark();
2386 listcmd_busy = TRUE; /* avoids setting pcmark below */
2387
2388 while (!got_int)
2389 {
2390 if (eap->cmdidx == CMD_argdo)
2391 {
2392 /* go to argument "i" */
2393 if (i == ARGCOUNT)
2394 break;
2395 /* Don't call do_argfile() when already there, it will try
2396 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002397 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002398 {
2399 /* Clear 'shm' to avoid that the file message overwrites
2400 * any output from the command. */
2401 p_shm_save = vim_strsave(p_shm);
2402 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002403 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002404 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2405 vim_free(p_shm_save);
2406 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002407 if (curwin->w_arg_idx != i)
2408 break;
2409 ++i;
2410 }
2411#ifdef FEAT_WINDOWS
2412 else if (eap->cmdidx == CMD_windo)
2413 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002414 /* go to window "wp" */
2415 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002416 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002417 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002418 if (curwin != wp)
2419 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002420 wp = curwin->w_next;
2421 }
2422 else if (eap->cmdidx == CMD_tabdo)
2423 {
2424 /* go to window "tp" */
2425 if (!valid_tabpage(tp))
2426 break;
2427 goto_tabpage_tp(tp);
2428 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429 }
2430#endif
2431 else if (eap->cmdidx == CMD_bufdo)
2432 {
2433 /* Remember the number of the next listed buffer, in case
2434 * ":bwipe" is used or autocommands do something strange. */
2435 next_fnum = -1;
2436 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2437 if (buf->b_p_bl)
2438 {
2439 next_fnum = buf->b_fnum;
2440 break;
2441 }
2442 }
2443
2444 /* execute the command */
2445 do_cmdline(eap->arg, eap->getline, eap->cookie,
2446 DOCMD_VERBOSE + DOCMD_NOWAIT);
2447
2448 if (eap->cmdidx == CMD_bufdo)
2449 {
2450 /* Done? */
2451 if (next_fnum < 0)
2452 break;
2453 /* Check if the buffer still exists. */
2454 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2455 if (buf->b_fnum == next_fnum)
2456 break;
2457 if (buf == NULL)
2458 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002459
2460 /* Go to the next buffer. Clear 'shm' to avoid that the file
2461 * message overwrites any output from the command. */
2462 p_shm_save = vim_strsave(p_shm);
2463 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002465 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2466 vim_free(p_shm_save);
2467
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 /* If autocommands took us elsewhere, quit here */
2469 if (curbuf->b_fnum != next_fnum)
2470 break;
2471 }
2472
2473 if (eap->cmdidx == CMD_windo)
2474 {
2475 validate_cursor(); /* cursor may have moved */
2476#ifdef FEAT_SCROLLBIND
2477 /* required when 'scrollbind' has been set */
2478 if (curwin->w_p_scb)
2479 do_check_scrollbind(TRUE);
2480#endif
2481 }
2482 }
2483 listcmd_busy = FALSE;
2484 }
2485
2486#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002487 if (save_ei != NULL)
2488 {
2489 au_event_restore(save_ei);
2490 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2491 curbuf->b_fname, TRUE, curbuf);
2492 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002493#endif
2494}
2495
2496/*
2497 * Add files[count] to the arglist of the current window after arg "after".
2498 * The file names in files[count] must have been allocated and are taken over.
2499 * Files[] itself is not taken over.
2500 * Returns index of first added argument. Returns -1 when failed (out of mem).
2501 */
2502 static int
2503alist_add_list(count, files, after)
2504 int count;
2505 char_u **files;
2506 int after; /* where to add: 0 = before first one */
2507{
2508 int i;
2509
2510 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2511 {
2512 if (after < 0)
2513 after = 0;
2514 if (after > ARGCOUNT)
2515 after = ARGCOUNT;
2516 if (after < ARGCOUNT)
2517 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2518 (ARGCOUNT - after) * sizeof(aentry_T));
2519 for (i = 0; i < count; ++i)
2520 {
2521 ARGLIST[after + i].ae_fname = files[i];
2522 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2523 }
2524 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525 if (curwin->w_arg_idx >= after)
2526 ++curwin->w_arg_idx;
2527 return after;
2528 }
2529
2530 for (i = 0; i < count; ++i)
2531 vim_free(files[i]);
2532 return -1;
2533}
2534
2535#endif /* FEAT_LISTCMDS */
2536
2537#ifdef FEAT_EVAL
2538/*
2539 * ":compiler[!] {name}"
2540 */
2541 void
2542ex_compiler(eap)
2543 exarg_T *eap;
2544{
2545 char_u *buf;
2546 char_u *old_cur_comp = NULL;
2547 char_u *p;
2548
2549 if (*eap->arg == NUL)
2550 {
2551 /* List all compiler scripts. */
2552 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2553 /* ) keep the indenter happy... */
2554 }
2555 else
2556 {
2557 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2558 if (buf != NULL)
2559 {
2560 if (eap->forceit)
2561 {
2562 /* ":compiler! {name}" sets global options */
2563 do_cmdline_cmd((char_u *)
2564 "command -nargs=* CompilerSet set <args>");
2565 }
2566 else
2567 {
2568 /* ":compiler! {name}" sets local options.
2569 * To remain backwards compatible "current_compiler" is always
2570 * used. A user's compiler plugin may set it, the distributed
2571 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002572 * "b:current_compiler" and restore "current_compiler".
2573 * Explicitly prepend "g:" to make it work in a function. */
2574 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002575 if (old_cur_comp != NULL)
2576 old_cur_comp = vim_strsave(old_cur_comp);
2577 do_cmdline_cmd((char_u *)
2578 "command -nargs=* CompilerSet setlocal <args>");
2579 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002580 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002581 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582
2583 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002584 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002585 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2586 vim_free(buf);
2587
2588 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2589
2590 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002591 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592 if (p != NULL)
2593 set_internal_string_var((char_u *)"b:current_compiler", p);
2594
2595 /* Restore "current_compiler" for ":compiler {name}". */
2596 if (!eap->forceit)
2597 {
2598 if (old_cur_comp != NULL)
2599 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002600 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002601 old_cur_comp);
2602 vim_free(old_cur_comp);
2603 }
2604 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002605 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606 }
2607 }
2608 }
2609}
2610#endif
2611
2612/*
2613 * ":runtime {name}"
2614 */
2615 void
2616ex_runtime(eap)
2617 exarg_T *eap;
2618{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002619 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620}
2621
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002622static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623
2624 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002625source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002627 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002629 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630}
2631
2632/*
2633 * Source the file "name" from all directories in 'runtimepath'.
2634 * "name" can contain wildcards.
2635 * When "all" is TRUE, source all files, otherwise only the first one.
2636 * return FAIL when no file could be sourced, OK otherwise.
2637 */
2638 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002639source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640 char_u *name;
2641 int all;
2642{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002643 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644}
2645
2646/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002647 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2648 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2650 * used.
2651 * Returns OK when at least one match found, FAIL otherwise.
2652 */
2653 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002654do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002655 char_u *name;
2656 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002657 void (*callback)__ARGS((char_u *fname, void *ck));
2658 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002659{
2660 char_u *rtp;
2661 char_u *np;
2662 char_u *buf;
2663 char_u *rtp_copy;
2664 char_u *tail;
2665 int num_files;
2666 char_u **files;
2667 int i;
2668 int did_one = FALSE;
2669#ifdef AMIGA
2670 struct Process *proc = (struct Process *)FindTask(0L);
2671 APTR save_winptr = proc->pr_WindowPtr;
2672
2673 /* Avoid a requester here for a volume that doesn't exist. */
2674 proc->pr_WindowPtr = (APTR)-1L;
2675#endif
2676
2677 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2678 * value. */
2679 rtp_copy = vim_strsave(p_rtp);
2680 buf = alloc(MAXPATHL);
2681 if (buf != NULL && rtp_copy != NULL)
2682 {
2683 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002684 {
2685 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002686 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002687 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002688 verbose_leave();
2689 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002690
Bram Moolenaar071d4272004-06-13 20:20:40 +00002691 /* Loop over all entries in 'runtimepath'. */
2692 rtp = rtp_copy;
2693 while (*rtp != NUL && (all || !did_one))
2694 {
2695 /* Copy the path from 'runtimepath' to buf[]. */
2696 copy_option_part(&rtp, buf, MAXPATHL, ",");
2697 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2698 {
2699 add_pathsep(buf);
2700 tail = buf + STRLEN(buf);
2701
2702 /* Loop over all patterns in "name" */
2703 np = name;
2704 while (*np != NUL && (all || !did_one))
2705 {
2706 /* Append the pattern from "name" to buf[]. */
2707 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2708 "\t ");
2709
2710 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002711 {
2712 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002713 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002714 verbose_leave();
2715 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716
2717 /* Expand wildcards, invoke the callback for each match. */
2718 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2719 EW_FILE) == OK)
2720 {
2721 for (i = 0; i < num_files; ++i)
2722 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002723 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 did_one = TRUE;
2725 if (!all)
2726 break;
2727 }
2728 FreeWild(num_files, files);
2729 }
2730 }
2731 }
2732 }
2733 }
2734 vim_free(buf);
2735 vim_free(rtp_copy);
2736 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002737 {
2738 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002739 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002740 verbose_leave();
2741 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002742
2743#ifdef AMIGA
2744 proc->pr_WindowPtr = save_winptr;
2745#endif
2746
2747 return did_one ? OK : FAIL;
2748}
2749
2750#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2751/*
2752 * ":options"
2753 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754 void
2755ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002756 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757{
2758 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2759}
2760#endif
2761
2762/*
2763 * ":source {fname}"
2764 */
2765 void
2766ex_source(eap)
2767 exarg_T *eap;
2768{
2769#ifdef FEAT_BROWSE
2770 if (cmdmod.browse)
2771 {
2772 char_u *fname = NULL;
2773
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002774 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2776 if (fname != NULL)
2777 {
2778 cmd_source(fname, eap);
2779 vim_free(fname);
2780 }
2781 }
2782 else
2783#endif
2784 cmd_source(eap->arg, eap);
2785}
2786
2787 static void
2788cmd_source(fname, eap)
2789 char_u *fname;
2790 exarg_T *eap;
2791{
2792 if (*fname == NUL)
2793 EMSG(_(e_argreq));
2794
Bram Moolenaar071d4272004-06-13 20:20:40 +00002795 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002796 /* ":source!": read Normal mdoe commands
2797 * Need to execute the commands directly. This is required at least
2798 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 * - ":g" command busy
2800 * - after ":argdo", ":windo" or ":bufdo"
2801 * - another command follows
2802 * - inside a loop
2803 */
2804 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2805#ifdef FEAT_EVAL
2806 || eap->cstack->cs_idx >= 0
2807#endif
2808 );
2809
2810 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002811 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812 EMSG2(_(e_notopen), fname);
2813}
2814
2815/*
2816 * ":source" and associated commands.
2817 */
2818/*
2819 * Structure used to store info for each sourced file.
2820 * It is shared between do_source() and getsourceline().
2821 * This is required, because it needs to be handed to do_cmdline() and
2822 * sourcing can be done recursively.
2823 */
2824struct source_cookie
2825{
2826 FILE *fp; /* opened file for sourcing */
2827 char_u *nextline; /* if not NULL: line that was read ahead */
2828 int finished; /* ":finish" used */
2829#if defined (USE_CRNL) || defined (USE_CR)
2830 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2831 int error; /* TRUE if LF found after CR-LF */
2832#endif
2833#ifdef FEAT_EVAL
2834 linenr_T breakpoint; /* next line with breakpoint or zero */
2835 char_u *fname; /* name of sourced file */
2836 int dbg_tick; /* debug_tick when breakpoint was set */
2837 int level; /* top nesting level of sourced file */
2838#endif
2839#ifdef FEAT_MBYTE
2840 vimconv_T conv; /* type of conversion */
2841#endif
2842};
2843
2844#ifdef FEAT_EVAL
2845/*
2846 * Return the address holding the next breakpoint line for a source cookie.
2847 */
2848 linenr_T *
2849source_breakpoint(cookie)
2850 void *cookie;
2851{
2852 return &((struct source_cookie *)cookie)->breakpoint;
2853}
2854
2855/*
2856 * Return the address holding the debug tick for a source cookie.
2857 */
2858 int *
2859source_dbg_tick(cookie)
2860 void *cookie;
2861{
2862 return &((struct source_cookie *)cookie)->dbg_tick;
2863}
2864
2865/*
2866 * Return the nesting level for a source cookie.
2867 */
2868 int
2869source_level(cookie)
2870 void *cookie;
2871{
2872 return ((struct source_cookie *)cookie)->level;
2873}
2874#endif
2875
2876static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2877
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002878#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2879# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002880static FILE *fopen_noinh_readbin __ARGS((char *filename));
2881
2882/*
2883 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002884 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002885 */
2886 static FILE *
2887fopen_noinh_readbin(filename)
2888 char *filename;
2889{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002890# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002891 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2892# else
2893 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002894# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895
2896 if (fd_tmp == -1)
2897 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002898
2899# ifdef HAVE_FD_CLOEXEC
2900 {
2901 int fdflags = fcntl(fd_tmp, F_GETFD);
2902 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
2903 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
2904 }
2905# endif
2906
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907 return fdopen(fd_tmp, READBIN);
2908}
2909#endif
2910
2911
2912/*
2913 * do_source: Read the file "fname" and execute its lines as EX commands.
2914 *
2915 * This function may be called recursively!
2916 *
2917 * return FAIL if file could not be opened, OK otherwise
2918 */
2919 int
2920do_source(fname, check_other, is_vimrc)
2921 char_u *fname;
2922 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002923 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924{
2925 struct source_cookie cookie;
2926 char_u *save_sourcing_name;
2927 linenr_T save_sourcing_lnum;
2928 char_u *p;
2929 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002930 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931 int retval = FAIL;
2932#ifdef FEAT_EVAL
2933 scid_T save_current_SID;
2934 static scid_T last_current_SID = 0;
2935 void *save_funccalp;
2936 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002937 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938# ifdef UNIX
2939 struct stat st;
2940 int stat_ok;
2941# endif
2942#endif
2943#ifdef STARTUPTIME
2944 struct timeval tv_rel;
2945 struct timeval tv_start;
2946#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002947#ifdef FEAT_PROFILE
2948 proftime_T wait_start;
2949#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950
2951#ifdef RISCOS
2952 p = mch_munge_fname(fname);
2953#else
2954 p = expand_env_save(fname);
2955#endif
2956 if (p == NULL)
2957 return retval;
2958 fname_exp = fix_fname(p);
2959 vim_free(p);
2960 if (fname_exp == NULL)
2961 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002962 if (mch_isdir(fname_exp))
2963 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002964 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965 goto theend;
2966 }
2967
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002968#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002969 /* Apply SourceCmd autocommands, they should get the file and source it. */
2970 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2971 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2972 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002973 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002974# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002975 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002976# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002977 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002978# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002979 goto theend;
2980 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002981
2982 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002983 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2984#endif
2985
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002986#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2988#else
2989 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2990#endif
2991 if (cookie.fp == NULL && check_other)
2992 {
2993 /*
2994 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2995 * and ".exrc" by "_exrc" or vice versa.
2996 */
2997 p = gettail(fname_exp);
2998 if ((*p == '.' || *p == '_')
2999 && (STRICMP(p + 1, "vimrc") == 0
3000 || STRICMP(p + 1, "gvimrc") == 0
3001 || STRICMP(p + 1, "exrc") == 0))
3002 {
3003 if (*p == '_')
3004 *p = '.';
3005 else
3006 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003007#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3009#else
3010 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3011#endif
3012 }
3013 }
3014
3015 if (cookie.fp == NULL)
3016 {
3017 if (p_verbose > 0)
3018 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003019 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003021 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022 else
3023 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003024 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003025 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003026 }
3027 goto theend;
3028 }
3029
3030 /*
3031 * The file exists.
3032 * - In verbose mode, give a message.
3033 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3034 */
3035 if (p_verbose > 1)
3036 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003037 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003039 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040 else
3041 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003042 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003043 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003045 if (is_vimrc == DOSO_VIMRC)
3046 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3047 else if (is_vimrc == DOSO_GVIMRC)
3048 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049
3050#ifdef USE_CRNL
3051 /* If no automatic file format: Set default to CR-NL. */
3052 if (*p_ffs == NUL)
3053 cookie.fileformat = EOL_DOS;
3054 else
3055 cookie.fileformat = EOL_UNKNOWN;
3056 cookie.error = FALSE;
3057#endif
3058
3059#ifdef USE_CR
3060 /* If no automatic file format: Set default to CR. */
3061 if (*p_ffs == NUL)
3062 cookie.fileformat = EOL_MAC;
3063 else
3064 cookie.fileformat = EOL_UNKNOWN;
3065 cookie.error = FALSE;
3066#endif
3067
3068 cookie.nextline = NULL;
3069 cookie.finished = FALSE;
3070
3071#ifdef FEAT_EVAL
3072 /*
3073 * Check if this script has a breakpoint.
3074 */
3075 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3076 cookie.fname = fname_exp;
3077 cookie.dbg_tick = debug_tick;
3078
3079 cookie.level = ex_nesting_level;
3080#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003081
3082 /*
3083 * Keep the sourcing name/lnum, for recursive calls.
3084 */
3085 save_sourcing_name = sourcing_name;
3086 sourcing_name = fname_exp;
3087 save_sourcing_lnum = sourcing_lnum;
3088 sourcing_lnum = 0;
3089
Bram Moolenaar73881402009-02-04 16:50:47 +00003090#ifdef FEAT_MBYTE
3091 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3092
3093 /* Read the first line so we can check for a UTF-8 BOM. */
3094 firstline = getsourceline(0, (void *)&cookie, 0);
3095 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3096 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3097 {
3098 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3099 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3100 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003101 if (p == NULL)
3102 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003103 if (p != NULL)
3104 {
3105 vim_free(firstline);
3106 firstline = p;
3107 }
3108 }
3109#endif
3110
Bram Moolenaar071d4272004-06-13 20:20:40 +00003111#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003112 if (time_fd != NULL)
3113 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114#endif
3115
3116#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003117# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003118 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003119 prof_child_enter(&wait_start); /* entering a child now */
3120# endif
3121
3122 /* Don't use local function variables, if called from a function.
3123 * Also starts profiling timer for nested script. */
3124 save_funccalp = save_funccal();
3125
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126 /*
3127 * Check if this script was sourced before to finds its SID.
3128 * If it's new, generate a new SID.
3129 */
3130 save_current_SID = current_SID;
3131# ifdef UNIX
3132 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3133# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003134 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3135 {
3136 si = &SCRIPT_ITEM(current_SID);
3137 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 && (
3139# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003140 /* Compare dev/ino when possible, it catches symbolic
3141 * links. Also compare file names, the inode may change
3142 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003143 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003144 && (si->sn_dev == st.st_dev
3145 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003147 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003149 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150 if (current_SID == 0)
3151 {
3152 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003153 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3154 == FAIL)
3155 goto almosttheend;
3156 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003157 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003158 ++script_items.ga_len;
3159 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3160# ifdef FEAT_PROFILE
3161 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003164 si = &SCRIPT_ITEM(current_SID);
3165 si->sn_name = fname_exp;
3166 fname_exp = NULL;
3167# ifdef UNIX
3168 if (stat_ok)
3169 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003170 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003171 si->sn_dev = st.st_dev;
3172 si->sn_ino = st.st_ino;
3173 }
3174 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003175 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003176# endif
3177
Bram Moolenaar071d4272004-06-13 20:20:40 +00003178 /* Allocate the local script variables to use for this script. */
3179 new_script_vars(current_SID);
3180 }
3181
Bram Moolenaar05159a02005-02-26 23:04:13 +00003182# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003183 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003184 {
3185 int forceit;
3186
3187 /* Check if we do profiling for this script. */
3188 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3189 {
3190 script_do_profile(si);
3191 si->sn_pr_force = forceit;
3192 }
3193 if (si->sn_prof_on)
3194 {
3195 ++si->sn_pr_count;
3196 profile_start(&si->sn_pr_start);
3197 profile_zero(&si->sn_pr_children);
3198 }
3199 }
3200# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003201#endif
3202
3203 /*
3204 * Call do_cmdline, which will call getsourceline() to get the lines.
3205 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003206 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003207 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003209
3210#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003211 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003212 {
3213 /* Get "si" again, "script_items" may have been reallocated. */
3214 si = &SCRIPT_ITEM(current_SID);
3215 if (si->sn_prof_on)
3216 {
3217 profile_end(&si->sn_pr_start);
3218 profile_sub_wait(&wait_start, &si->sn_pr_start);
3219 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003220 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3221 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003222 }
3223 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003224#endif
3225
3226 if (got_int)
3227 EMSG(_(e_interr));
3228 sourcing_name = save_sourcing_name;
3229 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003230 if (p_verbose > 1)
3231 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003232 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003233 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003235 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003236 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237 }
3238#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003239 if (time_fd != NULL)
3240 {
3241 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3242 time_msg((char *)IObuff, &tv_start);
3243 time_pop(&tv_rel);
3244 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245#endif
3246
3247#ifdef FEAT_EVAL
3248 /*
3249 * After a "finish" in debug mode, need to break at first command of next
3250 * sourced file.
3251 */
3252 if (save_debug_break_level > ex_nesting_level
3253 && debug_break_level == ex_nesting_level)
3254 ++debug_break_level;
3255#endif
3256
Bram Moolenaar05159a02005-02-26 23:04:13 +00003257#ifdef FEAT_EVAL
3258almosttheend:
3259 current_SID = save_current_SID;
3260 restore_funccal(save_funccalp);
3261# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003262 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003263 prof_child_exit(&wait_start); /* leaving a child now */
3264# endif
3265#endif
3266 fclose(cookie.fp);
3267 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003268 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003269#ifdef FEAT_MBYTE
3270 convert_setup(&cookie.conv, NULL, NULL);
3271#endif
3272
Bram Moolenaar071d4272004-06-13 20:20:40 +00003273theend:
3274 vim_free(fname_exp);
3275 return retval;
3276}
3277
3278#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003279
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280/*
3281 * ":scriptnames"
3282 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003283 void
3284ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003285 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003286{
3287 int i;
3288
Bram Moolenaar05159a02005-02-26 23:04:13 +00003289 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3290 if (SCRIPT_ITEM(i).sn_name != NULL)
3291 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292}
3293
3294# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3295/*
3296 * Fix slashes in the list of script names for 'shellslash'.
3297 */
3298 void
3299scriptnames_slash_adjust()
3300{
3301 int i;
3302
Bram Moolenaar05159a02005-02-26 23:04:13 +00003303 for (i = 1; i <= script_items.ga_len; ++i)
3304 if (SCRIPT_ITEM(i).sn_name != NULL)
3305 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306}
3307# endif
3308
3309/*
3310 * Get a pointer to a script name. Used for ":verbose set".
3311 */
3312 char_u *
3313get_scriptname(id)
3314 scid_T id;
3315{
3316 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003317 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003319 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003320 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003321 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003323 return (char_u *)_("environment variable");
3324 if (id == SID_ERROR)
3325 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003326 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003328
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003329# if defined(EXITFREE) || defined(PROTO)
3330 void
3331free_scriptnames()
3332{
3333 int i;
3334
3335 for (i = script_items.ga_len; i > 0; --i)
3336 vim_free(SCRIPT_ITEM(i).sn_name);
3337 ga_clear(&script_items);
3338}
3339# endif
3340
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341#endif
3342
3343#if defined(USE_CR) || defined(PROTO)
3344
3345# if defined(__MSL__) && (__MSL__ >= 22)
3346/*
3347 * Newer version of the Metrowerks library handle DOS and UNIX files
3348 * without help.
3349 * Test with earlier versions, MSL 2.2 is the library supplied with
3350 * Codewarrior Pro 2.
3351 */
3352 char *
3353fgets_cr(s, n, stream)
3354 char *s;
3355 int n;
3356 FILE *stream;
3357{
3358 return fgets(s, n, stream);
3359}
3360# else
3361/*
3362 * Version of fgets() which also works for lines ending in a <CR> only
3363 * (Macintosh format).
3364 * For older versions of the Metrowerks library.
3365 * At least CodeWarrior 9 needed this code.
3366 */
3367 char *
3368fgets_cr(s, n, stream)
3369 char *s;
3370 int n;
3371 FILE *stream;
3372{
3373 int c = 0;
3374 int char_read = 0;
3375
3376 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3377 {
3378 c = fgetc(stream);
3379 s[char_read++] = c;
3380 /* If the file is in DOS format, we need to skip a NL after a CR. I
3381 * thought it was the other way around, but this appears to work... */
3382 if (c == '\n')
3383 {
3384 c = fgetc(stream);
3385 if (c != '\r')
3386 ungetc(c, stream);
3387 }
3388 }
3389
3390 s[char_read] = 0;
3391 if (char_read == 0)
3392 return NULL;
3393
3394 if (feof(stream) && char_read == 1)
3395 return NULL;
3396
3397 return s;
3398}
3399# endif
3400#endif
3401
3402/*
3403 * Get one full line from a sourced file.
3404 * Called by do_cmdline() when it's called from do_source().
3405 *
3406 * Return a pointer to the line in allocated memory.
3407 * Return NULL for end-of-file or some error.
3408 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003409 char_u *
3410getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003411 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003412 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003413 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414{
3415 struct source_cookie *sp = (struct source_cookie *)cookie;
3416 char_u *line;
3417 char_u *p, *s;
3418
3419#ifdef FEAT_EVAL
3420 /* If breakpoints have been added/deleted need to check for it. */
3421 if (sp->dbg_tick < debug_tick)
3422 {
3423 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3424 sp->dbg_tick = debug_tick;
3425 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003426# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003427 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003428 script_line_end();
3429# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003430#endif
3431 /*
3432 * Get current line. If there is a read-ahead line, use it, otherwise get
3433 * one now.
3434 */
3435 if (sp->finished)
3436 line = NULL;
3437 else if (sp->nextline == NULL)
3438 line = get_one_sourceline(sp);
3439 else
3440 {
3441 line = sp->nextline;
3442 sp->nextline = NULL;
3443 ++sourcing_lnum;
3444 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003445#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003446 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003447 script_line_start();
3448#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449
3450 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3451 * contain the 'C' flag. */
3452 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3453 {
3454 /* compensate for the one line read-ahead */
3455 --sourcing_lnum;
3456 for (;;)
3457 {
3458 sp->nextline = get_one_sourceline(sp);
3459 if (sp->nextline == NULL)
3460 break;
3461 p = skipwhite(sp->nextline);
3462 if (*p != '\\')
3463 break;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00003464 s = alloc((unsigned)(STRLEN(line) + STRLEN(p)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003465 if (s == NULL) /* out of memory */
3466 break;
3467 STRCPY(s, line);
3468 STRCAT(s, p + 1);
3469 vim_free(line);
3470 line = s;
3471 vim_free(sp->nextline);
3472 }
3473 }
3474
3475#ifdef FEAT_MBYTE
3476 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3477 {
3478 /* Convert the encoding of the script line. */
3479 s = string_convert(&sp->conv, line, NULL);
3480 if (s != NULL)
3481 {
3482 vim_free(line);
3483 line = s;
3484 }
3485 }
3486#endif
3487
3488#ifdef FEAT_EVAL
3489 /* Did we encounter a breakpoint? */
3490 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3491 {
3492 dbg_breakpoint(sp->fname, sourcing_lnum);
3493 /* Find next breakpoint. */
3494 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3495 sp->dbg_tick = debug_tick;
3496 }
3497#endif
3498
3499 return line;
3500}
3501
3502 static char_u *
3503get_one_sourceline(sp)
3504 struct source_cookie *sp;
3505{
3506 garray_T ga;
3507 int len;
3508 int c;
3509 char_u *buf;
3510#ifdef USE_CRNL
3511 int has_cr; /* CR-LF found */
3512#endif
3513#ifdef USE_CR
3514 char_u *scan;
3515#endif
3516 int have_read = FALSE;
3517
3518 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003519 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520
3521 /*
3522 * Loop until there is a finished line (or end-of-file).
3523 */
3524 sourcing_lnum++;
3525 for (;;)
3526 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003527 /* make room to read at least 120 (more) characters */
3528 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529 break;
3530 buf = (char_u *)ga.ga_data;
3531
3532#ifdef USE_CR
3533 if (sp->fileformat == EOL_MAC)
3534 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003535 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3536 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537 break;
3538 }
3539 else
3540#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003541 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3542 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003543 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003544 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003545#ifdef USE_CRNL
3546 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3547 * CTRL-Z by its own, or after a NL. */
3548 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3549 && sp->fileformat == EOL_DOS
3550 && buf[len - 1] == Ctrl_Z)
3551 {
3552 buf[len - 1] = NUL;
3553 break;
3554 }
3555#endif
3556
3557#ifdef USE_CR
3558 /* If the read doesn't stop on a new line, and there's
3559 * some CR then we assume a Mac format */
3560 if (sp->fileformat == EOL_UNKNOWN)
3561 {
3562 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3563 sp->fileformat = EOL_MAC;
3564 else
3565 sp->fileformat = EOL_UNIX;
3566 }
3567
3568 if (sp->fileformat == EOL_MAC)
3569 {
3570 scan = vim_strchr(buf, '\r');
3571
3572 if (scan != NULL)
3573 {
3574 *scan = '\n';
3575 if (*(scan + 1) != 0)
3576 {
3577 *(scan + 1) = 0;
3578 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3579 }
3580 }
3581 len = STRLEN(buf);
3582 }
3583#endif
3584
3585 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586 ga.ga_len = len;
3587
3588 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003589 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590 continue;
3591
3592 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3593 {
3594#ifdef USE_CRNL
3595 has_cr = (len >= 2 && buf[len - 2] == '\r');
3596 if (sp->fileformat == EOL_UNKNOWN)
3597 {
3598 if (has_cr)
3599 sp->fileformat = EOL_DOS;
3600 else
3601 sp->fileformat = EOL_UNIX;
3602 }
3603
3604 if (sp->fileformat == EOL_DOS)
3605 {
3606 if (has_cr) /* replace trailing CR */
3607 {
3608 buf[len - 2] = '\n';
3609 --len;
3610 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611 }
3612 else /* lines like ":map xx yy^M" will have failed */
3613 {
3614 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003615 {
3616 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003618 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003619 sp->error = TRUE;
3620 sp->fileformat = EOL_UNIX;
3621 }
3622 }
3623#endif
3624 /* The '\n' is escaped if there is an odd number of ^V's just
3625 * before it, first set "c" just before the 'V's and then check
3626 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3627 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3628 ;
3629 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3630 {
3631 sourcing_lnum++;
3632 continue;
3633 }
3634
3635 buf[len - 1] = NUL; /* remove the NL */
3636 }
3637
3638 /*
3639 * Check for ^C here now and then, so recursive :so can be broken.
3640 */
3641 line_breakcheck();
3642 break;
3643 }
3644
3645 if (have_read)
3646 return (char_u *)ga.ga_data;
3647
3648 vim_free(ga.ga_data);
3649 return NULL;
3650}
3651
Bram Moolenaar05159a02005-02-26 23:04:13 +00003652#if defined(FEAT_PROFILE) || defined(PROTO)
3653/*
3654 * Called when starting to read a script line.
3655 * "sourcing_lnum" must be correct!
3656 * When skipping lines it may not actually be executed, but we won't find out
3657 * until later and we need to store the time now.
3658 */
3659 void
3660script_line_start()
3661{
3662 scriptitem_T *si;
3663 sn_prl_T *pp;
3664
3665 if (current_SID <= 0 || current_SID > script_items.ga_len)
3666 return;
3667 si = &SCRIPT_ITEM(current_SID);
3668 if (si->sn_prof_on && sourcing_lnum >= 1)
3669 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003670 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003671 * here isn't counted. */
3672 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3673 si->sn_prl_idx = sourcing_lnum - 1;
3674 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3675 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3676 {
3677 /* Zero counters for a line that was not used before. */
3678 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3679 pp->snp_count = 0;
3680 profile_zero(&pp->sn_prl_total);
3681 profile_zero(&pp->sn_prl_self);
3682 ++si->sn_prl_ga.ga_len;
3683 }
3684 si->sn_prl_execed = FALSE;
3685 profile_start(&si->sn_prl_start);
3686 profile_zero(&si->sn_prl_children);
3687 profile_get_wait(&si->sn_prl_wait);
3688 }
3689}
3690
3691/*
3692 * Called when actually executing a function line.
3693 */
3694 void
3695script_line_exec()
3696{
3697 scriptitem_T *si;
3698
3699 if (current_SID <= 0 || current_SID > script_items.ga_len)
3700 return;
3701 si = &SCRIPT_ITEM(current_SID);
3702 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3703 si->sn_prl_execed = TRUE;
3704}
3705
3706/*
3707 * Called when done with a function line.
3708 */
3709 void
3710script_line_end()
3711{
3712 scriptitem_T *si;
3713 sn_prl_T *pp;
3714
3715 if (current_SID <= 0 || current_SID > script_items.ga_len)
3716 return;
3717 si = &SCRIPT_ITEM(current_SID);
3718 if (si->sn_prof_on && si->sn_prl_idx >= 0
3719 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3720 {
3721 if (si->sn_prl_execed)
3722 {
3723 pp = &PRL_ITEM(si, si->sn_prl_idx);
3724 ++pp->snp_count;
3725 profile_end(&si->sn_prl_start);
3726 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003727 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003728 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3729 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003730 }
3731 si->sn_prl_idx = -1;
3732 }
3733}
3734#endif
3735
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736/*
3737 * ":scriptencoding": Set encoding conversion for a sourced script.
3738 * Without the multi-byte feature it's simply ignored.
3739 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003740 void
3741ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003742 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743{
3744#ifdef FEAT_MBYTE
3745 struct source_cookie *sp;
3746 char_u *name;
3747
3748 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3749 {
3750 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3751 return;
3752 }
3753
3754 if (*eap->arg != NUL)
3755 {
3756 name = enc_canonize(eap->arg);
3757 if (name == NULL) /* out of memory */
3758 return;
3759 }
3760 else
3761 name = eap->arg;
3762
3763 /* Setup for conversion from the specified encoding to 'encoding'. */
3764 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3765 convert_setup(&sp->conv, name, p_enc);
3766
3767 if (name != eap->arg)
3768 vim_free(name);
3769#endif
3770}
3771
3772#if defined(FEAT_EVAL) || defined(PROTO)
3773/*
3774 * ":finish": Mark a sourced file as finished.
3775 */
3776 void
3777ex_finish(eap)
3778 exarg_T *eap;
3779{
3780 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3781 do_finish(eap, FALSE);
3782 else
3783 EMSG(_("E168: :finish used outside of a sourced file"));
3784}
3785
3786/*
3787 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3788 * Also called for a pending finish at the ":endtry" or after returning from
3789 * an extra do_cmdline(). "reanimate" is used in the latter case.
3790 */
3791 void
3792do_finish(eap, reanimate)
3793 exarg_T *eap;
3794 int reanimate;
3795{
3796 int idx;
3797
3798 if (reanimate)
3799 ((struct source_cookie *)getline_cookie(eap->getline,
3800 eap->cookie))->finished = FALSE;
3801
3802 /*
3803 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3804 * not in its finally clause (which then is to be executed next) is found.
3805 * In this case, make the ":finish" pending for execution at the ":endtry".
3806 * Otherwise, finish normally.
3807 */
3808 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3809 if (idx >= 0)
3810 {
3811 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3812 report_make_pending(CSTP_FINISH, NULL);
3813 }
3814 else
3815 ((struct source_cookie *)getline_cookie(eap->getline,
3816 eap->cookie))->finished = TRUE;
3817}
3818
3819
3820/*
3821 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3822 * message for missing ":endif".
3823 * Return FALSE when not sourcing a file.
3824 */
3825 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003826source_finished(fgetline, cookie)
3827 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003828 void *cookie;
3829{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003830 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003831 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003832 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003833}
3834#endif
3835
3836#if defined(FEAT_LISTCMDS) || defined(PROTO)
3837/*
3838 * ":checktime [buffer]"
3839 */
3840 void
3841ex_checktime(eap)
3842 exarg_T *eap;
3843{
3844 buf_T *buf;
3845 int save_no_check_timestamps = no_check_timestamps;
3846
3847 no_check_timestamps = 0;
3848 if (eap->addr_count == 0) /* default is all buffers */
3849 check_timestamps(FALSE);
3850 else
3851 {
3852 buf = buflist_findnr((int)eap->line2);
3853 if (buf != NULL) /* cannot happen? */
3854 (void)buf_check_timestamp(buf, FALSE);
3855 }
3856 no_check_timestamps = save_no_check_timestamps;
3857}
3858#endif
3859
Bram Moolenaar071d4272004-06-13 20:20:40 +00003860#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3861 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3862static char *get_locale_val __ARGS((int what));
3863
3864 static char *
3865get_locale_val(what)
3866 int what;
3867{
3868 char *loc;
3869
3870 /* Obtain the locale value from the libraries. For DJGPP this is
3871 * redefined and it doesn't use the arguments. */
3872 loc = setlocale(what, NULL);
3873
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003874# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003875 if (loc != NULL)
3876 {
3877 char_u *p;
3878
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003879 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3880 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 p = vim_strchr(loc, '=');
3882 if (p != NULL)
3883 {
3884 loc = ++p;
3885 while (*p != NUL) /* remove trailing newline */
3886 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003887 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888 {
3889 *p = NUL;
3890 break;
3891 }
3892 ++p;
3893 }
3894 }
3895 }
3896# endif
3897
3898 return loc;
3899}
3900#endif
3901
3902
3903#ifdef WIN32
3904/*
3905 * On MS-Windows locale names are strings like "German_Germany.1252", but
3906 * gettext expects "de". Try to translate one into another here for a few
3907 * supported languages.
3908 */
3909 static char_u *
3910gettext_lang(char_u *name)
3911{
3912 int i;
3913 static char *(mtable[]) = {
3914 "afrikaans", "af",
3915 "czech", "cs",
3916 "dutch", "nl",
3917 "german", "de",
3918 "english_united kingdom", "en_GB",
3919 "spanish", "es",
3920 "french", "fr",
3921 "italian", "it",
3922 "japanese", "ja",
3923 "korean", "ko",
3924 "norwegian", "no",
3925 "polish", "pl",
3926 "russian", "ru",
3927 "slovak", "sk",
3928 "swedish", "sv",
3929 "ukrainian", "uk",
3930 "chinese_china", "zh_CN",
3931 "chinese_taiwan", "zh_TW",
3932 NULL};
3933
3934 for (i = 0; mtable[i] != NULL; i += 2)
3935 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3936 return mtable[i + 1];
3937 return name;
3938}
3939#endif
3940
3941#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3942/*
3943 * Obtain the current messages language. Used to set the default for
3944 * 'helplang'. May return NULL or an empty string.
3945 */
3946 char_u *
3947get_mess_lang()
3948{
3949 char_u *p;
3950
3951# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3952# if defined(LC_MESSAGES)
3953 p = (char_u *)get_locale_val(LC_MESSAGES);
3954# else
3955 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003956 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3957 * and LC_MONETARY may be set differently for a Japanese working in the
3958 * US. */
3959 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003960# endif
3961# else
3962 p = mch_getenv((char_u *)"LC_ALL");
3963 if (p == NULL || *p == NUL)
3964 {
3965 p = mch_getenv((char_u *)"LC_MESSAGES");
3966 if (p == NULL || *p == NUL)
3967 p = mch_getenv((char_u *)"LANG");
3968 }
3969# endif
3970# ifdef WIN32
3971 p = gettext_lang(p);
3972# endif
3973 return p;
3974}
3975#endif
3976
Bram Moolenaardef9e822004-12-31 20:58:58 +00003977/* Complicated #if; matches with where get_mess_env() is used below. */
3978#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3979 && defined(LC_MESSAGES))) \
3980 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3981 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3982 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003983static char_u *get_mess_env __ARGS((void));
3984
3985/*
3986 * Get the language used for messages from the environment.
3987 */
3988 static char_u *
3989get_mess_env()
3990{
3991 char_u *p;
3992
3993 p = mch_getenv((char_u *)"LC_ALL");
3994 if (p == NULL || *p == NUL)
3995 {
3996 p = mch_getenv((char_u *)"LC_MESSAGES");
3997 if (p == NULL || *p == NUL)
3998 {
3999 p = mch_getenv((char_u *)"LANG");
4000 if (p != NULL && VIM_ISDIGIT(*p))
4001 p = NULL; /* ignore something like "1043" */
4002# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4003 if (p == NULL || *p == NUL)
4004 p = (char_u *)get_locale_val(LC_CTYPE);
4005# endif
4006 }
4007 }
4008 return p;
4009}
4010#endif
4011
4012#if defined(FEAT_EVAL) || defined(PROTO)
4013
4014/*
4015 * Set the "v:lang" variable according to the current locale setting.
4016 * Also do "v:lc_time"and "v:ctype".
4017 */
4018 void
4019set_lang_var()
4020{
4021 char_u *loc;
4022
4023# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4024 loc = (char_u *)get_locale_val(LC_CTYPE);
4025# else
4026 /* setlocale() not supported: use the default value */
4027 loc = (char_u *)"C";
4028# endif
4029 set_vim_var_string(VV_CTYPE, loc, -1);
4030
4031 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4032 * back to LC_CTYPE if it's empty. */
4033# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
4034 loc = (char_u *)get_locale_val(LC_MESSAGES);
4035# else
4036 loc = get_mess_env();
4037# endif
4038 set_vim_var_string(VV_LANG, loc, -1);
4039
4040# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4041 loc = (char_u *)get_locale_val(LC_TIME);
4042# endif
4043 set_vim_var_string(VV_LC_TIME, loc, -1);
4044}
4045#endif
4046
4047#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4048 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4049/*
4050 * ":language": Set the language (locale).
4051 */
4052 void
4053ex_language(eap)
4054 exarg_T *eap;
4055{
4056 char *loc;
4057 char_u *p;
4058 char_u *name;
4059 int what = LC_ALL;
4060 char *whatstr = "";
4061#ifdef LC_MESSAGES
4062# define VIM_LC_MESSAGES LC_MESSAGES
4063#else
4064# define VIM_LC_MESSAGES 6789
4065#endif
4066
4067 name = eap->arg;
4068
4069 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4070 * Allow abbreviation, but require at least 3 characters to avoid
4071 * confusion with a two letter language name "me" or "ct". */
4072 p = skiptowhite(eap->arg);
4073 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4074 {
4075 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4076 {
4077 what = VIM_LC_MESSAGES;
4078 name = skipwhite(p);
4079 whatstr = "messages ";
4080 }
4081 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4082 {
4083 what = LC_CTYPE;
4084 name = skipwhite(p);
4085 whatstr = "ctype ";
4086 }
4087 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4088 {
4089 what = LC_TIME;
4090 name = skipwhite(p);
4091 whatstr = "time ";
4092 }
4093 }
4094
4095 if (*name == NUL)
4096 {
4097#ifndef LC_MESSAGES
4098 if (what == VIM_LC_MESSAGES)
4099 p = get_mess_env();
4100 else
4101#endif
4102 p = (char_u *)setlocale(what, NULL);
4103 if (p == NULL || *p == NUL)
4104 p = (char_u *)"Unknown";
4105 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4106 }
4107 else
4108 {
4109#ifndef LC_MESSAGES
4110 if (what == VIM_LC_MESSAGES)
4111 loc = "";
4112 else
4113#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004114 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004116#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4117 /* Make sure strtod() uses a decimal point, not a comma. */
4118 setlocale(LC_NUMERIC, "C");
4119#endif
4120 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121 if (loc == NULL)
4122 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4123 else
4124 {
4125#ifdef HAVE_NL_MSG_CAT_CNTR
4126 /* Need to do this for GNU gettext, otherwise cached translations
4127 * will be used again. */
4128 extern int _nl_msg_cat_cntr;
4129
4130 ++_nl_msg_cat_cntr;
4131#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004132 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4134
4135 if (what != LC_TIME)
4136 {
4137 /* Tell gettext() what to translate to. It apparently doesn't
4138 * use the currently effective locale. Also do this when
4139 * FEAT_GETTEXT isn't defined, so that shell commands use this
4140 * value. */
4141 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004142 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004143 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004144# ifdef WIN32
4145 /* Apparently MS-Windows printf() may cause a crash when
4146 * we give it 8-bit text while it's expecting text in the
4147 * current locale. This call avoids that. */
4148 setlocale(LC_CTYPE, "C");
4149# endif
4150 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004151 if (what != LC_CTYPE)
4152 {
4153 char_u *mname;
4154#ifdef WIN32
4155 mname = gettext_lang(name);
4156#else
4157 mname = name;
4158#endif
4159 vim_setenv((char_u *)"LC_MESSAGES", mname);
4160#ifdef FEAT_MULTI_LANG
4161 set_helplang_default(mname);
4162#endif
4163 }
4164
4165 /* Set $LC_CTYPE, because it overrules $LANG, and
4166 * gtk_set_locale() calls setlocale() again. gnome_init()
4167 * sets $LC_CTYPE to "en_US" (that's a bug!). */
4168 if (what != VIM_LC_MESSAGES)
4169 vim_setenv((char_u *)"LC_CTYPE", name);
4170# ifdef FEAT_GUI_GTK
4171 /* Let GTK know what locale we're using. Not sure this is
4172 * really needed... */
4173 if (gui.in_use)
4174 (void)gtk_set_locale();
4175# endif
4176 }
4177
4178# ifdef FEAT_EVAL
4179 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4180 set_lang_var();
4181# endif
4182 }
4183 }
4184}
4185
4186# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4187/*
4188 * Function given to ExpandGeneric() to obtain the possible arguments of the
4189 * ":language" command.
4190 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191 char_u *
4192get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004193 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194 int idx;
4195{
4196 if (idx == 0)
4197 return (char_u *)"messages";
4198 if (idx == 1)
4199 return (char_u *)"ctype";
4200 if (idx == 2)
4201 return (char_u *)"time";
4202 return NULL;
4203}
4204# endif
4205
4206#endif