blob: 8a7498a58228839faccce90c1a5de88d9934e5b4 [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;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001168
1169 /* Default: expand subcommands. */
1170 xp->xp_context = EXPAND_PROFILE;
1171 pexpand_what = PEXP_SUBCMD;
1172 xp->xp_pattern = arg;
1173
1174 end_subcmd = skiptowhite(arg);
1175 if (*end_subcmd == NUL)
1176 return;
1177
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001178 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001179 {
1180 xp->xp_context = EXPAND_FILES;
1181 xp->xp_pattern = skipwhite(end_subcmd);
1182 return;
1183 }
1184
1185 /* TODO: expand function names after "func" */
1186 xp->xp_context = EXPAND_NOTHING;
1187}
1188
Bram Moolenaar05159a02005-02-26 23:04:13 +00001189/*
1190 * Dump the profiling info.
1191 */
1192 void
1193profile_dump()
1194{
1195 FILE *fd;
1196
1197 if (profile_fname != NULL)
1198 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001199 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001200 if (fd == NULL)
1201 EMSG2(_(e_notopen), profile_fname);
1202 else
1203 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001204 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001205 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001206 fclose(fd);
1207 }
1208 }
1209}
1210
1211/*
1212 * Start profiling script "fp".
1213 */
1214 static void
1215script_do_profile(si)
1216 scriptitem_T *si;
1217{
1218 si->sn_pr_count = 0;
1219 profile_zero(&si->sn_pr_total);
1220 profile_zero(&si->sn_pr_self);
1221
1222 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1223 si->sn_prl_idx = -1;
1224 si->sn_prof_on = TRUE;
1225 si->sn_pr_nest = 0;
1226}
1227
1228/*
1229 * save time when starting to invoke another script or function.
1230 */
1231 void
1232script_prof_save(tm)
1233 proftime_T *tm; /* place to store wait time */
1234{
1235 scriptitem_T *si;
1236
1237 if (current_SID > 0 && current_SID <= script_items.ga_len)
1238 {
1239 si = &SCRIPT_ITEM(current_SID);
1240 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1241 profile_start(&si->sn_pr_child);
1242 }
1243 profile_get_wait(tm);
1244}
1245
1246/*
1247 * Count time spent in children after invoking another script or function.
1248 */
1249 void
1250script_prof_restore(tm)
1251 proftime_T *tm;
1252{
1253 scriptitem_T *si;
1254
1255 if (current_SID > 0 && current_SID <= script_items.ga_len)
1256 {
1257 si = &SCRIPT_ITEM(current_SID);
1258 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1259 {
1260 profile_end(&si->sn_pr_child);
1261 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1262 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1263 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1264 }
1265 }
1266}
1267
1268static proftime_T inchar_time;
1269
1270/*
1271 * Called when starting to wait for the user to type a character.
1272 */
1273 void
1274prof_inchar_enter()
1275{
1276 profile_start(&inchar_time);
1277}
1278
1279/*
1280 * Called when finished waiting for the user to type a character.
1281 */
1282 void
1283prof_inchar_exit()
1284{
1285 profile_end(&inchar_time);
1286 profile_add(&prof_wait_time, &inchar_time);
1287}
1288
1289/*
1290 * Dump the profiling results for all scripts in file "fd".
1291 */
1292 static void
1293script_dump_profile(fd)
1294 FILE *fd;
1295{
1296 int id;
1297 scriptitem_T *si;
1298 int i;
1299 FILE *sfd;
1300 sn_prl_T *pp;
1301
1302 for (id = 1; id <= script_items.ga_len; ++id)
1303 {
1304 si = &SCRIPT_ITEM(id);
1305 if (si->sn_prof_on)
1306 {
1307 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1308 if (si->sn_pr_count == 1)
1309 fprintf(fd, "Sourced 1 time\n");
1310 else
1311 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1312 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1313 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1314 fprintf(fd, "\n");
1315 fprintf(fd, "count total (s) self (s)\n");
1316
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001317 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001318 if (sfd == NULL)
1319 fprintf(fd, "Cannot open file!\n");
1320 else
1321 {
1322 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1323 {
1324 if (vim_fgets(IObuff, IOSIZE, sfd))
1325 break;
1326 pp = &PRL_ITEM(si, i);
1327 if (pp->snp_count > 0)
1328 {
1329 fprintf(fd, "%5d ", pp->snp_count);
1330 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1331 fprintf(fd, " ");
1332 else
1333 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1334 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1335 }
1336 else
1337 fprintf(fd, " ");
1338 fprintf(fd, "%s", IObuff);
1339 }
1340 fclose(sfd);
1341 }
1342 fprintf(fd, "\n");
1343 }
1344 }
1345}
1346
1347/*
1348 * Return TRUE when a function defined in the current script should be
1349 * profiled.
1350 */
1351 int
1352prof_def_func()
1353{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001354 if (current_SID > 0)
1355 return SCRIPT_ITEM(current_SID).sn_pr_force;
1356 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001357}
1358
1359# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001360#endif
1361
1362/*
1363 * If 'autowrite' option set, try to write the file.
1364 * Careful: autocommands may make "buf" invalid!
1365 *
1366 * return FAIL for failure, OK otherwise
1367 */
1368 int
1369autowrite(buf, forceit)
1370 buf_T *buf;
1371 int forceit;
1372{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001373 int r;
1374
Bram Moolenaar071d4272004-06-13 20:20:40 +00001375 if (!(p_aw || p_awa) || !p_write
1376#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001377 /* never autowrite a "nofile" or "nowrite" buffer */
1378 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001379#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001380 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001381 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001382 r = buf_write_all(buf, forceit);
1383
1384 /* Writing may succeed but the buffer still changed, e.g., when there is a
1385 * conversion error. We do want to return FAIL then. */
1386 if (buf_valid(buf) && bufIsChanged(buf))
1387 r = FAIL;
1388 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001389}
1390
1391/*
1392 * flush all buffers, except the ones that are readonly
1393 */
1394 void
1395autowrite_all()
1396{
1397 buf_T *buf;
1398
1399 if (!(p_aw || p_awa) || !p_write)
1400 return;
1401 for (buf = firstbuf; buf; buf = buf->b_next)
1402 if (bufIsChanged(buf) && !buf->b_p_ro)
1403 {
1404 (void)buf_write_all(buf, FALSE);
1405#ifdef FEAT_AUTOCMD
1406 /* an autocommand may have deleted the buffer */
1407 if (!buf_valid(buf))
1408 buf = firstbuf;
1409#endif
1410 }
1411}
1412
1413/*
1414 * return TRUE if buffer was changed and cannot be abandoned.
1415 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001416 int
1417check_changed(buf, checkaw, mult_win, forceit, allbuf)
1418 buf_T *buf;
1419 int checkaw; /* do autowrite if buffer was changed */
1420 int mult_win; /* check also when several wins for the buf */
1421 int forceit;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001422 int allbuf UNUSED; /* may write all buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001423{
1424 if ( !forceit
1425 && bufIsChanged(buf)
1426 && (mult_win || buf->b_nwindows <= 1)
1427 && (!checkaw || autowrite(buf, forceit) == FAIL))
1428 {
1429#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1430 if ((p_confirm || cmdmod.confirm) && p_write)
1431 {
1432 buf_T *buf2;
1433 int count = 0;
1434
1435 if (allbuf)
1436 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1437 if (bufIsChanged(buf2)
1438 && (buf2->b_ffname != NULL
1439# ifdef FEAT_BROWSE
1440 || cmdmod.browse
1441# endif
1442 ))
1443 ++count;
1444# ifdef FEAT_AUTOCMD
1445 if (!buf_valid(buf))
1446 /* Autocommand deleted buffer, oops! It's not changed now. */
1447 return FALSE;
1448# endif
1449 dialog_changed(buf, count > 1);
1450# ifdef FEAT_AUTOCMD
1451 if (!buf_valid(buf))
1452 /* Autocommand deleted buffer, oops! It's not changed now. */
1453 return FALSE;
1454# endif
1455 return bufIsChanged(buf);
1456 }
1457#endif
1458 EMSG(_(e_nowrtmsg));
1459 return TRUE;
1460 }
1461 return FALSE;
1462}
1463
1464#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1465
1466#if defined(FEAT_BROWSE) || defined(PROTO)
1467/*
1468 * When wanting to write a file without a file name, ask the user for a name.
1469 */
1470 void
1471browse_save_fname(buf)
1472 buf_T *buf;
1473{
1474 if (buf->b_fname == NULL)
1475 {
1476 char_u *fname;
1477
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001478 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1479 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001480 if (fname != NULL)
1481 {
1482 if (setfname(buf, fname, NULL, TRUE) == OK)
1483 buf->b_flags |= BF_NOTEDITED;
1484 vim_free(fname);
1485 }
1486 }
1487}
1488#endif
1489
1490/*
1491 * Ask the user what to do when abondoning a changed buffer.
1492 * Must check 'write' option first!
1493 */
1494 void
1495dialog_changed(buf, checkall)
1496 buf_T *buf;
1497 int checkall; /* may abandon all changed buffers */
1498{
1499 char_u buff[IOSIZE];
1500 int ret;
1501 buf_T *buf2;
1502
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001503 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 (buf->b_fname != NULL) ?
1505 buf->b_fname : (char_u *)_("Untitled"));
1506 if (checkall)
1507 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1508 else
1509 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1510
1511 if (ret == VIM_YES)
1512 {
1513#ifdef FEAT_BROWSE
1514 /* May get file name, when there is none */
1515 browse_save_fname(buf);
1516#endif
1517 if (buf->b_fname != NULL) /* didn't hit Cancel */
1518 (void)buf_write_all(buf, FALSE);
1519 }
1520 else if (ret == VIM_NO)
1521 {
1522 unchanged(buf, TRUE);
1523 }
1524 else if (ret == VIM_ALL)
1525 {
1526 /*
1527 * Write all modified files that can be written.
1528 * Skip readonly buffers, these need to be confirmed
1529 * individually.
1530 */
1531 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1532 {
1533 if (bufIsChanged(buf2)
1534 && (buf2->b_ffname != NULL
1535#ifdef FEAT_BROWSE
1536 || cmdmod.browse
1537#endif
1538 )
1539 && !buf2->b_p_ro)
1540 {
1541#ifdef FEAT_BROWSE
1542 /* May get file name, when there is none */
1543 browse_save_fname(buf2);
1544#endif
1545 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1546 (void)buf_write_all(buf2, FALSE);
1547#ifdef FEAT_AUTOCMD
1548 /* an autocommand may have deleted the buffer */
1549 if (!buf_valid(buf2))
1550 buf2 = firstbuf;
1551#endif
1552 }
1553 }
1554 }
1555 else if (ret == VIM_DISCARDALL)
1556 {
1557 /*
1558 * mark all buffers as unchanged
1559 */
1560 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1561 unchanged(buf2, TRUE);
1562 }
1563}
1564#endif
1565
1566/*
1567 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1568 * hidden, autowriting it or unloading it.
1569 */
1570 int
1571can_abandon(buf, forceit)
1572 buf_T *buf;
1573 int forceit;
1574{
1575 return ( P_HID(buf)
1576 || !bufIsChanged(buf)
1577 || buf->b_nwindows > 1
1578 || autowrite(buf, forceit) == OK
1579 || forceit);
1580}
1581
1582/*
1583 * Return TRUE if any buffer was changed and cannot be abandoned.
1584 * That changed buffer becomes the current buffer.
1585 */
1586 int
1587check_changed_any(hidden)
1588 int hidden; /* Only check hidden buffers */
1589{
1590 buf_T *buf;
1591 int save;
1592#ifdef FEAT_WINDOWS
1593 win_T *wp;
1594#endif
1595
1596 for (;;)
1597 {
1598 /* check curbuf first: if it was changed we can't abandon it */
1599 if (!hidden && curbufIsChanged())
1600 buf = curbuf;
1601 else
1602 {
1603 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1604 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1605 break;
1606 }
1607 if (buf == NULL) /* No buffers changed */
1608 return FALSE;
1609
Bram Moolenaar373154b2007-02-13 05:19:30 +00001610 /* Try auto-writing the buffer. If this fails but the buffer no
1611 * longer exists it's not changed, that's OK. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001612 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1613 break; /* didn't save - still changes */
1614 }
1615
1616 exiting = FALSE;
1617#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1618 /*
1619 * When ":confirm" used, don't give an error message.
1620 */
1621 if (!(p_confirm || cmdmod.confirm))
1622#endif
1623 {
1624 /* There must be a wait_return for this message, do_buffer()
1625 * may cause a redraw. But wait_return() is a no-op when vgetc()
1626 * is busy (Quit used from window menu), then make sure we don't
1627 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001628 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001629 {
1630 msg_row = cmdline_row;
1631 msg_col = 0;
1632 msg_didout = FALSE;
1633 }
1634 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1635 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1636 buf->b_fname))
1637 {
1638 save = no_wait_return;
1639 no_wait_return = FALSE;
1640 wait_return(FALSE);
1641 no_wait_return = save;
1642 }
1643 }
1644
1645#ifdef FEAT_WINDOWS
1646 /* Try to find a window that contains the buffer. */
1647 if (buf != curbuf)
1648 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1649 if (wp->w_buffer == buf)
1650 {
1651 win_goto(wp);
1652# ifdef FEAT_AUTOCMD
1653 /* Paranoia: did autocms wipe out the buffer with changes? */
1654 if (!buf_valid(buf))
1655 return TRUE;
1656# endif
1657 break;
1658 }
1659#endif
1660
1661 /* Open the changed buffer in the current window. */
1662 if (buf != curbuf)
1663 set_curbuf(buf, DOBUF_GOTO);
1664
1665 return TRUE;
1666}
1667
1668/*
1669 * return FAIL if there is no file name, OK if there is one
1670 * give error message for FAIL
1671 */
1672 int
1673check_fname()
1674{
1675 if (curbuf->b_ffname == NULL)
1676 {
1677 EMSG(_(e_noname));
1678 return FAIL;
1679 }
1680 return OK;
1681}
1682
1683/*
1684 * flush the contents of a buffer, unless it has no file name
1685 *
1686 * return FAIL for failure, OK otherwise
1687 */
1688 int
1689buf_write_all(buf, forceit)
1690 buf_T *buf;
1691 int forceit;
1692{
1693 int retval;
1694#ifdef FEAT_AUTOCMD
1695 buf_T *old_curbuf = curbuf;
1696#endif
1697
1698 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1699 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1700 FALSE, forceit, TRUE, FALSE));
1701#ifdef FEAT_AUTOCMD
1702 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001703 {
1704 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001705 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001706 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001707#endif
1708 return retval;
1709}
1710
1711/*
1712 * Code to handle the argument list.
1713 */
1714
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001715static char_u *do_one_arg __ARGS((char_u *str));
1716static int do_arglist __ARGS((char_u *str, int what, int after));
1717static void alist_check_arg_idx __ARGS((void));
1718static int editing_arg_idx __ARGS((win_T *win));
1719#ifdef FEAT_LISTCMDS
1720static int alist_add_list __ARGS((int count, char_u **files, int after));
1721#endif
1722#define AL_SET 1
1723#define AL_ADD 2
1724#define AL_DEL 3
1725
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001727 * Isolate one argument, taking backticks.
1728 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729 * Return a pointer to the start of the next argument.
1730 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001731 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732do_one_arg(str)
1733 char_u *str;
1734{
1735 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001736 int inbacktick;
1737
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738 inbacktick = FALSE;
1739 for (p = str; *str; ++str)
1740 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001741 /* When the backslash is used for escaping the special meaning of a
1742 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743 if (rem_backslash(str))
1744 {
1745 *p++ = *str++;
1746 *p++ = *str;
1747 }
1748 else
1749 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001750 /* An item ends at a space not in backticks */
1751 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001753 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001754 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001755 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756 }
1757 }
1758 str = skipwhite(str);
1759 *p = NUL;
1760
1761 return str;
1762}
1763
Bram Moolenaar86b68352004-12-27 21:59:20 +00001764/*
1765 * Separate the arguments in "str" and return a list of pointers in the
1766 * growarray "gap".
1767 */
1768 int
1769get_arglist(gap, str)
1770 garray_T *gap;
1771 char_u *str;
1772{
1773 ga_init2(gap, (int)sizeof(char_u *), 20);
1774 while (*str != NUL)
1775 {
1776 if (ga_grow(gap, 1) == FAIL)
1777 {
1778 ga_clear(gap);
1779 return FAIL;
1780 }
1781 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1782
1783 /* Isolate one argument, change it in-place, put a NUL after it. */
1784 str = do_one_arg(str);
1785 }
1786 return OK;
1787}
1788
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001789#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001790/*
1791 * Parse a list of arguments (file names), expand them and return in
1792 * "fnames[fcountp]".
1793 * Return FAIL or OK.
1794 */
1795 int
1796get_arglist_exp(str, fcountp, fnamesp)
1797 char_u *str;
1798 int *fcountp;
1799 char_u ***fnamesp;
1800{
1801 garray_T ga;
1802 int i;
1803
1804 if (get_arglist(&ga, str) == FAIL)
1805 return FAIL;
1806 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1807 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1808 ga_clear(&ga);
1809 return i;
1810}
1811#endif
1812
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1814/*
1815 * Redefine the argument list.
1816 */
1817 void
1818set_arglist(str)
1819 char_u *str;
1820{
1821 do_arglist(str, AL_SET, 0);
1822}
1823#endif
1824
1825/*
1826 * "what" == AL_SET: Redefine the argument list to 'str'.
1827 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1828 * "what" == AL_DEL: remove files in 'str' from the argument list.
1829 *
1830 * Return FAIL for failure, OK otherwise.
1831 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832 static int
1833do_arglist(str, what, after)
1834 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001835 int what UNUSED;
1836 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001837{
1838 garray_T new_ga;
1839 int exp_count;
1840 char_u **exp_files;
1841 int i;
1842#ifdef FEAT_LISTCMDS
1843 char_u *p;
1844 int match;
1845#endif
1846
1847 /*
1848 * Collect all file name arguments in "new_ga".
1849 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001850 if (get_arglist(&new_ga, str) == FAIL)
1851 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852
1853#ifdef FEAT_LISTCMDS
1854 if (what == AL_DEL)
1855 {
1856 regmatch_T regmatch;
1857 int didone;
1858
1859 /*
1860 * Delete the items: use each item as a regexp and find a match in the
1861 * argument list.
1862 */
1863#ifdef CASE_INSENSITIVE_FILENAME
1864 regmatch.rm_ic = TRUE; /* Always ignore case */
1865#else
1866 regmatch.rm_ic = FALSE; /* Never ignore case */
1867#endif
1868 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1869 {
1870 p = ((char_u **)new_ga.ga_data)[i];
1871 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1872 if (p == NULL)
1873 break;
1874 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1875 if (regmatch.regprog == NULL)
1876 {
1877 vim_free(p);
1878 break;
1879 }
1880
1881 didone = FALSE;
1882 for (match = 0; match < ARGCOUNT; ++match)
1883 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1884 (colnr_T)0))
1885 {
1886 didone = TRUE;
1887 vim_free(ARGLIST[match].ae_fname);
1888 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1889 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1890 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 if (curwin->w_arg_idx > match)
1892 --curwin->w_arg_idx;
1893 --match;
1894 }
1895
1896 vim_free(regmatch.regprog);
1897 vim_free(p);
1898 if (!didone)
1899 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1900 }
1901 ga_clear(&new_ga);
1902 }
1903 else
1904#endif
1905 {
1906 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1907 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1908 ga_clear(&new_ga);
1909 if (i == FAIL)
1910 return FAIL;
1911 if (exp_count == 0)
1912 {
1913 EMSG(_(e_nomatch));
1914 return FAIL;
1915 }
1916
1917#ifdef FEAT_LISTCMDS
1918 if (what == AL_ADD)
1919 {
1920 (void)alist_add_list(exp_count, exp_files, after);
1921 vim_free(exp_files);
1922 }
1923 else /* what == AL_SET */
1924#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001925 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 }
1927
1928 alist_check_arg_idx();
1929
1930 return OK;
1931}
1932
1933/*
1934 * Check the validity of the arg_idx for each other window.
1935 */
1936 static void
1937alist_check_arg_idx()
1938{
1939#ifdef FEAT_WINDOWS
1940 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001941 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942
Bram Moolenaarf740b292006-02-16 22:11:02 +00001943 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944 if (win->w_alist == curwin->w_alist)
1945 check_arg_idx(win);
1946#else
1947 check_arg_idx(curwin);
1948#endif
1949}
1950
1951/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001952 * Return TRUE if window "win" is editing then file at the current argument
1953 * index.
1954 */
1955 static int
1956editing_arg_idx(win)
1957 win_T *win;
1958{
1959 return !(win->w_arg_idx >= WARGCOUNT(win)
1960 || (win->w_buffer->b_fnum
1961 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1962 && (win->w_buffer->b_ffname == NULL
1963 || !(fullpathcmp(
1964 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1965 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1966}
1967
1968/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969 * Check if window "win" is editing the w_arg_idx file in its argument list.
1970 */
1971 void
1972check_arg_idx(win)
1973 win_T *win;
1974{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001975 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976 {
1977 /* We are not editing the current entry in the argument list.
1978 * Set "arg_had_last" if we are editing the last one. */
1979 win->w_arg_idx_invalid = TRUE;
1980 if (win->w_arg_idx != WARGCOUNT(win) - 1
1981 && arg_had_last == FALSE
1982#ifdef FEAT_WINDOWS
1983 && ALIST(win) == &global_alist
1984#endif
1985 && GARGCOUNT > 0
1986 && win->w_arg_idx < GARGCOUNT
1987 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1988 || (win->w_buffer->b_ffname != NULL
1989 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1990 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1991 arg_had_last = TRUE;
1992 }
1993 else
1994 {
1995 /* We are editing the current entry in the argument list.
1996 * Set "arg_had_last" if it's also the last one */
1997 win->w_arg_idx_invalid = FALSE;
1998 if (win->w_arg_idx == WARGCOUNT(win) - 1
1999#ifdef FEAT_WINDOWS
2000 && win->w_alist == &global_alist
2001#endif
2002 )
2003 arg_had_last = TRUE;
2004 }
2005}
2006
2007/*
2008 * ":args", ":argslocal" and ":argsglobal".
2009 */
2010 void
2011ex_args(eap)
2012 exarg_T *eap;
2013{
2014 int i;
2015
2016 if (eap->cmdidx != CMD_args)
2017 {
2018#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2019 alist_unlink(ALIST(curwin));
2020 if (eap->cmdidx == CMD_argglobal)
2021 ALIST(curwin) = &global_alist;
2022 else /* eap->cmdidx == CMD_arglocal */
2023 alist_new();
2024#else
2025 ex_ni(eap);
2026 return;
2027#endif
2028 }
2029
2030 if (!ends_excmd(*eap->arg))
2031 {
2032 /*
2033 * ":args file ..": define new argument list, handle like ":next"
2034 * Also for ":argslocal file .." and ":argsglobal file ..".
2035 */
2036 ex_next(eap);
2037 }
2038 else
2039#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2040 if (eap->cmdidx == CMD_args)
2041#endif
2042 {
2043 /*
2044 * ":args": list arguments.
2045 */
2046 if (ARGCOUNT > 0)
2047 {
2048 /* Overwrite the command, for a short list there is no scrolling
2049 * required and no wait_return(). */
2050 gotocmdline(TRUE);
2051 for (i = 0; i < ARGCOUNT; ++i)
2052 {
2053 if (i == curwin->w_arg_idx)
2054 msg_putchar('[');
2055 msg_outtrans(alist_name(&ARGLIST[i]));
2056 if (i == curwin->w_arg_idx)
2057 msg_putchar(']');
2058 msg_putchar(' ');
2059 }
2060 }
2061 }
2062#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2063 else if (eap->cmdidx == CMD_arglocal)
2064 {
2065 garray_T *gap = &curwin->w_alist->al_ga;
2066
2067 /*
2068 * ":argslocal": make a local copy of the global argument list.
2069 */
2070 if (ga_grow(gap, GARGCOUNT) == OK)
2071 for (i = 0; i < GARGCOUNT; ++i)
2072 if (GARGLIST[i].ae_fname != NULL)
2073 {
2074 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2075 vim_strsave(GARGLIST[i].ae_fname);
2076 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2077 GARGLIST[i].ae_fnum;
2078 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002079 }
2080 }
2081#endif
2082}
2083
2084/*
2085 * ":previous", ":sprevious", ":Next" and ":sNext".
2086 */
2087 void
2088ex_previous(eap)
2089 exarg_T *eap;
2090{
2091 /* If past the last one already, go to the last one. */
2092 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2093 do_argfile(eap, ARGCOUNT - 1);
2094 else
2095 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2096}
2097
2098/*
2099 * ":rewind", ":first", ":sfirst" and ":srewind".
2100 */
2101 void
2102ex_rewind(eap)
2103 exarg_T *eap;
2104{
2105 do_argfile(eap, 0);
2106}
2107
2108/*
2109 * ":last" and ":slast".
2110 */
2111 void
2112ex_last(eap)
2113 exarg_T *eap;
2114{
2115 do_argfile(eap, ARGCOUNT - 1);
2116}
2117
2118/*
2119 * ":argument" and ":sargument".
2120 */
2121 void
2122ex_argument(eap)
2123 exarg_T *eap;
2124{
2125 int i;
2126
2127 if (eap->addr_count > 0)
2128 i = eap->line2 - 1;
2129 else
2130 i = curwin->w_arg_idx;
2131 do_argfile(eap, i);
2132}
2133
2134/*
2135 * Edit file "argn" of the argument lists.
2136 */
2137 void
2138do_argfile(eap, argn)
2139 exarg_T *eap;
2140 int argn;
2141{
2142 int other;
2143 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002144 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145
2146 if (argn < 0 || argn >= ARGCOUNT)
2147 {
2148 if (ARGCOUNT <= 1)
2149 EMSG(_("E163: There is only one file to edit"));
2150 else if (argn < 0)
2151 EMSG(_("E164: Cannot go before first file"));
2152 else
2153 EMSG(_("E165: Cannot go beyond last file"));
2154 }
2155 else
2156 {
2157 setpcmark();
2158#ifdef FEAT_GUI
2159 need_mouse_correct = TRUE;
2160#endif
2161
2162#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002163 /* split window or create new tab page first */
2164 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 {
2166 if (win_split(0, 0) == FAIL)
2167 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002168 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002169 }
2170 else
2171#endif
2172 {
2173 /*
2174 * if 'hidden' set, only check for changed file when re-editing
2175 * the same buffer
2176 */
2177 other = TRUE;
2178 if (P_HID(curbuf))
2179 {
2180 p = fix_fname(alist_name(&ARGLIST[argn]));
2181 other = otherfile(p);
2182 vim_free(p);
2183 }
2184 if ((!P_HID(curbuf) || !other)
2185 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2186 return;
2187 }
2188
2189 curwin->w_arg_idx = argn;
2190 if (argn == ARGCOUNT - 1
2191#ifdef FEAT_WINDOWS
2192 && curwin->w_alist == &global_alist
2193#endif
2194 )
2195 arg_had_last = TRUE;
2196
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002197 /* Edit the file; always use the last known line number.
2198 * When it fails (e.g. Abort for already edited file) restore the
2199 * argument index. */
2200 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002201 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002202 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2203 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002204 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002205 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002206 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002207 setmark('\'');
2208 }
2209}
2210
2211/*
2212 * ":next", and commands that behave like it.
2213 */
2214 void
2215ex_next(eap)
2216 exarg_T *eap;
2217{
2218 int i;
2219
2220 /*
2221 * check for changed buffer now, if this fails the argument list is not
2222 * redefined.
2223 */
2224 if ( P_HID(curbuf)
2225 || eap->cmdidx == CMD_snext
2226 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2227 {
2228 if (*eap->arg != NUL) /* redefine file list */
2229 {
2230 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2231 return;
2232 i = 0;
2233 }
2234 else
2235 i = curwin->w_arg_idx + (int)eap->line2;
2236 do_argfile(eap, i);
2237 }
2238}
2239
2240#ifdef FEAT_LISTCMDS
2241/*
2242 * ":argedit"
2243 */
2244 void
2245ex_argedit(eap)
2246 exarg_T *eap;
2247{
2248 int fnum;
2249 int i;
2250 char_u *s;
2251
2252 /* Add the argument to the buffer list and get the buffer number. */
2253 fnum = buflist_add(eap->arg, BLN_LISTED);
2254
2255 /* Check if this argument is already in the argument list. */
2256 for (i = 0; i < ARGCOUNT; ++i)
2257 if (ARGLIST[i].ae_fnum == fnum)
2258 break;
2259 if (i == ARGCOUNT)
2260 {
2261 /* Can't find it, add it to the argument list. */
2262 s = vim_strsave(eap->arg);
2263 if (s == NULL)
2264 return;
2265 i = alist_add_list(1, &s,
2266 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2267 if (i < 0)
2268 return;
2269 curwin->w_arg_idx = i;
2270 }
2271
2272 alist_check_arg_idx();
2273
2274 /* Edit the argument. */
2275 do_argfile(eap, i);
2276}
2277
2278/*
2279 * ":argadd"
2280 */
2281 void
2282ex_argadd(eap)
2283 exarg_T *eap;
2284{
2285 do_arglist(eap->arg, AL_ADD,
2286 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2287#ifdef FEAT_TITLE
2288 maketitle();
2289#endif
2290}
2291
2292/*
2293 * ":argdelete"
2294 */
2295 void
2296ex_argdelete(eap)
2297 exarg_T *eap;
2298{
2299 int i;
2300 int n;
2301
2302 if (eap->addr_count > 0)
2303 {
2304 /* ":1,4argdel": Delete all arguments in the range. */
2305 if (eap->line2 > ARGCOUNT)
2306 eap->line2 = ARGCOUNT;
2307 n = eap->line2 - eap->line1 + 1;
2308 if (*eap->arg != NUL || n <= 0)
2309 EMSG(_(e_invarg));
2310 else
2311 {
2312 for (i = eap->line1; i <= eap->line2; ++i)
2313 vim_free(ARGLIST[i - 1].ae_fname);
2314 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2315 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2316 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 if (curwin->w_arg_idx >= eap->line2)
2318 curwin->w_arg_idx -= n;
2319 else if (curwin->w_arg_idx > eap->line1)
2320 curwin->w_arg_idx = eap->line1;
2321 }
2322 }
2323 else if (*eap->arg == NUL)
2324 EMSG(_(e_argreq));
2325 else
2326 do_arglist(eap->arg, AL_DEL, 0);
2327#ifdef FEAT_TITLE
2328 maketitle();
2329#endif
2330}
2331
2332/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002333 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002334 */
2335 void
2336ex_listdo(eap)
2337 exarg_T *eap;
2338{
2339 int i;
2340#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002341 win_T *wp;
2342 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002343#endif
2344 buf_T *buf;
2345 int next_fnum = 0;
2346#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2347 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002349 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350
2351#ifndef FEAT_WINDOWS
2352 if (eap->cmdidx == CMD_windo)
2353 {
2354 ex_ni(eap);
2355 return;
2356 }
2357#endif
2358
2359#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002360 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002361 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2362 * great speed improvement. */
2363 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364#endif
2365
2366 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002367 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002368 || P_HID(curbuf)
2369 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2370 {
2371 /* start at the first argument/window/buffer */
2372 i = 0;
2373#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002374 wp = firstwin;
2375 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376#endif
2377 /* set pcmark now */
2378 if (eap->cmdidx == CMD_bufdo)
2379 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2380 else
2381 setpcmark();
2382 listcmd_busy = TRUE; /* avoids setting pcmark below */
2383
2384 while (!got_int)
2385 {
2386 if (eap->cmdidx == CMD_argdo)
2387 {
2388 /* go to argument "i" */
2389 if (i == ARGCOUNT)
2390 break;
2391 /* Don't call do_argfile() when already there, it will try
2392 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002393 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002394 {
2395 /* Clear 'shm' to avoid that the file message overwrites
2396 * any output from the command. */
2397 p_shm_save = vim_strsave(p_shm);
2398 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002400 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2401 vim_free(p_shm_save);
2402 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002403 if (curwin->w_arg_idx != i)
2404 break;
2405 ++i;
2406 }
2407#ifdef FEAT_WINDOWS
2408 else if (eap->cmdidx == CMD_windo)
2409 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002410 /* go to window "wp" */
2411 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002413 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002414 if (curwin != wp)
2415 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002416 wp = curwin->w_next;
2417 }
2418 else if (eap->cmdidx == CMD_tabdo)
2419 {
2420 /* go to window "tp" */
2421 if (!valid_tabpage(tp))
2422 break;
2423 goto_tabpage_tp(tp);
2424 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425 }
2426#endif
2427 else if (eap->cmdidx == CMD_bufdo)
2428 {
2429 /* Remember the number of the next listed buffer, in case
2430 * ":bwipe" is used or autocommands do something strange. */
2431 next_fnum = -1;
2432 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2433 if (buf->b_p_bl)
2434 {
2435 next_fnum = buf->b_fnum;
2436 break;
2437 }
2438 }
2439
2440 /* execute the command */
2441 do_cmdline(eap->arg, eap->getline, eap->cookie,
2442 DOCMD_VERBOSE + DOCMD_NOWAIT);
2443
2444 if (eap->cmdidx == CMD_bufdo)
2445 {
2446 /* Done? */
2447 if (next_fnum < 0)
2448 break;
2449 /* Check if the buffer still exists. */
2450 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2451 if (buf->b_fnum == next_fnum)
2452 break;
2453 if (buf == NULL)
2454 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002455
2456 /* Go to the next buffer. Clear 'shm' to avoid that the file
2457 * message overwrites any output from the command. */
2458 p_shm_save = vim_strsave(p_shm);
2459 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002461 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2462 vim_free(p_shm_save);
2463
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 /* If autocommands took us elsewhere, quit here */
2465 if (curbuf->b_fnum != next_fnum)
2466 break;
2467 }
2468
2469 if (eap->cmdidx == CMD_windo)
2470 {
2471 validate_cursor(); /* cursor may have moved */
2472#ifdef FEAT_SCROLLBIND
2473 /* required when 'scrollbind' has been set */
2474 if (curwin->w_p_scb)
2475 do_check_scrollbind(TRUE);
2476#endif
2477 }
2478 }
2479 listcmd_busy = FALSE;
2480 }
2481
2482#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002483 if (save_ei != NULL)
2484 {
2485 au_event_restore(save_ei);
2486 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2487 curbuf->b_fname, TRUE, curbuf);
2488 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002489#endif
2490}
2491
2492/*
2493 * Add files[count] to the arglist of the current window after arg "after".
2494 * The file names in files[count] must have been allocated and are taken over.
2495 * Files[] itself is not taken over.
2496 * Returns index of first added argument. Returns -1 when failed (out of mem).
2497 */
2498 static int
2499alist_add_list(count, files, after)
2500 int count;
2501 char_u **files;
2502 int after; /* where to add: 0 = before first one */
2503{
2504 int i;
2505
2506 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2507 {
2508 if (after < 0)
2509 after = 0;
2510 if (after > ARGCOUNT)
2511 after = ARGCOUNT;
2512 if (after < ARGCOUNT)
2513 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2514 (ARGCOUNT - after) * sizeof(aentry_T));
2515 for (i = 0; i < count; ++i)
2516 {
2517 ARGLIST[after + i].ae_fname = files[i];
2518 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2519 }
2520 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002521 if (curwin->w_arg_idx >= after)
2522 ++curwin->w_arg_idx;
2523 return after;
2524 }
2525
2526 for (i = 0; i < count; ++i)
2527 vim_free(files[i]);
2528 return -1;
2529}
2530
2531#endif /* FEAT_LISTCMDS */
2532
2533#ifdef FEAT_EVAL
2534/*
2535 * ":compiler[!] {name}"
2536 */
2537 void
2538ex_compiler(eap)
2539 exarg_T *eap;
2540{
2541 char_u *buf;
2542 char_u *old_cur_comp = NULL;
2543 char_u *p;
2544
2545 if (*eap->arg == NUL)
2546 {
2547 /* List all compiler scripts. */
2548 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2549 /* ) keep the indenter happy... */
2550 }
2551 else
2552 {
2553 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2554 if (buf != NULL)
2555 {
2556 if (eap->forceit)
2557 {
2558 /* ":compiler! {name}" sets global options */
2559 do_cmdline_cmd((char_u *)
2560 "command -nargs=* CompilerSet set <args>");
2561 }
2562 else
2563 {
2564 /* ":compiler! {name}" sets local options.
2565 * To remain backwards compatible "current_compiler" is always
2566 * used. A user's compiler plugin may set it, the distributed
2567 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002568 * "b:current_compiler" and restore "current_compiler".
2569 * Explicitly prepend "g:" to make it work in a function. */
2570 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 if (old_cur_comp != NULL)
2572 old_cur_comp = vim_strsave(old_cur_comp);
2573 do_cmdline_cmd((char_u *)
2574 "command -nargs=* CompilerSet setlocal <args>");
2575 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002576 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002577 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578
2579 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002580 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002581 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2582 vim_free(buf);
2583
2584 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2585
2586 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002587 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588 if (p != NULL)
2589 set_internal_string_var((char_u *)"b:current_compiler", p);
2590
2591 /* Restore "current_compiler" for ":compiler {name}". */
2592 if (!eap->forceit)
2593 {
2594 if (old_cur_comp != NULL)
2595 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002596 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597 old_cur_comp);
2598 vim_free(old_cur_comp);
2599 }
2600 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002601 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602 }
2603 }
2604 }
2605}
2606#endif
2607
2608/*
2609 * ":runtime {name}"
2610 */
2611 void
2612ex_runtime(eap)
2613 exarg_T *eap;
2614{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002615 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616}
2617
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002618static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002619
2620 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002621source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002622 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002623 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002625 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626}
2627
2628/*
2629 * Source the file "name" from all directories in 'runtimepath'.
2630 * "name" can contain wildcards.
2631 * When "all" is TRUE, source all files, otherwise only the first one.
2632 * return FAIL when no file could be sourced, OK otherwise.
2633 */
2634 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002635source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636 char_u *name;
2637 int all;
2638{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002639 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640}
2641
2642/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002643 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2644 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2646 * used.
2647 * Returns OK when at least one match found, FAIL otherwise.
2648 */
2649 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002650do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651 char_u *name;
2652 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002653 void (*callback)__ARGS((char_u *fname, void *ck));
2654 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002655{
2656 char_u *rtp;
2657 char_u *np;
2658 char_u *buf;
2659 char_u *rtp_copy;
2660 char_u *tail;
2661 int num_files;
2662 char_u **files;
2663 int i;
2664 int did_one = FALSE;
2665#ifdef AMIGA
2666 struct Process *proc = (struct Process *)FindTask(0L);
2667 APTR save_winptr = proc->pr_WindowPtr;
2668
2669 /* Avoid a requester here for a volume that doesn't exist. */
2670 proc->pr_WindowPtr = (APTR)-1L;
2671#endif
2672
2673 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2674 * value. */
2675 rtp_copy = vim_strsave(p_rtp);
2676 buf = alloc(MAXPATHL);
2677 if (buf != NULL && rtp_copy != NULL)
2678 {
2679 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002680 {
2681 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002682 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002683 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002684 verbose_leave();
2685 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002686
Bram Moolenaar071d4272004-06-13 20:20:40 +00002687 /* Loop over all entries in 'runtimepath'. */
2688 rtp = rtp_copy;
2689 while (*rtp != NUL && (all || !did_one))
2690 {
2691 /* Copy the path from 'runtimepath' to buf[]. */
2692 copy_option_part(&rtp, buf, MAXPATHL, ",");
2693 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2694 {
2695 add_pathsep(buf);
2696 tail = buf + STRLEN(buf);
2697
2698 /* Loop over all patterns in "name" */
2699 np = name;
2700 while (*np != NUL && (all || !did_one))
2701 {
2702 /* Append the pattern from "name" to buf[]. */
2703 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2704 "\t ");
2705
2706 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002707 {
2708 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002709 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002710 verbose_leave();
2711 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712
2713 /* Expand wildcards, invoke the callback for each match. */
2714 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2715 EW_FILE) == OK)
2716 {
2717 for (i = 0; i < num_files; ++i)
2718 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002719 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 did_one = TRUE;
2721 if (!all)
2722 break;
2723 }
2724 FreeWild(num_files, files);
2725 }
2726 }
2727 }
2728 }
2729 }
2730 vim_free(buf);
2731 vim_free(rtp_copy);
2732 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002733 {
2734 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002735 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002736 verbose_leave();
2737 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002738
2739#ifdef AMIGA
2740 proc->pr_WindowPtr = save_winptr;
2741#endif
2742
2743 return did_one ? OK : FAIL;
2744}
2745
2746#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2747/*
2748 * ":options"
2749 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002750 void
2751ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002752 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753{
2754 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2755}
2756#endif
2757
2758/*
2759 * ":source {fname}"
2760 */
2761 void
2762ex_source(eap)
2763 exarg_T *eap;
2764{
2765#ifdef FEAT_BROWSE
2766 if (cmdmod.browse)
2767 {
2768 char_u *fname = NULL;
2769
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002770 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002771 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2772 if (fname != NULL)
2773 {
2774 cmd_source(fname, eap);
2775 vim_free(fname);
2776 }
2777 }
2778 else
2779#endif
2780 cmd_source(eap->arg, eap);
2781}
2782
2783 static void
2784cmd_source(fname, eap)
2785 char_u *fname;
2786 exarg_T *eap;
2787{
2788 if (*fname == NUL)
2789 EMSG(_(e_argreq));
2790
Bram Moolenaar071d4272004-06-13 20:20:40 +00002791 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002792 /* ":source!": read Normal mdoe commands
2793 * Need to execute the commands directly. This is required at least
2794 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002795 * - ":g" command busy
2796 * - after ":argdo", ":windo" or ":bufdo"
2797 * - another command follows
2798 * - inside a loop
2799 */
2800 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2801#ifdef FEAT_EVAL
2802 || eap->cstack->cs_idx >= 0
2803#endif
2804 );
2805
2806 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002807 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808 EMSG2(_(e_notopen), fname);
2809}
2810
2811/*
2812 * ":source" and associated commands.
2813 */
2814/*
2815 * Structure used to store info for each sourced file.
2816 * It is shared between do_source() and getsourceline().
2817 * This is required, because it needs to be handed to do_cmdline() and
2818 * sourcing can be done recursively.
2819 */
2820struct source_cookie
2821{
2822 FILE *fp; /* opened file for sourcing */
2823 char_u *nextline; /* if not NULL: line that was read ahead */
2824 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002825#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002826 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2827 int error; /* TRUE if LF found after CR-LF */
2828#endif
2829#ifdef FEAT_EVAL
2830 linenr_T breakpoint; /* next line with breakpoint or zero */
2831 char_u *fname; /* name of sourced file */
2832 int dbg_tick; /* debug_tick when breakpoint was set */
2833 int level; /* top nesting level of sourced file */
2834#endif
2835#ifdef FEAT_MBYTE
2836 vimconv_T conv; /* type of conversion */
2837#endif
2838};
2839
2840#ifdef FEAT_EVAL
2841/*
2842 * Return the address holding the next breakpoint line for a source cookie.
2843 */
2844 linenr_T *
2845source_breakpoint(cookie)
2846 void *cookie;
2847{
2848 return &((struct source_cookie *)cookie)->breakpoint;
2849}
2850
2851/*
2852 * Return the address holding the debug tick for a source cookie.
2853 */
2854 int *
2855source_dbg_tick(cookie)
2856 void *cookie;
2857{
2858 return &((struct source_cookie *)cookie)->dbg_tick;
2859}
2860
2861/*
2862 * Return the nesting level for a source cookie.
2863 */
2864 int
2865source_level(cookie)
2866 void *cookie;
2867{
2868 return ((struct source_cookie *)cookie)->level;
2869}
2870#endif
2871
2872static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2873
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002874#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2875# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876static FILE *fopen_noinh_readbin __ARGS((char *filename));
2877
2878/*
2879 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002880 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881 */
2882 static FILE *
2883fopen_noinh_readbin(filename)
2884 char *filename;
2885{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002886# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002887 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2888# else
2889 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002890# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891
2892 if (fd_tmp == -1)
2893 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002894
2895# ifdef HAVE_FD_CLOEXEC
2896 {
2897 int fdflags = fcntl(fd_tmp, F_GETFD);
2898 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
2899 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
2900 }
2901# endif
2902
Bram Moolenaar071d4272004-06-13 20:20:40 +00002903 return fdopen(fd_tmp, READBIN);
2904}
2905#endif
2906
2907
2908/*
2909 * do_source: Read the file "fname" and execute its lines as EX commands.
2910 *
2911 * This function may be called recursively!
2912 *
2913 * return FAIL if file could not be opened, OK otherwise
2914 */
2915 int
2916do_source(fname, check_other, is_vimrc)
2917 char_u *fname;
2918 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002919 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920{
2921 struct source_cookie cookie;
2922 char_u *save_sourcing_name;
2923 linenr_T save_sourcing_lnum;
2924 char_u *p;
2925 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002926 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002927 int retval = FAIL;
2928#ifdef FEAT_EVAL
2929 scid_T save_current_SID;
2930 static scid_T last_current_SID = 0;
2931 void *save_funccalp;
2932 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002933 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934# ifdef UNIX
2935 struct stat st;
2936 int stat_ok;
2937# endif
2938#endif
2939#ifdef STARTUPTIME
2940 struct timeval tv_rel;
2941 struct timeval tv_start;
2942#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002943#ifdef FEAT_PROFILE
2944 proftime_T wait_start;
2945#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946
2947#ifdef RISCOS
2948 p = mch_munge_fname(fname);
2949#else
2950 p = expand_env_save(fname);
2951#endif
2952 if (p == NULL)
2953 return retval;
2954 fname_exp = fix_fname(p);
2955 vim_free(p);
2956 if (fname_exp == NULL)
2957 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958 if (mch_isdir(fname_exp))
2959 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002960 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002961 goto theend;
2962 }
2963
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002964#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002965 /* Apply SourceCmd autocommands, they should get the file and source it. */
2966 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2967 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2968 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002969 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002970# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002971 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002972# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002973 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002974# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002975 goto theend;
2976 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002977
2978 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002979 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2980#endif
2981
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002982#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2984#else
2985 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2986#endif
2987 if (cookie.fp == NULL && check_other)
2988 {
2989 /*
2990 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2991 * and ".exrc" by "_exrc" or vice versa.
2992 */
2993 p = gettail(fname_exp);
2994 if ((*p == '.' || *p == '_')
2995 && (STRICMP(p + 1, "vimrc") == 0
2996 || STRICMP(p + 1, "gvimrc") == 0
2997 || STRICMP(p + 1, "exrc") == 0))
2998 {
2999 if (*p == '_')
3000 *p = '.';
3001 else
3002 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003003#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3005#else
3006 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3007#endif
3008 }
3009 }
3010
3011 if (cookie.fp == NULL)
3012 {
3013 if (p_verbose > 0)
3014 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003015 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003017 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 else
3019 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003020 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003021 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022 }
3023 goto theend;
3024 }
3025
3026 /*
3027 * The file exists.
3028 * - In verbose mode, give a message.
3029 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3030 */
3031 if (p_verbose > 1)
3032 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003033 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003035 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036 else
3037 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003038 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003039 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003041 if (is_vimrc == DOSO_VIMRC)
3042 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3043 else if (is_vimrc == DOSO_GVIMRC)
3044 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003045
3046#ifdef USE_CRNL
3047 /* If no automatic file format: Set default to CR-NL. */
3048 if (*p_ffs == NUL)
3049 cookie.fileformat = EOL_DOS;
3050 else
3051 cookie.fileformat = EOL_UNKNOWN;
3052 cookie.error = FALSE;
3053#endif
3054
3055#ifdef USE_CR
3056 /* If no automatic file format: Set default to CR. */
3057 if (*p_ffs == NUL)
3058 cookie.fileformat = EOL_MAC;
3059 else
3060 cookie.fileformat = EOL_UNKNOWN;
3061 cookie.error = FALSE;
3062#endif
3063
3064 cookie.nextline = NULL;
3065 cookie.finished = FALSE;
3066
3067#ifdef FEAT_EVAL
3068 /*
3069 * Check if this script has a breakpoint.
3070 */
3071 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3072 cookie.fname = fname_exp;
3073 cookie.dbg_tick = debug_tick;
3074
3075 cookie.level = ex_nesting_level;
3076#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077
3078 /*
3079 * Keep the sourcing name/lnum, for recursive calls.
3080 */
3081 save_sourcing_name = sourcing_name;
3082 sourcing_name = fname_exp;
3083 save_sourcing_lnum = sourcing_lnum;
3084 sourcing_lnum = 0;
3085
Bram Moolenaar73881402009-02-04 16:50:47 +00003086#ifdef FEAT_MBYTE
3087 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3088
3089 /* Read the first line so we can check for a UTF-8 BOM. */
3090 firstline = getsourceline(0, (void *)&cookie, 0);
3091 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3092 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3093 {
3094 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3095 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3096 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003097 if (p == NULL)
3098 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003099 if (p != NULL)
3100 {
3101 vim_free(firstline);
3102 firstline = p;
3103 }
3104 }
3105#endif
3106
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003108 if (time_fd != NULL)
3109 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003110#endif
3111
3112#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003113# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003114 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003115 prof_child_enter(&wait_start); /* entering a child now */
3116# endif
3117
3118 /* Don't use local function variables, if called from a function.
3119 * Also starts profiling timer for nested script. */
3120 save_funccalp = save_funccal();
3121
Bram Moolenaar071d4272004-06-13 20:20:40 +00003122 /*
3123 * Check if this script was sourced before to finds its SID.
3124 * If it's new, generate a new SID.
3125 */
3126 save_current_SID = current_SID;
3127# ifdef UNIX
3128 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3129# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003130 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3131 {
3132 si = &SCRIPT_ITEM(current_SID);
3133 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134 && (
3135# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003136 /* Compare dev/ino when possible, it catches symbolic
3137 * links. Also compare file names, the inode may change
3138 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003139 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003140 && (si->sn_dev == st.st_dev
3141 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003143 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003145 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146 if (current_SID == 0)
3147 {
3148 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003149 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3150 == FAIL)
3151 goto almosttheend;
3152 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003154 ++script_items.ga_len;
3155 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3156# ifdef FEAT_PROFILE
3157 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003158# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003160 si = &SCRIPT_ITEM(current_SID);
3161 si->sn_name = fname_exp;
3162 fname_exp = NULL;
3163# ifdef UNIX
3164 if (stat_ok)
3165 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003166 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003167 si->sn_dev = st.st_dev;
3168 si->sn_ino = st.st_ino;
3169 }
3170 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003171 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003172# endif
3173
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174 /* Allocate the local script variables to use for this script. */
3175 new_script_vars(current_SID);
3176 }
3177
Bram Moolenaar05159a02005-02-26 23:04:13 +00003178# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003179 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003180 {
3181 int forceit;
3182
3183 /* Check if we do profiling for this script. */
3184 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3185 {
3186 script_do_profile(si);
3187 si->sn_pr_force = forceit;
3188 }
3189 if (si->sn_prof_on)
3190 {
3191 ++si->sn_pr_count;
3192 profile_start(&si->sn_pr_start);
3193 profile_zero(&si->sn_pr_children);
3194 }
3195 }
3196# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197#endif
3198
3199 /*
3200 * Call do_cmdline, which will call getsourceline() to get the lines.
3201 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003202 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003203 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003205
3206#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003207 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003208 {
3209 /* Get "si" again, "script_items" may have been reallocated. */
3210 si = &SCRIPT_ITEM(current_SID);
3211 if (si->sn_prof_on)
3212 {
3213 profile_end(&si->sn_pr_start);
3214 profile_sub_wait(&wait_start, &si->sn_pr_start);
3215 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003216 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3217 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003218 }
3219 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220#endif
3221
3222 if (got_int)
3223 EMSG(_(e_interr));
3224 sourcing_name = save_sourcing_name;
3225 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 if (p_verbose > 1)
3227 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003228 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003229 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003230 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003231 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003232 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003233 }
3234#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003235 if (time_fd != NULL)
3236 {
3237 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3238 time_msg((char *)IObuff, &tv_start);
3239 time_pop(&tv_rel);
3240 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241#endif
3242
3243#ifdef FEAT_EVAL
3244 /*
3245 * After a "finish" in debug mode, need to break at first command of next
3246 * sourced file.
3247 */
3248 if (save_debug_break_level > ex_nesting_level
3249 && debug_break_level == ex_nesting_level)
3250 ++debug_break_level;
3251#endif
3252
Bram Moolenaar05159a02005-02-26 23:04:13 +00003253#ifdef FEAT_EVAL
3254almosttheend:
3255 current_SID = save_current_SID;
3256 restore_funccal(save_funccalp);
3257# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003258 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003259 prof_child_exit(&wait_start); /* leaving a child now */
3260# endif
3261#endif
3262 fclose(cookie.fp);
3263 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003264 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003265#ifdef FEAT_MBYTE
3266 convert_setup(&cookie.conv, NULL, NULL);
3267#endif
3268
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269theend:
3270 vim_free(fname_exp);
3271 return retval;
3272}
3273
3274#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003275
Bram Moolenaar071d4272004-06-13 20:20:40 +00003276/*
3277 * ":scriptnames"
3278 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003279 void
3280ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003281 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003282{
3283 int i;
3284
Bram Moolenaar05159a02005-02-26 23:04:13 +00003285 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3286 if (SCRIPT_ITEM(i).sn_name != NULL)
3287 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288}
3289
3290# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3291/*
3292 * Fix slashes in the list of script names for 'shellslash'.
3293 */
3294 void
3295scriptnames_slash_adjust()
3296{
3297 int i;
3298
Bram Moolenaar05159a02005-02-26 23:04:13 +00003299 for (i = 1; i <= script_items.ga_len; ++i)
3300 if (SCRIPT_ITEM(i).sn_name != NULL)
3301 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302}
3303# endif
3304
3305/*
3306 * Get a pointer to a script name. Used for ":verbose set".
3307 */
3308 char_u *
3309get_scriptname(id)
3310 scid_T id;
3311{
3312 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003313 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003315 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003316 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003317 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003319 return (char_u *)_("environment variable");
3320 if (id == SID_ERROR)
3321 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003322 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003323}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003324
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003325# if defined(EXITFREE) || defined(PROTO)
3326 void
3327free_scriptnames()
3328{
3329 int i;
3330
3331 for (i = script_items.ga_len; i > 0; --i)
3332 vim_free(SCRIPT_ITEM(i).sn_name);
3333 ga_clear(&script_items);
3334}
3335# endif
3336
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337#endif
3338
3339#if defined(USE_CR) || defined(PROTO)
3340
3341# if defined(__MSL__) && (__MSL__ >= 22)
3342/*
3343 * Newer version of the Metrowerks library handle DOS and UNIX files
3344 * without help.
3345 * Test with earlier versions, MSL 2.2 is the library supplied with
3346 * Codewarrior Pro 2.
3347 */
3348 char *
3349fgets_cr(s, n, stream)
3350 char *s;
3351 int n;
3352 FILE *stream;
3353{
3354 return fgets(s, n, stream);
3355}
3356# else
3357/*
3358 * Version of fgets() which also works for lines ending in a <CR> only
3359 * (Macintosh format).
3360 * For older versions of the Metrowerks library.
3361 * At least CodeWarrior 9 needed this code.
3362 */
3363 char *
3364fgets_cr(s, n, stream)
3365 char *s;
3366 int n;
3367 FILE *stream;
3368{
3369 int c = 0;
3370 int char_read = 0;
3371
3372 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3373 {
3374 c = fgetc(stream);
3375 s[char_read++] = c;
3376 /* If the file is in DOS format, we need to skip a NL after a CR. I
3377 * thought it was the other way around, but this appears to work... */
3378 if (c == '\n')
3379 {
3380 c = fgetc(stream);
3381 if (c != '\r')
3382 ungetc(c, stream);
3383 }
3384 }
3385
3386 s[char_read] = 0;
3387 if (char_read == 0)
3388 return NULL;
3389
3390 if (feof(stream) && char_read == 1)
3391 return NULL;
3392
3393 return s;
3394}
3395# endif
3396#endif
3397
3398/*
3399 * Get one full line from a sourced file.
3400 * Called by do_cmdline() when it's called from do_source().
3401 *
3402 * Return a pointer to the line in allocated memory.
3403 * Return NULL for end-of-file or some error.
3404 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405 char_u *
3406getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003407 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003408 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003409 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003410{
3411 struct source_cookie *sp = (struct source_cookie *)cookie;
3412 char_u *line;
3413 char_u *p, *s;
3414
3415#ifdef FEAT_EVAL
3416 /* If breakpoints have been added/deleted need to check for it. */
3417 if (sp->dbg_tick < debug_tick)
3418 {
3419 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3420 sp->dbg_tick = debug_tick;
3421 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003422# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003423 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003424 script_line_end();
3425# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003426#endif
3427 /*
3428 * Get current line. If there is a read-ahead line, use it, otherwise get
3429 * one now.
3430 */
3431 if (sp->finished)
3432 line = NULL;
3433 else if (sp->nextline == NULL)
3434 line = get_one_sourceline(sp);
3435 else
3436 {
3437 line = sp->nextline;
3438 sp->nextline = NULL;
3439 ++sourcing_lnum;
3440 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003441#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003442 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003443 script_line_start();
3444#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445
3446 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3447 * contain the 'C' flag. */
3448 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3449 {
3450 /* compensate for the one line read-ahead */
3451 --sourcing_lnum;
3452 for (;;)
3453 {
3454 sp->nextline = get_one_sourceline(sp);
3455 if (sp->nextline == NULL)
3456 break;
3457 p = skipwhite(sp->nextline);
3458 if (*p != '\\')
3459 break;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00003460 s = alloc((unsigned)(STRLEN(line) + STRLEN(p)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461 if (s == NULL) /* out of memory */
3462 break;
3463 STRCPY(s, line);
3464 STRCAT(s, p + 1);
3465 vim_free(line);
3466 line = s;
3467 vim_free(sp->nextline);
3468 }
3469 }
3470
3471#ifdef FEAT_MBYTE
3472 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3473 {
3474 /* Convert the encoding of the script line. */
3475 s = string_convert(&sp->conv, line, NULL);
3476 if (s != NULL)
3477 {
3478 vim_free(line);
3479 line = s;
3480 }
3481 }
3482#endif
3483
3484#ifdef FEAT_EVAL
3485 /* Did we encounter a breakpoint? */
3486 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3487 {
3488 dbg_breakpoint(sp->fname, sourcing_lnum);
3489 /* Find next breakpoint. */
3490 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3491 sp->dbg_tick = debug_tick;
3492 }
3493#endif
3494
3495 return line;
3496}
3497
3498 static char_u *
3499get_one_sourceline(sp)
3500 struct source_cookie *sp;
3501{
3502 garray_T ga;
3503 int len;
3504 int c;
3505 char_u *buf;
3506#ifdef USE_CRNL
3507 int has_cr; /* CR-LF found */
3508#endif
3509#ifdef USE_CR
3510 char_u *scan;
3511#endif
3512 int have_read = FALSE;
3513
3514 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003515 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003516
3517 /*
3518 * Loop until there is a finished line (or end-of-file).
3519 */
3520 sourcing_lnum++;
3521 for (;;)
3522 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003523 /* make room to read at least 120 (more) characters */
3524 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525 break;
3526 buf = (char_u *)ga.ga_data;
3527
3528#ifdef USE_CR
3529 if (sp->fileformat == EOL_MAC)
3530 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003531 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3532 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003533 break;
3534 }
3535 else
3536#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003537 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3538 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003539 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003540 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541#ifdef USE_CRNL
3542 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3543 * CTRL-Z by its own, or after a NL. */
3544 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3545 && sp->fileformat == EOL_DOS
3546 && buf[len - 1] == Ctrl_Z)
3547 {
3548 buf[len - 1] = NUL;
3549 break;
3550 }
3551#endif
3552
3553#ifdef USE_CR
3554 /* If the read doesn't stop on a new line, and there's
3555 * some CR then we assume a Mac format */
3556 if (sp->fileformat == EOL_UNKNOWN)
3557 {
3558 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3559 sp->fileformat = EOL_MAC;
3560 else
3561 sp->fileformat = EOL_UNIX;
3562 }
3563
3564 if (sp->fileformat == EOL_MAC)
3565 {
3566 scan = vim_strchr(buf, '\r');
3567
3568 if (scan != NULL)
3569 {
3570 *scan = '\n';
3571 if (*(scan + 1) != 0)
3572 {
3573 *(scan + 1) = 0;
3574 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3575 }
3576 }
3577 len = STRLEN(buf);
3578 }
3579#endif
3580
3581 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582 ga.ga_len = len;
3583
3584 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003585 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586 continue;
3587
3588 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3589 {
3590#ifdef USE_CRNL
3591 has_cr = (len >= 2 && buf[len - 2] == '\r');
3592 if (sp->fileformat == EOL_UNKNOWN)
3593 {
3594 if (has_cr)
3595 sp->fileformat = EOL_DOS;
3596 else
3597 sp->fileformat = EOL_UNIX;
3598 }
3599
3600 if (sp->fileformat == EOL_DOS)
3601 {
3602 if (has_cr) /* replace trailing CR */
3603 {
3604 buf[len - 2] = '\n';
3605 --len;
3606 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003607 }
3608 else /* lines like ":map xx yy^M" will have failed */
3609 {
3610 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003611 {
3612 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003613 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003614 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003615 sp->error = TRUE;
3616 sp->fileformat = EOL_UNIX;
3617 }
3618 }
3619#endif
3620 /* The '\n' is escaped if there is an odd number of ^V's just
3621 * before it, first set "c" just before the 'V's and then check
3622 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3623 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3624 ;
3625 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3626 {
3627 sourcing_lnum++;
3628 continue;
3629 }
3630
3631 buf[len - 1] = NUL; /* remove the NL */
3632 }
3633
3634 /*
3635 * Check for ^C here now and then, so recursive :so can be broken.
3636 */
3637 line_breakcheck();
3638 break;
3639 }
3640
3641 if (have_read)
3642 return (char_u *)ga.ga_data;
3643
3644 vim_free(ga.ga_data);
3645 return NULL;
3646}
3647
Bram Moolenaar05159a02005-02-26 23:04:13 +00003648#if defined(FEAT_PROFILE) || defined(PROTO)
3649/*
3650 * Called when starting to read a script line.
3651 * "sourcing_lnum" must be correct!
3652 * When skipping lines it may not actually be executed, but we won't find out
3653 * until later and we need to store the time now.
3654 */
3655 void
3656script_line_start()
3657{
3658 scriptitem_T *si;
3659 sn_prl_T *pp;
3660
3661 if (current_SID <= 0 || current_SID > script_items.ga_len)
3662 return;
3663 si = &SCRIPT_ITEM(current_SID);
3664 if (si->sn_prof_on && sourcing_lnum >= 1)
3665 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003666 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003667 * here isn't counted. */
3668 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3669 si->sn_prl_idx = sourcing_lnum - 1;
3670 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3671 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3672 {
3673 /* Zero counters for a line that was not used before. */
3674 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3675 pp->snp_count = 0;
3676 profile_zero(&pp->sn_prl_total);
3677 profile_zero(&pp->sn_prl_self);
3678 ++si->sn_prl_ga.ga_len;
3679 }
3680 si->sn_prl_execed = FALSE;
3681 profile_start(&si->sn_prl_start);
3682 profile_zero(&si->sn_prl_children);
3683 profile_get_wait(&si->sn_prl_wait);
3684 }
3685}
3686
3687/*
3688 * Called when actually executing a function line.
3689 */
3690 void
3691script_line_exec()
3692{
3693 scriptitem_T *si;
3694
3695 if (current_SID <= 0 || current_SID > script_items.ga_len)
3696 return;
3697 si = &SCRIPT_ITEM(current_SID);
3698 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3699 si->sn_prl_execed = TRUE;
3700}
3701
3702/*
3703 * Called when done with a function line.
3704 */
3705 void
3706script_line_end()
3707{
3708 scriptitem_T *si;
3709 sn_prl_T *pp;
3710
3711 if (current_SID <= 0 || current_SID > script_items.ga_len)
3712 return;
3713 si = &SCRIPT_ITEM(current_SID);
3714 if (si->sn_prof_on && si->sn_prl_idx >= 0
3715 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3716 {
3717 if (si->sn_prl_execed)
3718 {
3719 pp = &PRL_ITEM(si, si->sn_prl_idx);
3720 ++pp->snp_count;
3721 profile_end(&si->sn_prl_start);
3722 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003723 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003724 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3725 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003726 }
3727 si->sn_prl_idx = -1;
3728 }
3729}
3730#endif
3731
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732/*
3733 * ":scriptencoding": Set encoding conversion for a sourced script.
3734 * Without the multi-byte feature it's simply ignored.
3735 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736 void
3737ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003738 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739{
3740#ifdef FEAT_MBYTE
3741 struct source_cookie *sp;
3742 char_u *name;
3743
3744 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3745 {
3746 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3747 return;
3748 }
3749
3750 if (*eap->arg != NUL)
3751 {
3752 name = enc_canonize(eap->arg);
3753 if (name == NULL) /* out of memory */
3754 return;
3755 }
3756 else
3757 name = eap->arg;
3758
3759 /* Setup for conversion from the specified encoding to 'encoding'. */
3760 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3761 convert_setup(&sp->conv, name, p_enc);
3762
3763 if (name != eap->arg)
3764 vim_free(name);
3765#endif
3766}
3767
3768#if defined(FEAT_EVAL) || defined(PROTO)
3769/*
3770 * ":finish": Mark a sourced file as finished.
3771 */
3772 void
3773ex_finish(eap)
3774 exarg_T *eap;
3775{
3776 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3777 do_finish(eap, FALSE);
3778 else
3779 EMSG(_("E168: :finish used outside of a sourced file"));
3780}
3781
3782/*
3783 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3784 * Also called for a pending finish at the ":endtry" or after returning from
3785 * an extra do_cmdline(). "reanimate" is used in the latter case.
3786 */
3787 void
3788do_finish(eap, reanimate)
3789 exarg_T *eap;
3790 int reanimate;
3791{
3792 int idx;
3793
3794 if (reanimate)
3795 ((struct source_cookie *)getline_cookie(eap->getline,
3796 eap->cookie))->finished = FALSE;
3797
3798 /*
3799 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3800 * not in its finally clause (which then is to be executed next) is found.
3801 * In this case, make the ":finish" pending for execution at the ":endtry".
3802 * Otherwise, finish normally.
3803 */
3804 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3805 if (idx >= 0)
3806 {
3807 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3808 report_make_pending(CSTP_FINISH, NULL);
3809 }
3810 else
3811 ((struct source_cookie *)getline_cookie(eap->getline,
3812 eap->cookie))->finished = TRUE;
3813}
3814
3815
3816/*
3817 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3818 * message for missing ":endif".
3819 * Return FALSE when not sourcing a file.
3820 */
3821 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003822source_finished(fgetline, cookie)
3823 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003824 void *cookie;
3825{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003826 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003827 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003828 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829}
3830#endif
3831
3832#if defined(FEAT_LISTCMDS) || defined(PROTO)
3833/*
3834 * ":checktime [buffer]"
3835 */
3836 void
3837ex_checktime(eap)
3838 exarg_T *eap;
3839{
3840 buf_T *buf;
3841 int save_no_check_timestamps = no_check_timestamps;
3842
3843 no_check_timestamps = 0;
3844 if (eap->addr_count == 0) /* default is all buffers */
3845 check_timestamps(FALSE);
3846 else
3847 {
3848 buf = buflist_findnr((int)eap->line2);
3849 if (buf != NULL) /* cannot happen? */
3850 (void)buf_check_timestamp(buf, FALSE);
3851 }
3852 no_check_timestamps = save_no_check_timestamps;
3853}
3854#endif
3855
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3857 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003858# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003859static char *get_locale_val __ARGS((int what));
3860
3861 static char *
3862get_locale_val(what)
3863 int what;
3864{
3865 char *loc;
3866
3867 /* Obtain the locale value from the libraries. For DJGPP this is
3868 * redefined and it doesn't use the arguments. */
3869 loc = setlocale(what, NULL);
3870
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003871# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00003872 if (loc != NULL)
3873 {
3874 char_u *p;
3875
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003876 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3877 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003878 p = vim_strchr(loc, '=');
3879 if (p != NULL)
3880 {
3881 loc = ++p;
3882 while (*p != NUL) /* remove trailing newline */
3883 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003884 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 {
3886 *p = NUL;
3887 break;
3888 }
3889 ++p;
3890 }
3891 }
3892 }
3893# endif
3894
3895 return loc;
3896}
3897#endif
3898
3899
3900#ifdef WIN32
3901/*
3902 * On MS-Windows locale names are strings like "German_Germany.1252", but
3903 * gettext expects "de". Try to translate one into another here for a few
3904 * supported languages.
3905 */
3906 static char_u *
3907gettext_lang(char_u *name)
3908{
3909 int i;
3910 static char *(mtable[]) = {
3911 "afrikaans", "af",
3912 "czech", "cs",
3913 "dutch", "nl",
3914 "german", "de",
3915 "english_united kingdom", "en_GB",
3916 "spanish", "es",
3917 "french", "fr",
3918 "italian", "it",
3919 "japanese", "ja",
3920 "korean", "ko",
3921 "norwegian", "no",
3922 "polish", "pl",
3923 "russian", "ru",
3924 "slovak", "sk",
3925 "swedish", "sv",
3926 "ukrainian", "uk",
3927 "chinese_china", "zh_CN",
3928 "chinese_taiwan", "zh_TW",
3929 NULL};
3930
3931 for (i = 0; mtable[i] != NULL; i += 2)
3932 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3933 return mtable[i + 1];
3934 return name;
3935}
3936#endif
3937
3938#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3939/*
3940 * Obtain the current messages language. Used to set the default for
3941 * 'helplang'. May return NULL or an empty string.
3942 */
3943 char_u *
3944get_mess_lang()
3945{
3946 char_u *p;
3947
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003948# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003949# if defined(LC_MESSAGES)
3950 p = (char_u *)get_locale_val(LC_MESSAGES);
3951# else
3952 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003953 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3954 * and LC_MONETARY may be set differently for a Japanese working in the
3955 * US. */
3956 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003957# endif
3958# else
3959 p = mch_getenv((char_u *)"LC_ALL");
3960 if (p == NULL || *p == NUL)
3961 {
3962 p = mch_getenv((char_u *)"LC_MESSAGES");
3963 if (p == NULL || *p == NUL)
3964 p = mch_getenv((char_u *)"LANG");
3965 }
3966# endif
3967# ifdef WIN32
3968 p = gettext_lang(p);
3969# endif
3970 return p;
3971}
3972#endif
3973
Bram Moolenaardef9e822004-12-31 20:58:58 +00003974/* Complicated #if; matches with where get_mess_env() is used below. */
3975#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3976 && defined(LC_MESSAGES))) \
3977 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3978 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3979 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003980static char_u *get_mess_env __ARGS((void));
3981
3982/*
3983 * Get the language used for messages from the environment.
3984 */
3985 static char_u *
3986get_mess_env()
3987{
3988 char_u *p;
3989
3990 p = mch_getenv((char_u *)"LC_ALL");
3991 if (p == NULL || *p == NUL)
3992 {
3993 p = mch_getenv((char_u *)"LC_MESSAGES");
3994 if (p == NULL || *p == NUL)
3995 {
3996 p = mch_getenv((char_u *)"LANG");
3997 if (p != NULL && VIM_ISDIGIT(*p))
3998 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003999# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000 if (p == NULL || *p == NUL)
4001 p = (char_u *)get_locale_val(LC_CTYPE);
4002# endif
4003 }
4004 }
4005 return p;
4006}
4007#endif
4008
4009#if defined(FEAT_EVAL) || defined(PROTO)
4010
4011/*
4012 * Set the "v:lang" variable according to the current locale setting.
4013 * Also do "v:lc_time"and "v:ctype".
4014 */
4015 void
4016set_lang_var()
4017{
4018 char_u *loc;
4019
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004020# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004021 loc = (char_u *)get_locale_val(LC_CTYPE);
4022# else
4023 /* setlocale() not supported: use the default value */
4024 loc = (char_u *)"C";
4025# endif
4026 set_vim_var_string(VV_CTYPE, loc, -1);
4027
4028 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4029 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004030# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004031 loc = (char_u *)get_locale_val(LC_MESSAGES);
4032# else
4033 loc = get_mess_env();
4034# endif
4035 set_vim_var_string(VV_LANG, loc, -1);
4036
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004037# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004038 loc = (char_u *)get_locale_val(LC_TIME);
4039# endif
4040 set_vim_var_string(VV_LC_TIME, loc, -1);
4041}
4042#endif
4043
4044#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4045 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4046/*
4047 * ":language": Set the language (locale).
4048 */
4049 void
4050ex_language(eap)
4051 exarg_T *eap;
4052{
4053 char *loc;
4054 char_u *p;
4055 char_u *name;
4056 int what = LC_ALL;
4057 char *whatstr = "";
4058#ifdef LC_MESSAGES
4059# define VIM_LC_MESSAGES LC_MESSAGES
4060#else
4061# define VIM_LC_MESSAGES 6789
4062#endif
4063
4064 name = eap->arg;
4065
4066 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4067 * Allow abbreviation, but require at least 3 characters to avoid
4068 * confusion with a two letter language name "me" or "ct". */
4069 p = skiptowhite(eap->arg);
4070 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4071 {
4072 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4073 {
4074 what = VIM_LC_MESSAGES;
4075 name = skipwhite(p);
4076 whatstr = "messages ";
4077 }
4078 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4079 {
4080 what = LC_CTYPE;
4081 name = skipwhite(p);
4082 whatstr = "ctype ";
4083 }
4084 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4085 {
4086 what = LC_TIME;
4087 name = skipwhite(p);
4088 whatstr = "time ";
4089 }
4090 }
4091
4092 if (*name == NUL)
4093 {
4094#ifndef LC_MESSAGES
4095 if (what == VIM_LC_MESSAGES)
4096 p = get_mess_env();
4097 else
4098#endif
4099 p = (char_u *)setlocale(what, NULL);
4100 if (p == NULL || *p == NUL)
4101 p = (char_u *)"Unknown";
4102 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4103 }
4104 else
4105 {
4106#ifndef LC_MESSAGES
4107 if (what == VIM_LC_MESSAGES)
4108 loc = "";
4109 else
4110#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004111 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004113#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4114 /* Make sure strtod() uses a decimal point, not a comma. */
4115 setlocale(LC_NUMERIC, "C");
4116#endif
4117 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118 if (loc == NULL)
4119 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4120 else
4121 {
4122#ifdef HAVE_NL_MSG_CAT_CNTR
4123 /* Need to do this for GNU gettext, otherwise cached translations
4124 * will be used again. */
4125 extern int _nl_msg_cat_cntr;
4126
4127 ++_nl_msg_cat_cntr;
4128#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004129 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004130 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4131
4132 if (what != LC_TIME)
4133 {
4134 /* Tell gettext() what to translate to. It apparently doesn't
4135 * use the currently effective locale. Also do this when
4136 * FEAT_GETTEXT isn't defined, so that shell commands use this
4137 * value. */
4138 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004139 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004141# ifdef WIN32
4142 /* Apparently MS-Windows printf() may cause a crash when
4143 * we give it 8-bit text while it's expecting text in the
4144 * current locale. This call avoids that. */
4145 setlocale(LC_CTYPE, "C");
4146# endif
4147 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004148 if (what != LC_CTYPE)
4149 {
4150 char_u *mname;
4151#ifdef WIN32
4152 mname = gettext_lang(name);
4153#else
4154 mname = name;
4155#endif
4156 vim_setenv((char_u *)"LC_MESSAGES", mname);
4157#ifdef FEAT_MULTI_LANG
4158 set_helplang_default(mname);
4159#endif
4160 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161 }
4162
4163# ifdef FEAT_EVAL
4164 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4165 set_lang_var();
4166# endif
4167 }
4168 }
4169}
4170
4171# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4172/*
4173 * Function given to ExpandGeneric() to obtain the possible arguments of the
4174 * ":language" command.
4175 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176 char_u *
4177get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004178 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179 int idx;
4180{
4181 if (idx == 0)
4182 return (char_u *)"messages";
4183 if (idx == 1)
4184 return (char_u *)"ctype";
4185 if (idx == 2)
4186 return (char_u *)"time";
4187 return NULL;
4188}
4189# endif
4190
4191#endif