blob: 0e671c8af5fb54a75f93fa4563be6c1db2943750 [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
14#if defined(WIN32) && defined(FEAT_CSCOPE)
15# include <io.h>
16#endif
17
18#include "vim.h"
19
20#if defined(WIN32) && defined(FEAT_CSCOPE)
21# include <fcntl.h>
22#endif
23
24#include "version.h"
25
26static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
27
Bram Moolenaar05159a02005-02-26 23:04:13 +000028#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000029/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000030 * For Unix also store the dev/ino, so that we don't have to stat() each
31 * script when going through the list. */
32typedef struct scriptitem_S
33{
34 char_u *sn_name;
35# ifdef UNIX
36 int sn_dev;
37 ino_t sn_ino;
38# endif
39# ifdef FEAT_PROFILE
40 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000041 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000042 proftime_T sn_pr_child; /* time set when going into first child */
43 int sn_pr_nest; /* nesting for sn_pr_child */
44 /* profiling the script as a whole */
45 int sn_pr_count; /* nr of times sourced */
46 proftime_T sn_pr_total; /* time spend in script + children */
47 proftime_T sn_pr_self; /* time spend in script itself */
48 proftime_T sn_pr_start; /* time at script start */
49 proftime_T sn_pr_children; /* time in children after script start */
50 /* profiling the script per line */
51 garray_T sn_prl_ga; /* things stored for every line */
52 proftime_T sn_prl_start; /* start time for current line */
53 proftime_T sn_prl_children; /* time spent in children for this line */
54 proftime_T sn_prl_wait; /* wait start time for current line */
55 int sn_prl_idx; /* index of line being timed; -1 if none */
56 int sn_prl_execed; /* line being timed was executed */
57# endif
58} scriptitem_T;
59
60static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
61#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
62
63# ifdef FEAT_PROFILE
64/* Struct used in sn_prl_ga for every line of a script. */
65typedef struct sn_prl_S
66{
67 int snp_count; /* nr of times line was executed */
68 proftime_T sn_prl_total; /* time spend in a line + children */
69 proftime_T sn_prl_self; /* time spend in a line itself */
70} sn_prl_T;
71
72# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
73# endif
74#endif
75
Bram Moolenaar071d4272004-06-13 20:20:40 +000076#if defined(FEAT_EVAL) || defined(PROTO)
77static int debug_greedy = FALSE; /* batch mode debugging: don't save
78 and restore typeahead. */
79
80/*
81 * do_debug(): Debug mode.
82 * Repeatedly get Ex commands, until told to continue normal execution.
83 */
84 void
85do_debug(cmd)
86 char_u *cmd;
87{
88 int save_msg_scroll = msg_scroll;
89 int save_State = State;
90 int save_did_emsg = did_emsg;
91 int save_cmd_silent = cmd_silent;
92 int save_msg_silent = msg_silent;
93 int save_emsg_silent = emsg_silent;
94 int save_redir_off = redir_off;
95 tasave_T typeaheadbuf;
96# ifdef FEAT_EX_EXTRA
97 int save_ex_normal_busy;
98# endif
99 int n;
100 char_u *cmdline = NULL;
101 char_u *p;
102 char *tail = NULL;
103 static int last_cmd = 0;
104#define CMD_CONT 1
105#define CMD_NEXT 2
106#define CMD_STEP 3
107#define CMD_FINISH 4
108#define CMD_QUIT 5
109#define CMD_INTERRUPT 6
110
111#ifdef ALWAYS_USE_GUI
112 /* Can't do this when there is no terminal for input/output. */
113 if (!gui.in_use)
114 {
115 /* Break as soon as possible. */
116 debug_break_level = 9999;
117 return;
118 }
119#endif
120
121 /* Make sure we are in raw mode and start termcap mode. Might have side
122 * effects... */
123 settmode(TMODE_RAW);
124 starttermcap();
125
126 ++RedrawingDisabled; /* don't redisplay the window */
127 ++no_wait_return; /* don't wait for return */
128 did_emsg = FALSE; /* don't use error from debugged stuff */
129 cmd_silent = FALSE; /* display commands */
130 msg_silent = FALSE; /* display messages */
131 emsg_silent = FALSE; /* display error messages */
132 redir_off = TRUE; /* don't redirect debug commands */
133
134 State = NORMAL;
135#ifdef FEAT_SNIFF
136 want_sniff_request = 0; /* No K_SNIFF wanted */
137#endif
138
139 if (!debug_did_msg)
140 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
141 if (sourcing_name != NULL)
142 msg(sourcing_name);
143 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000144 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000146 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147
148 /*
149 * Repeat getting a command and executing it.
150 */
151 for (;;)
152 {
153 msg_scroll = TRUE;
154 need_wait_return = FALSE;
155#ifdef FEAT_SNIFF
156 ProcessSniffRequests();
157#endif
158 /* Save the current typeahead buffer and replace it with an empty one.
159 * This makes sure we get input from the user here and don't interfere
160 * with the commands being executed. Reset "ex_normal_busy" to avoid
161 * the side effects of using ":normal". Save the stuff buffer and make
162 * it empty. */
163# ifdef FEAT_EX_EXTRA
164 save_ex_normal_busy = ex_normal_busy;
165 ex_normal_busy = 0;
166# endif
167 if (!debug_greedy)
168 save_typeahead(&typeaheadbuf);
169
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000170 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171
172 if (!debug_greedy)
173 restore_typeahead(&typeaheadbuf);
174# ifdef FEAT_EX_EXTRA
175 ex_normal_busy = save_ex_normal_busy;
176# endif
177
178 cmdline_row = msg_row;
179 if (cmdline != NULL)
180 {
181 /* If this is a debug command, set "last_cmd".
182 * If not, reset "last_cmd".
183 * For a blank line use previous command. */
184 p = skipwhite(cmdline);
185 if (*p != NUL)
186 {
187 switch (*p)
188 {
189 case 'c': last_cmd = CMD_CONT;
190 tail = "ont";
191 break;
192 case 'n': last_cmd = CMD_NEXT;
193 tail = "ext";
194 break;
195 case 's': last_cmd = CMD_STEP;
196 tail = "tep";
197 break;
198 case 'f': last_cmd = CMD_FINISH;
199 tail = "inish";
200 break;
201 case 'q': last_cmd = CMD_QUIT;
202 tail = "uit";
203 break;
204 case 'i': last_cmd = CMD_INTERRUPT;
205 tail = "nterrupt";
206 break;
207 default: last_cmd = 0;
208 }
209 if (last_cmd != 0)
210 {
211 /* Check that the tail matches. */
212 ++p;
213 while (*p != NUL && *p == *tail)
214 {
215 ++p;
216 ++tail;
217 }
218 if (ASCII_ISALPHA(*p))
219 last_cmd = 0;
220 }
221 }
222
223 if (last_cmd != 0)
224 {
225 /* Execute debug command: decided where to break next and
226 * return. */
227 switch (last_cmd)
228 {
229 case CMD_CONT:
230 debug_break_level = -1;
231 break;
232 case CMD_NEXT:
233 debug_break_level = ex_nesting_level;
234 break;
235 case CMD_STEP:
236 debug_break_level = 9999;
237 break;
238 case CMD_FINISH:
239 debug_break_level = ex_nesting_level - 1;
240 break;
241 case CMD_QUIT:
242 got_int = TRUE;
243 debug_break_level = -1;
244 break;
245 case CMD_INTERRUPT:
246 got_int = TRUE;
247 debug_break_level = 9999;
248 /* Do not repeat ">interrupt" cmd, continue stepping. */
249 last_cmd = CMD_STEP;
250 break;
251 }
252 break;
253 }
254
255 /* don't debug this command */
256 n = debug_break_level;
257 debug_break_level = -1;
258 (void)do_cmdline(cmdline, getexline, NULL,
259 DOCMD_VERBOSE|DOCMD_EXCRESET);
260 debug_break_level = n;
261
262 vim_free(cmdline);
263 }
264 lines_left = Rows - 1;
265 }
266 vim_free(cmdline);
267
268 --RedrawingDisabled;
269 --no_wait_return;
270 redraw_all_later(NOT_VALID);
271 need_wait_return = FALSE;
272 msg_scroll = save_msg_scroll;
273 lines_left = Rows - 1;
274 State = save_State;
275 did_emsg = save_did_emsg;
276 cmd_silent = save_cmd_silent;
277 msg_silent = save_msg_silent;
278 emsg_silent = save_emsg_silent;
279 redir_off = save_redir_off;
280
281 /* Only print the message again when typing a command before coming back
282 * here. */
283 debug_did_msg = TRUE;
284}
285
286/*
287 * ":debug".
288 */
289 void
290ex_debug(eap)
291 exarg_T *eap;
292{
293 int debug_break_level_save = debug_break_level;
294
295 debug_break_level = 9999;
296 do_cmdline_cmd(eap->arg);
297 debug_break_level = debug_break_level_save;
298}
299
300static char_u *debug_breakpoint_name = NULL;
301static linenr_T debug_breakpoint_lnum;
302
303/*
304 * When debugging or a breakpoint is set on a skipped command, no debug prompt
305 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
306 * debug_skipped_name is then set to the source name in the breakpoint case. If
307 * a skipped command decides itself that a debug prompt should be displayed, it
308 * can do so by calling dbg_check_skipped().
309 */
310static int debug_skipped;
311static char_u *debug_skipped_name;
312
313/*
314 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
315 * at or below the break level. But only when the line is actually
316 * executed. Return TRUE and set breakpoint_name for skipped commands that
317 * decide to execute something themselves.
318 * Called from do_one_cmd() before executing a command.
319 */
320 void
321dbg_check_breakpoint(eap)
322 exarg_T *eap;
323{
324 char_u *p;
325
326 debug_skipped = FALSE;
327 if (debug_breakpoint_name != NULL)
328 {
329 if (!eap->skip)
330 {
331 /* replace K_SNR with "<SNR>" */
332 if (debug_breakpoint_name[0] == K_SPECIAL
333 && debug_breakpoint_name[1] == KS_EXTRA
334 && debug_breakpoint_name[2] == (int)KE_SNR)
335 p = (char_u *)"<SNR>";
336 else
337 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000338 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
339 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000340 debug_breakpoint_name + (*p == NUL ? 0 : 3),
341 (long)debug_breakpoint_lnum);
342 debug_breakpoint_name = NULL;
343 do_debug(eap->cmd);
344 }
345 else
346 {
347 debug_skipped = TRUE;
348 debug_skipped_name = debug_breakpoint_name;
349 debug_breakpoint_name = NULL;
350 }
351 }
352 else if (ex_nesting_level <= debug_break_level)
353 {
354 if (!eap->skip)
355 do_debug(eap->cmd);
356 else
357 {
358 debug_skipped = TRUE;
359 debug_skipped_name = NULL;
360 }
361 }
362}
363
364/*
365 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
366 * set. Return TRUE when the debug mode is entered this time.
367 */
368 int
369dbg_check_skipped(eap)
370 exarg_T *eap;
371{
372 int prev_got_int;
373
374 if (debug_skipped)
375 {
376 /*
377 * Save the value of got_int and reset it. We don't want a previous
378 * interruption cause flushing the input buffer.
379 */
380 prev_got_int = got_int;
381 got_int = FALSE;
382 debug_breakpoint_name = debug_skipped_name;
383 /* eap->skip is TRUE */
384 eap->skip = FALSE;
385 (void)dbg_check_breakpoint(eap);
386 eap->skip = TRUE;
387 got_int |= prev_got_int;
388 return TRUE;
389 }
390 return FALSE;
391}
392
393/*
394 * The list of breakpoints: dbg_breakp.
395 * This is a grow-array of structs.
396 */
397struct debuggy
398{
399 int dbg_nr; /* breakpoint number */
400 int dbg_type; /* DBG_FUNC or DBG_FILE */
401 char_u *dbg_name; /* function or file name */
402 regprog_T *dbg_prog; /* regexp program */
403 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000404 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405};
406
407static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000408#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
409#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410static int last_breakp = 0; /* nr of last defined breakpoint */
411
Bram Moolenaar05159a02005-02-26 23:04:13 +0000412#ifdef FEAT_PROFILE
413/* Profiling uses file and func names similar to breakpoints. */
414static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
415#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416#define DBG_FUNC 1
417#define DBG_FILE 2
418
Bram Moolenaar05159a02005-02-26 23:04:13 +0000419static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
420static 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 +0000421
422/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000423 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
424 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
425 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000426 * Returns FAIL for failure.
427 */
428 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000429dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000430 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000431 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432{
433 char_u *p = arg;
434 char_u *q;
435 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000436 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437
Bram Moolenaar05159a02005-02-26 23:04:13 +0000438 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000440 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441
442 /* Find "func" or "file". */
443 if (STRNCMP(p, "func", 4) == 0)
444 bp->dbg_type = DBG_FUNC;
445 else if (STRNCMP(p, "file", 4) == 0)
446 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000447 else if (
448#ifdef FEAT_PROFILE
449 gap != &prof_ga &&
450#endif
451 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000452 {
453 if (curbuf->b_ffname == NULL)
454 {
455 EMSG(_(e_noname));
456 return FAIL;
457 }
458 bp->dbg_type = DBG_FILE;
459 here = TRUE;
460 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000461 else
462 {
463 EMSG2(_(e_invarg2), p);
464 return FAIL;
465 }
466 p = skipwhite(p + 4);
467
468 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000469 if (here)
470 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000471 else if (
472#ifdef FEAT_PROFILE
473 gap != &prof_ga &&
474#endif
475 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000476 {
477 bp->dbg_lnum = getdigits(&p);
478 p = skipwhite(p);
479 }
480 else
481 bp->dbg_lnum = 0;
482
483 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000484 if ((!here && *p == NUL)
485 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000486 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
487 {
488 EMSG2(_(e_invarg2), arg);
489 return FAIL;
490 }
491
492 if (bp->dbg_type == DBG_FUNC)
493 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000494 else if (here)
495 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496 else
497 {
498 /* Expand the file name in the same way as do_source(). This means
499 * doing it twice, so that $DIR/file gets expanded when $DIR is
500 * "~/dir". */
501#ifdef RISCOS
502 q = mch_munge_fname(p);
503#else
504 q = expand_env_save(p);
505#endif
506 if (q == NULL)
507 return FAIL;
508#ifdef RISCOS
509 p = mch_munge_fname(q);
510#else
511 p = expand_env_save(q);
512#endif
513 vim_free(q);
514 if (p == NULL)
515 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000516 if (*p != '*')
517 {
518 bp->dbg_name = fix_fname(p);
519 vim_free(p);
520 }
521 else
522 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000523 }
524
525 if (bp->dbg_name == NULL)
526 return FAIL;
527 return OK;
528}
529
530/*
531 * ":breakadd".
532 */
533 void
534ex_breakadd(eap)
535 exarg_T *eap;
536{
537 struct debuggy *bp;
538 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000539 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540
Bram Moolenaar05159a02005-02-26 23:04:13 +0000541 gap = &dbg_breakp;
542#ifdef FEAT_PROFILE
543 if (eap->cmdidx == CMD_profile)
544 gap = &prof_ga;
545#endif
546
547 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000549 bp = &DEBUGGY(gap, gap->ga_len);
550 bp->dbg_forceit = eap->forceit;
551
Bram Moolenaar071d4272004-06-13 20:20:40 +0000552 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
553 if (pat != NULL)
554 {
555 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
556 vim_free(pat);
557 }
558 if (pat == NULL || bp->dbg_prog == NULL)
559 vim_free(bp->dbg_name);
560 else
561 {
562 if (bp->dbg_lnum == 0) /* default line number is 1 */
563 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000564#ifdef FEAT_PROFILE
565 if (eap->cmdidx != CMD_profile)
566#endif
567 {
568 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
569 ++debug_tick;
570 }
571 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572 }
573 }
574}
575
576/*
577 * ":debuggreedy".
578 */
579 void
580ex_debuggreedy(eap)
581 exarg_T *eap;
582{
583 if (eap->addr_count == 0 || eap->line2 != 0)
584 debug_greedy = TRUE;
585 else
586 debug_greedy = FALSE;
587}
588
589/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000590 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591 */
592 void
593ex_breakdel(eap)
594 exarg_T *eap;
595{
596 struct debuggy *bp, *bpi;
597 int nr;
598 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000599 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000600 int i;
601 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000602 garray_T *gap;
603
604 gap = &dbg_breakp;
605#ifdef FEAT_PROFILE
606 if (eap->cmdidx == CMD_profdel)
607 gap = &prof_ga;
608#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609
610 if (vim_isdigit(*eap->arg))
611 {
612 /* ":breakdel {nr}" */
613 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000614 for (i = 0; i < gap->ga_len; ++i)
615 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000616 {
617 todel = i;
618 break;
619 }
620 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000621 else if (*eap->arg == '*')
622 {
623 todel = 0;
624 del_all = TRUE;
625 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626 else
627 {
628 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000629 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000631 bp = &DEBUGGY(gap, gap->ga_len);
632 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000634 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635 if (bp->dbg_type == bpi->dbg_type
636 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
637 && (bp->dbg_lnum == bpi->dbg_lnum
638 || (bp->dbg_lnum == 0
639 && (best_lnum == 0
640 || bpi->dbg_lnum < best_lnum))))
641 {
642 todel = i;
643 best_lnum = bpi->dbg_lnum;
644 }
645 }
646 vim_free(bp->dbg_name);
647 }
648
649 if (todel < 0)
650 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
651 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000652 {
653 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000654 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000655 vim_free(DEBUGGY(gap, todel).dbg_name);
656 vim_free(DEBUGGY(gap, todel).dbg_prog);
657 --gap->ga_len;
658 if (todel < gap->ga_len)
659 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
660 (gap->ga_len - todel) * sizeof(struct debuggy));
661#ifdef FEAT_PROFILE
662 if (eap->cmdidx == CMD_breakdel)
663#endif
664 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000665 if (!del_all)
666 break;
667 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000668
669 /* If all breakpoints were removed clear the array. */
670 if (gap->ga_len == 0)
671 ga_clear(gap);
672 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000673}
674
675/*
676 * ":breaklist".
677 */
678/*ARGSUSED*/
679 void
680ex_breaklist(eap)
681 exarg_T *eap;
682{
683 struct debuggy *bp;
684 int i;
685
686 if (dbg_breakp.ga_len == 0)
687 MSG(_("No breakpoints defined"));
688 else
689 for (i = 0; i < dbg_breakp.ga_len; ++i)
690 {
691 bp = &BREAKP(i);
692 smsg((char_u *)_("%3d %s %s line %ld"),
693 bp->dbg_nr,
694 bp->dbg_type == DBG_FUNC ? "func" : "file",
695 bp->dbg_name,
696 (long)bp->dbg_lnum);
697 }
698}
699
700/*
701 * Find a breakpoint for a function or sourced file.
702 * Returns line number at which to break; zero when no matching breakpoint.
703 */
704 linenr_T
705dbg_find_breakpoint(file, fname, after)
706 int file; /* TRUE for a file, FALSE for a function */
707 char_u *fname; /* file or function name */
708 linenr_T after; /* after this line number */
709{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000710 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
711}
712
713#if defined(FEAT_PROFILE) || defined(PROTO)
714/*
715 * Return TRUE if profiling is on for a function or sourced file.
716 */
717 int
718has_profiling(file, fname, fp)
719 int file; /* TRUE for a file, FALSE for a function */
720 char_u *fname; /* file or function name */
721 int *fp; /* return: forceit */
722{
723 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
724 != (linenr_T)0);
725}
726#endif
727
728/*
729 * Common code for dbg_find_breakpoint() and has_profiling().
730 */
731 static linenr_T
732debuggy_find(file, fname, after, gap, fp)
733 int file; /* TRUE for a file, FALSE for a function */
734 char_u *fname; /* file or function name */
735 linenr_T after; /* after this line number */
736 garray_T *gap; /* either &dbg_breakp or &prof_ga */
737 int *fp; /* if not NULL: return forceit */
738{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 struct debuggy *bp;
740 int i;
741 linenr_T lnum = 0;
742 regmatch_T regmatch;
743 char_u *name = fname;
744 int prev_got_int;
745
Bram Moolenaar05159a02005-02-26 23:04:13 +0000746 /* Return quickly when there are no breakpoints. */
747 if (gap->ga_len == 0)
748 return (linenr_T)0;
749
Bram Moolenaar071d4272004-06-13 20:20:40 +0000750 /* Replace K_SNR in function name with "<SNR>". */
751 if (!file && fname[0] == K_SPECIAL)
752 {
753 name = alloc((unsigned)STRLEN(fname) + 3);
754 if (name == NULL)
755 name = fname;
756 else
757 {
758 STRCPY(name, "<SNR>");
759 STRCPY(name + 5, fname + 3);
760 }
761 }
762
Bram Moolenaar05159a02005-02-26 23:04:13 +0000763 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000765 /* Skip entries that are not useful or are for a line that is beyond
766 * an already found breakpoint. */
767 bp = &DEBUGGY(gap, i);
768 if (((bp->dbg_type == DBG_FILE) == file && (
769#ifdef FEAT_PROFILE
770 gap == &prof_ga ||
771#endif
772 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 {
774 regmatch.regprog = bp->dbg_prog;
775 regmatch.rm_ic = FALSE;
776 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000777 * Save the value of got_int and reset it. We don't want a
778 * previous interruption cancel matching, only hitting CTRL-C
779 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 */
781 prev_got_int = got_int;
782 got_int = FALSE;
783 if (vim_regexec(&regmatch, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000784 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000786 if (fp != NULL)
787 *fp = bp->dbg_forceit;
788 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789 got_int |= prev_got_int;
790 }
791 }
792 if (name != fname)
793 vim_free(name);
794
795 return lnum;
796}
797
798/*
799 * Called when a breakpoint was encountered.
800 */
801 void
802dbg_breakpoint(name, lnum)
803 char_u *name;
804 linenr_T lnum;
805{
806 /* We need to check if this line is actually executed in do_one_cmd() */
807 debug_breakpoint_name = name;
808 debug_breakpoint_lnum = lnum;
809}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000810
811
812# if defined(FEAT_PROFILE) || defined(PROTO)
813/*
814 * Functions for profiling.
815 */
816static void script_do_profile __ARGS((scriptitem_T *si));
817static void script_dump_profile __ARGS((FILE *fd));
818static proftime_T prof_wait_time;
819
820/*
821 * Set the time in "tm" to zero.
822 */
823 void
824profile_zero(tm)
825 proftime_T *tm;
826{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000827# ifdef WIN3264
828 tm->QuadPart = 0;
829# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000830 tm->tv_usec = 0;
831 tm->tv_sec = 0;
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000832# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000833}
834
835/*
836 * Store the current time in "tm".
837 */
838 void
839profile_start(tm)
840 proftime_T *tm;
841{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000842# ifdef WIN3264
843 QueryPerformanceCounter(tm);
844# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000846# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000847}
848
849/*
850 * Compute the elapsed time from "tm" till now and store in "tm".
851 */
852 void
853profile_end(tm)
854 proftime_T *tm;
855{
856 proftime_T now;
857
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000858# ifdef WIN3264
859 QueryPerformanceCounter(&now);
860 tm->QuadPart = now.QuadPart - tm->QuadPart;
861# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000862 gettimeofday(&now, NULL);
863 tm->tv_usec = now.tv_usec - tm->tv_usec;
864 tm->tv_sec = now.tv_sec - tm->tv_sec;
865 if (tm->tv_usec < 0)
866 {
867 tm->tv_usec += 1000000;
868 --tm->tv_sec;
869 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000870# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000871}
872
873/*
874 * Subtract the time "tm2" from "tm".
875 */
876 void
877profile_sub(tm, tm2)
878 proftime_T *tm, *tm2;
879{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000880# ifdef WIN3264
881 tm->QuadPart -= tm2->QuadPart;
882# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000883 tm->tv_usec -= tm2->tv_usec;
884 tm->tv_sec -= tm2->tv_sec;
885 if (tm->tv_usec < 0)
886 {
887 tm->tv_usec += 1000000;
888 --tm->tv_sec;
889 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000890# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000891}
892
893/*
894 * Add the time "tm2" to "tm".
895 */
896 void
897profile_add(tm, tm2)
898 proftime_T *tm, *tm2;
899{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000900# ifdef WIN3264
901 tm->QuadPart += tm2->QuadPart;
902# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000903 tm->tv_usec += tm2->tv_usec;
904 tm->tv_sec += tm2->tv_sec;
905 if (tm->tv_usec >= 1000000)
906 {
907 tm->tv_usec -= 1000000;
908 ++tm->tv_sec;
909 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000910# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000911}
912
913/*
914 * Get the current waittime.
915 */
916 void
917profile_get_wait(tm)
918 proftime_T *tm;
919{
920 *tm = prof_wait_time;
921}
922
923/*
924 * Subtract the passed waittime since "tm" from "tma".
925 */
926 void
927profile_sub_wait(tm, tma)
928 proftime_T *tm, *tma;
929{
930 proftime_T tm3 = prof_wait_time;
931
932 profile_sub(&tm3, tm);
933 profile_sub(tma, &tm3);
934}
935
936/*
937 * Return TRUE if "tm1" and "tm2" are equal.
938 */
939 int
940profile_equal(tm1, tm2)
941 proftime_T *tm1, *tm2;
942{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000943# ifdef WIN3264
944 return (tm1->QuadPart == tm2->QuadPart);
945# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000946 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000947# endif
948}
949
950/*
951 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
952 */
953 int
954profile_cmp(tm1, tm2)
955 proftime_T *tm1, *tm2;
956{
957# ifdef WIN3264
958 return (int)(tm2->QuadPart - tm1->QuadPart);
959# else
960 if (tm1->tv_sec == tm2->tv_sec)
961 return tm2->tv_usec - tm1->tv_usec;
962 return tm2->tv_sec - tm1->tv_sec;
963# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000964}
965
966/*
967 * Return a string that represents a time.
968 * Uses a static buffer!
969 */
970 char *
971profile_msg(tm)
972 proftime_T *tm;
973{
974 static char buf[50];
975
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000976# ifdef WIN3264
977 LARGE_INTEGER fr;
978
979 QueryPerformanceFrequency(&fr);
980 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
981# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000982 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000983#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000984 return buf;
985}
986
987static char_u *profile_fname = NULL;
988
989/*
990 * ":profile cmd args"
991 */
992 void
993ex_profile(eap)
994 exarg_T *eap;
995{
996 char_u *e;
997 int len;
998
999 e = skiptowhite(eap->arg);
1000 len = e - eap->arg;
1001 e = skipwhite(e);
1002
1003 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1004 {
1005 vim_free(profile_fname);
1006 profile_fname = vim_strsave(e);
1007 do_profiling = TRUE;
1008 profile_zero(&prof_wait_time);
1009 set_vim_var_nr(VV_PROFILING, 1L);
1010 }
1011 else if (!do_profiling)
1012 EMSG(_("E750: First use :profile start <fname>"));
1013 else
1014 {
1015 /* The rest is similar to ":breakadd". */
1016 ex_breakadd(eap);
1017 }
1018}
1019
1020/*
1021 * Dump the profiling info.
1022 */
1023 void
1024profile_dump()
1025{
1026 FILE *fd;
1027
1028 if (profile_fname != NULL)
1029 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001030 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001031 if (fd == NULL)
1032 EMSG2(_(e_notopen), profile_fname);
1033 else
1034 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001035 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001036 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001037 fclose(fd);
1038 }
1039 }
1040}
1041
1042/*
1043 * Start profiling script "fp".
1044 */
1045 static void
1046script_do_profile(si)
1047 scriptitem_T *si;
1048{
1049 si->sn_pr_count = 0;
1050 profile_zero(&si->sn_pr_total);
1051 profile_zero(&si->sn_pr_self);
1052
1053 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1054 si->sn_prl_idx = -1;
1055 si->sn_prof_on = TRUE;
1056 si->sn_pr_nest = 0;
1057}
1058
1059/*
1060 * save time when starting to invoke another script or function.
1061 */
1062 void
1063script_prof_save(tm)
1064 proftime_T *tm; /* place to store wait time */
1065{
1066 scriptitem_T *si;
1067
1068 if (current_SID > 0 && current_SID <= script_items.ga_len)
1069 {
1070 si = &SCRIPT_ITEM(current_SID);
1071 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1072 profile_start(&si->sn_pr_child);
1073 }
1074 profile_get_wait(tm);
1075}
1076
1077/*
1078 * Count time spent in children after invoking another script or function.
1079 */
1080 void
1081script_prof_restore(tm)
1082 proftime_T *tm;
1083{
1084 scriptitem_T *si;
1085
1086 if (current_SID > 0 && current_SID <= script_items.ga_len)
1087 {
1088 si = &SCRIPT_ITEM(current_SID);
1089 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1090 {
1091 profile_end(&si->sn_pr_child);
1092 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1093 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1094 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1095 }
1096 }
1097}
1098
1099static proftime_T inchar_time;
1100
1101/*
1102 * Called when starting to wait for the user to type a character.
1103 */
1104 void
1105prof_inchar_enter()
1106{
1107 profile_start(&inchar_time);
1108}
1109
1110/*
1111 * Called when finished waiting for the user to type a character.
1112 */
1113 void
1114prof_inchar_exit()
1115{
1116 profile_end(&inchar_time);
1117 profile_add(&prof_wait_time, &inchar_time);
1118}
1119
1120/*
1121 * Dump the profiling results for all scripts in file "fd".
1122 */
1123 static void
1124script_dump_profile(fd)
1125 FILE *fd;
1126{
1127 int id;
1128 scriptitem_T *si;
1129 int i;
1130 FILE *sfd;
1131 sn_prl_T *pp;
1132
1133 for (id = 1; id <= script_items.ga_len; ++id)
1134 {
1135 si = &SCRIPT_ITEM(id);
1136 if (si->sn_prof_on)
1137 {
1138 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1139 if (si->sn_pr_count == 1)
1140 fprintf(fd, "Sourced 1 time\n");
1141 else
1142 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1143 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1144 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1145 fprintf(fd, "\n");
1146 fprintf(fd, "count total (s) self (s)\n");
1147
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001148 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001149 if (sfd == NULL)
1150 fprintf(fd, "Cannot open file!\n");
1151 else
1152 {
1153 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1154 {
1155 if (vim_fgets(IObuff, IOSIZE, sfd))
1156 break;
1157 pp = &PRL_ITEM(si, i);
1158 if (pp->snp_count > 0)
1159 {
1160 fprintf(fd, "%5d ", pp->snp_count);
1161 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1162 fprintf(fd, " ");
1163 else
1164 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1165 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1166 }
1167 else
1168 fprintf(fd, " ");
1169 fprintf(fd, "%s", IObuff);
1170 }
1171 fclose(sfd);
1172 }
1173 fprintf(fd, "\n");
1174 }
1175 }
1176}
1177
1178/*
1179 * Return TRUE when a function defined in the current script should be
1180 * profiled.
1181 */
1182 int
1183prof_def_func()
1184{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001185 if (current_SID > 0)
1186 return SCRIPT_ITEM(current_SID).sn_pr_force;
1187 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001188}
1189
1190# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001191#endif
1192
1193/*
1194 * If 'autowrite' option set, try to write the file.
1195 * Careful: autocommands may make "buf" invalid!
1196 *
1197 * return FAIL for failure, OK otherwise
1198 */
1199 int
1200autowrite(buf, forceit)
1201 buf_T *buf;
1202 int forceit;
1203{
1204 if (!(p_aw || p_awa) || !p_write
1205#ifdef FEAT_QUICKFIX
1206 /* never autowrite a "nofile" or "nowrite" buffer */
1207 || bt_dontwrite(buf)
1208#endif
1209 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
1210 return FAIL;
1211 return buf_write_all(buf, forceit);
1212}
1213
1214/*
1215 * flush all buffers, except the ones that are readonly
1216 */
1217 void
1218autowrite_all()
1219{
1220 buf_T *buf;
1221
1222 if (!(p_aw || p_awa) || !p_write)
1223 return;
1224 for (buf = firstbuf; buf; buf = buf->b_next)
1225 if (bufIsChanged(buf) && !buf->b_p_ro)
1226 {
1227 (void)buf_write_all(buf, FALSE);
1228#ifdef FEAT_AUTOCMD
1229 /* an autocommand may have deleted the buffer */
1230 if (!buf_valid(buf))
1231 buf = firstbuf;
1232#endif
1233 }
1234}
1235
1236/*
1237 * return TRUE if buffer was changed and cannot be abandoned.
1238 */
1239/*ARGSUSED*/
1240 int
1241check_changed(buf, checkaw, mult_win, forceit, allbuf)
1242 buf_T *buf;
1243 int checkaw; /* do autowrite if buffer was changed */
1244 int mult_win; /* check also when several wins for the buf */
1245 int forceit;
1246 int allbuf; /* may write all buffers */
1247{
1248 if ( !forceit
1249 && bufIsChanged(buf)
1250 && (mult_win || buf->b_nwindows <= 1)
1251 && (!checkaw || autowrite(buf, forceit) == FAIL))
1252 {
1253#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1254 if ((p_confirm || cmdmod.confirm) && p_write)
1255 {
1256 buf_T *buf2;
1257 int count = 0;
1258
1259 if (allbuf)
1260 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1261 if (bufIsChanged(buf2)
1262 && (buf2->b_ffname != NULL
1263# ifdef FEAT_BROWSE
1264 || cmdmod.browse
1265# endif
1266 ))
1267 ++count;
1268# ifdef FEAT_AUTOCMD
1269 if (!buf_valid(buf))
1270 /* Autocommand deleted buffer, oops! It's not changed now. */
1271 return FALSE;
1272# endif
1273 dialog_changed(buf, count > 1);
1274# ifdef FEAT_AUTOCMD
1275 if (!buf_valid(buf))
1276 /* Autocommand deleted buffer, oops! It's not changed now. */
1277 return FALSE;
1278# endif
1279 return bufIsChanged(buf);
1280 }
1281#endif
1282 EMSG(_(e_nowrtmsg));
1283 return TRUE;
1284 }
1285 return FALSE;
1286}
1287
1288#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1289
1290#if defined(FEAT_BROWSE) || defined(PROTO)
1291/*
1292 * When wanting to write a file without a file name, ask the user for a name.
1293 */
1294 void
1295browse_save_fname(buf)
1296 buf_T *buf;
1297{
1298 if (buf->b_fname == NULL)
1299 {
1300 char_u *fname;
1301
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001302 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1303 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001304 if (fname != NULL)
1305 {
1306 if (setfname(buf, fname, NULL, TRUE) == OK)
1307 buf->b_flags |= BF_NOTEDITED;
1308 vim_free(fname);
1309 }
1310 }
1311}
1312#endif
1313
1314/*
1315 * Ask the user what to do when abondoning a changed buffer.
1316 * Must check 'write' option first!
1317 */
1318 void
1319dialog_changed(buf, checkall)
1320 buf_T *buf;
1321 int checkall; /* may abandon all changed buffers */
1322{
1323 char_u buff[IOSIZE];
1324 int ret;
1325 buf_T *buf2;
1326
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001327 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001328 (buf->b_fname != NULL) ?
1329 buf->b_fname : (char_u *)_("Untitled"));
1330 if (checkall)
1331 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1332 else
1333 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1334
1335 if (ret == VIM_YES)
1336 {
1337#ifdef FEAT_BROWSE
1338 /* May get file name, when there is none */
1339 browse_save_fname(buf);
1340#endif
1341 if (buf->b_fname != NULL) /* didn't hit Cancel */
1342 (void)buf_write_all(buf, FALSE);
1343 }
1344 else if (ret == VIM_NO)
1345 {
1346 unchanged(buf, TRUE);
1347 }
1348 else if (ret == VIM_ALL)
1349 {
1350 /*
1351 * Write all modified files that can be written.
1352 * Skip readonly buffers, these need to be confirmed
1353 * individually.
1354 */
1355 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1356 {
1357 if (bufIsChanged(buf2)
1358 && (buf2->b_ffname != NULL
1359#ifdef FEAT_BROWSE
1360 || cmdmod.browse
1361#endif
1362 )
1363 && !buf2->b_p_ro)
1364 {
1365#ifdef FEAT_BROWSE
1366 /* May get file name, when there is none */
1367 browse_save_fname(buf2);
1368#endif
1369 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1370 (void)buf_write_all(buf2, FALSE);
1371#ifdef FEAT_AUTOCMD
1372 /* an autocommand may have deleted the buffer */
1373 if (!buf_valid(buf2))
1374 buf2 = firstbuf;
1375#endif
1376 }
1377 }
1378 }
1379 else if (ret == VIM_DISCARDALL)
1380 {
1381 /*
1382 * mark all buffers as unchanged
1383 */
1384 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1385 unchanged(buf2, TRUE);
1386 }
1387}
1388#endif
1389
1390/*
1391 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1392 * hidden, autowriting it or unloading it.
1393 */
1394 int
1395can_abandon(buf, forceit)
1396 buf_T *buf;
1397 int forceit;
1398{
1399 return ( P_HID(buf)
1400 || !bufIsChanged(buf)
1401 || buf->b_nwindows > 1
1402 || autowrite(buf, forceit) == OK
1403 || forceit);
1404}
1405
1406/*
1407 * Return TRUE if any buffer was changed and cannot be abandoned.
1408 * That changed buffer becomes the current buffer.
1409 */
1410 int
1411check_changed_any(hidden)
1412 int hidden; /* Only check hidden buffers */
1413{
1414 buf_T *buf;
1415 int save;
1416#ifdef FEAT_WINDOWS
1417 win_T *wp;
1418#endif
1419
1420 for (;;)
1421 {
1422 /* check curbuf first: if it was changed we can't abandon it */
1423 if (!hidden && curbufIsChanged())
1424 buf = curbuf;
1425 else
1426 {
1427 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1428 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1429 break;
1430 }
1431 if (buf == NULL) /* No buffers changed */
1432 return FALSE;
1433
1434 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1435 break; /* didn't save - still changes */
1436 }
1437
1438 exiting = FALSE;
1439#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1440 /*
1441 * When ":confirm" used, don't give an error message.
1442 */
1443 if (!(p_confirm || cmdmod.confirm))
1444#endif
1445 {
1446 /* There must be a wait_return for this message, do_buffer()
1447 * may cause a redraw. But wait_return() is a no-op when vgetc()
1448 * is busy (Quit used from window menu), then make sure we don't
1449 * cause a scroll up. */
1450 if (vgetc_busy)
1451 {
1452 msg_row = cmdline_row;
1453 msg_col = 0;
1454 msg_didout = FALSE;
1455 }
1456 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1457 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1458 buf->b_fname))
1459 {
1460 save = no_wait_return;
1461 no_wait_return = FALSE;
1462 wait_return(FALSE);
1463 no_wait_return = save;
1464 }
1465 }
1466
1467#ifdef FEAT_WINDOWS
1468 /* Try to find a window that contains the buffer. */
1469 if (buf != curbuf)
1470 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1471 if (wp->w_buffer == buf)
1472 {
1473 win_goto(wp);
1474# ifdef FEAT_AUTOCMD
1475 /* Paranoia: did autocms wipe out the buffer with changes? */
1476 if (!buf_valid(buf))
1477 return TRUE;
1478# endif
1479 break;
1480 }
1481#endif
1482
1483 /* Open the changed buffer in the current window. */
1484 if (buf != curbuf)
1485 set_curbuf(buf, DOBUF_GOTO);
1486
1487 return TRUE;
1488}
1489
1490/*
1491 * return FAIL if there is no file name, OK if there is one
1492 * give error message for FAIL
1493 */
1494 int
1495check_fname()
1496{
1497 if (curbuf->b_ffname == NULL)
1498 {
1499 EMSG(_(e_noname));
1500 return FAIL;
1501 }
1502 return OK;
1503}
1504
1505/*
1506 * flush the contents of a buffer, unless it has no file name
1507 *
1508 * return FAIL for failure, OK otherwise
1509 */
1510 int
1511buf_write_all(buf, forceit)
1512 buf_T *buf;
1513 int forceit;
1514{
1515 int retval;
1516#ifdef FEAT_AUTOCMD
1517 buf_T *old_curbuf = curbuf;
1518#endif
1519
1520 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1521 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1522 FALSE, forceit, TRUE, FALSE));
1523#ifdef FEAT_AUTOCMD
1524 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001525 {
1526 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001527 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001528 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001529#endif
1530 return retval;
1531}
1532
1533/*
1534 * Code to handle the argument list.
1535 */
1536
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001537static char_u *do_one_arg __ARGS((char_u *str));
1538static int do_arglist __ARGS((char_u *str, int what, int after));
1539static void alist_check_arg_idx __ARGS((void));
1540static int editing_arg_idx __ARGS((win_T *win));
1541#ifdef FEAT_LISTCMDS
1542static int alist_add_list __ARGS((int count, char_u **files, int after));
1543#endif
1544#define AL_SET 1
1545#define AL_ADD 2
1546#define AL_DEL 3
1547
Bram Moolenaar071d4272004-06-13 20:20:40 +00001548/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001549 * Isolate one argument, taking backticks.
1550 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001551 * Return a pointer to the start of the next argument.
1552 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001553 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001554do_one_arg(str)
1555 char_u *str;
1556{
1557 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558 int inbacktick;
1559
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560 inbacktick = FALSE;
1561 for (p = str; *str; ++str)
1562 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001563 /* When the backslash is used for escaping the special meaning of a
1564 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565 if (rem_backslash(str))
1566 {
1567 *p++ = *str++;
1568 *p++ = *str;
1569 }
1570 else
1571 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001572 /* An item ends at a space not in backticks */
1573 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001574 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001575 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001576 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001577 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001578 }
1579 }
1580 str = skipwhite(str);
1581 *p = NUL;
1582
1583 return str;
1584}
1585
Bram Moolenaar86b68352004-12-27 21:59:20 +00001586/*
1587 * Separate the arguments in "str" and return a list of pointers in the
1588 * growarray "gap".
1589 */
1590 int
1591get_arglist(gap, str)
1592 garray_T *gap;
1593 char_u *str;
1594{
1595 ga_init2(gap, (int)sizeof(char_u *), 20);
1596 while (*str != NUL)
1597 {
1598 if (ga_grow(gap, 1) == FAIL)
1599 {
1600 ga_clear(gap);
1601 return FAIL;
1602 }
1603 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1604
1605 /* Isolate one argument, change it in-place, put a NUL after it. */
1606 str = do_one_arg(str);
1607 }
1608 return OK;
1609}
1610
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001611#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001612/*
1613 * Parse a list of arguments (file names), expand them and return in
1614 * "fnames[fcountp]".
1615 * Return FAIL or OK.
1616 */
1617 int
1618get_arglist_exp(str, fcountp, fnamesp)
1619 char_u *str;
1620 int *fcountp;
1621 char_u ***fnamesp;
1622{
1623 garray_T ga;
1624 int i;
1625
1626 if (get_arglist(&ga, str) == FAIL)
1627 return FAIL;
1628 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1629 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1630 ga_clear(&ga);
1631 return i;
1632}
1633#endif
1634
Bram Moolenaar071d4272004-06-13 20:20:40 +00001635#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1636/*
1637 * Redefine the argument list.
1638 */
1639 void
1640set_arglist(str)
1641 char_u *str;
1642{
1643 do_arglist(str, AL_SET, 0);
1644}
1645#endif
1646
1647/*
1648 * "what" == AL_SET: Redefine the argument list to 'str'.
1649 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1650 * "what" == AL_DEL: remove files in 'str' from the argument list.
1651 *
1652 * Return FAIL for failure, OK otherwise.
1653 */
1654/*ARGSUSED*/
1655 static int
1656do_arglist(str, what, after)
1657 char_u *str;
1658 int what;
1659 int after; /* 0 means before first one */
1660{
1661 garray_T new_ga;
1662 int exp_count;
1663 char_u **exp_files;
1664 int i;
1665#ifdef FEAT_LISTCMDS
1666 char_u *p;
1667 int match;
1668#endif
1669
1670 /*
1671 * Collect all file name arguments in "new_ga".
1672 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001673 if (get_arglist(&new_ga, str) == FAIL)
1674 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675
1676#ifdef FEAT_LISTCMDS
1677 if (what == AL_DEL)
1678 {
1679 regmatch_T regmatch;
1680 int didone;
1681
1682 /*
1683 * Delete the items: use each item as a regexp and find a match in the
1684 * argument list.
1685 */
1686#ifdef CASE_INSENSITIVE_FILENAME
1687 regmatch.rm_ic = TRUE; /* Always ignore case */
1688#else
1689 regmatch.rm_ic = FALSE; /* Never ignore case */
1690#endif
1691 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1692 {
1693 p = ((char_u **)new_ga.ga_data)[i];
1694 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1695 if (p == NULL)
1696 break;
1697 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1698 if (regmatch.regprog == NULL)
1699 {
1700 vim_free(p);
1701 break;
1702 }
1703
1704 didone = FALSE;
1705 for (match = 0; match < ARGCOUNT; ++match)
1706 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1707 (colnr_T)0))
1708 {
1709 didone = TRUE;
1710 vim_free(ARGLIST[match].ae_fname);
1711 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1712 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1713 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001714 if (curwin->w_arg_idx > match)
1715 --curwin->w_arg_idx;
1716 --match;
1717 }
1718
1719 vim_free(regmatch.regprog);
1720 vim_free(p);
1721 if (!didone)
1722 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1723 }
1724 ga_clear(&new_ga);
1725 }
1726 else
1727#endif
1728 {
1729 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1730 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1731 ga_clear(&new_ga);
1732 if (i == FAIL)
1733 return FAIL;
1734 if (exp_count == 0)
1735 {
1736 EMSG(_(e_nomatch));
1737 return FAIL;
1738 }
1739
1740#ifdef FEAT_LISTCMDS
1741 if (what == AL_ADD)
1742 {
1743 (void)alist_add_list(exp_count, exp_files, after);
1744 vim_free(exp_files);
1745 }
1746 else /* what == AL_SET */
1747#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001748 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749 }
1750
1751 alist_check_arg_idx();
1752
1753 return OK;
1754}
1755
1756/*
1757 * Check the validity of the arg_idx for each other window.
1758 */
1759 static void
1760alist_check_arg_idx()
1761{
1762#ifdef FEAT_WINDOWS
1763 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001764 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765
Bram Moolenaarf740b292006-02-16 22:11:02 +00001766 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767 if (win->w_alist == curwin->w_alist)
1768 check_arg_idx(win);
1769#else
1770 check_arg_idx(curwin);
1771#endif
1772}
1773
1774/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001775 * Return TRUE if window "win" is editing then file at the current argument
1776 * index.
1777 */
1778 static int
1779editing_arg_idx(win)
1780 win_T *win;
1781{
1782 return !(win->w_arg_idx >= WARGCOUNT(win)
1783 || (win->w_buffer->b_fnum
1784 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1785 && (win->w_buffer->b_ffname == NULL
1786 || !(fullpathcmp(
1787 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1788 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1789}
1790
1791/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792 * Check if window "win" is editing the w_arg_idx file in its argument list.
1793 */
1794 void
1795check_arg_idx(win)
1796 win_T *win;
1797{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001798 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001799 {
1800 /* We are not editing the current entry in the argument list.
1801 * Set "arg_had_last" if we are editing the last one. */
1802 win->w_arg_idx_invalid = TRUE;
1803 if (win->w_arg_idx != WARGCOUNT(win) - 1
1804 && arg_had_last == FALSE
1805#ifdef FEAT_WINDOWS
1806 && ALIST(win) == &global_alist
1807#endif
1808 && GARGCOUNT > 0
1809 && win->w_arg_idx < GARGCOUNT
1810 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1811 || (win->w_buffer->b_ffname != NULL
1812 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1813 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1814 arg_had_last = TRUE;
1815 }
1816 else
1817 {
1818 /* We are editing the current entry in the argument list.
1819 * Set "arg_had_last" if it's also the last one */
1820 win->w_arg_idx_invalid = FALSE;
1821 if (win->w_arg_idx == WARGCOUNT(win) - 1
1822#ifdef FEAT_WINDOWS
1823 && win->w_alist == &global_alist
1824#endif
1825 )
1826 arg_had_last = TRUE;
1827 }
1828}
1829
1830/*
1831 * ":args", ":argslocal" and ":argsglobal".
1832 */
1833 void
1834ex_args(eap)
1835 exarg_T *eap;
1836{
1837 int i;
1838
1839 if (eap->cmdidx != CMD_args)
1840 {
1841#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1842 alist_unlink(ALIST(curwin));
1843 if (eap->cmdidx == CMD_argglobal)
1844 ALIST(curwin) = &global_alist;
1845 else /* eap->cmdidx == CMD_arglocal */
1846 alist_new();
1847#else
1848 ex_ni(eap);
1849 return;
1850#endif
1851 }
1852
1853 if (!ends_excmd(*eap->arg))
1854 {
1855 /*
1856 * ":args file ..": define new argument list, handle like ":next"
1857 * Also for ":argslocal file .." and ":argsglobal file ..".
1858 */
1859 ex_next(eap);
1860 }
1861 else
1862#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1863 if (eap->cmdidx == CMD_args)
1864#endif
1865 {
1866 /*
1867 * ":args": list arguments.
1868 */
1869 if (ARGCOUNT > 0)
1870 {
1871 /* Overwrite the command, for a short list there is no scrolling
1872 * required and no wait_return(). */
1873 gotocmdline(TRUE);
1874 for (i = 0; i < ARGCOUNT; ++i)
1875 {
1876 if (i == curwin->w_arg_idx)
1877 msg_putchar('[');
1878 msg_outtrans(alist_name(&ARGLIST[i]));
1879 if (i == curwin->w_arg_idx)
1880 msg_putchar(']');
1881 msg_putchar(' ');
1882 }
1883 }
1884 }
1885#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1886 else if (eap->cmdidx == CMD_arglocal)
1887 {
1888 garray_T *gap = &curwin->w_alist->al_ga;
1889
1890 /*
1891 * ":argslocal": make a local copy of the global argument list.
1892 */
1893 if (ga_grow(gap, GARGCOUNT) == OK)
1894 for (i = 0; i < GARGCOUNT; ++i)
1895 if (GARGLIST[i].ae_fname != NULL)
1896 {
1897 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1898 vim_strsave(GARGLIST[i].ae_fname);
1899 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1900 GARGLIST[i].ae_fnum;
1901 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001902 }
1903 }
1904#endif
1905}
1906
1907/*
1908 * ":previous", ":sprevious", ":Next" and ":sNext".
1909 */
1910 void
1911ex_previous(eap)
1912 exarg_T *eap;
1913{
1914 /* If past the last one already, go to the last one. */
1915 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1916 do_argfile(eap, ARGCOUNT - 1);
1917 else
1918 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1919}
1920
1921/*
1922 * ":rewind", ":first", ":sfirst" and ":srewind".
1923 */
1924 void
1925ex_rewind(eap)
1926 exarg_T *eap;
1927{
1928 do_argfile(eap, 0);
1929}
1930
1931/*
1932 * ":last" and ":slast".
1933 */
1934 void
1935ex_last(eap)
1936 exarg_T *eap;
1937{
1938 do_argfile(eap, ARGCOUNT - 1);
1939}
1940
1941/*
1942 * ":argument" and ":sargument".
1943 */
1944 void
1945ex_argument(eap)
1946 exarg_T *eap;
1947{
1948 int i;
1949
1950 if (eap->addr_count > 0)
1951 i = eap->line2 - 1;
1952 else
1953 i = curwin->w_arg_idx;
1954 do_argfile(eap, i);
1955}
1956
1957/*
1958 * Edit file "argn" of the argument lists.
1959 */
1960 void
1961do_argfile(eap, argn)
1962 exarg_T *eap;
1963 int argn;
1964{
1965 int other;
1966 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001967 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968
1969 if (argn < 0 || argn >= ARGCOUNT)
1970 {
1971 if (ARGCOUNT <= 1)
1972 EMSG(_("E163: There is only one file to edit"));
1973 else if (argn < 0)
1974 EMSG(_("E164: Cannot go before first file"));
1975 else
1976 EMSG(_("E165: Cannot go beyond last file"));
1977 }
1978 else
1979 {
1980 setpcmark();
1981#ifdef FEAT_GUI
1982 need_mouse_correct = TRUE;
1983#endif
1984
1985#ifdef FEAT_WINDOWS
1986 if (*eap->cmd == 's') /* split window first */
1987 {
1988 if (win_split(0, 0) == FAIL)
1989 return;
1990# ifdef FEAT_SCROLLBIND
1991 curwin->w_p_scb = FALSE;
1992# endif
1993 }
1994 else
1995#endif
1996 {
1997 /*
1998 * if 'hidden' set, only check for changed file when re-editing
1999 * the same buffer
2000 */
2001 other = TRUE;
2002 if (P_HID(curbuf))
2003 {
2004 p = fix_fname(alist_name(&ARGLIST[argn]));
2005 other = otherfile(p);
2006 vim_free(p);
2007 }
2008 if ((!P_HID(curbuf) || !other)
2009 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2010 return;
2011 }
2012
2013 curwin->w_arg_idx = argn;
2014 if (argn == ARGCOUNT - 1
2015#ifdef FEAT_WINDOWS
2016 && curwin->w_alist == &global_alist
2017#endif
2018 )
2019 arg_had_last = TRUE;
2020
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002021 /* Edit the file; always use the last known line number.
2022 * When it fails (e.g. Abort for already edited file) restore the
2023 * argument index. */
2024 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025 eap, ECMD_LAST,
2026 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) +
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002027 (eap->forceit ? ECMD_FORCEIT : 0)) == FAIL)
2028 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002029 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002030 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031 setmark('\'');
2032 }
2033}
2034
2035/*
2036 * ":next", and commands that behave like it.
2037 */
2038 void
2039ex_next(eap)
2040 exarg_T *eap;
2041{
2042 int i;
2043
2044 /*
2045 * check for changed buffer now, if this fails the argument list is not
2046 * redefined.
2047 */
2048 if ( P_HID(curbuf)
2049 || eap->cmdidx == CMD_snext
2050 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2051 {
2052 if (*eap->arg != NUL) /* redefine file list */
2053 {
2054 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2055 return;
2056 i = 0;
2057 }
2058 else
2059 i = curwin->w_arg_idx + (int)eap->line2;
2060 do_argfile(eap, i);
2061 }
2062}
2063
2064#ifdef FEAT_LISTCMDS
2065/*
2066 * ":argedit"
2067 */
2068 void
2069ex_argedit(eap)
2070 exarg_T *eap;
2071{
2072 int fnum;
2073 int i;
2074 char_u *s;
2075
2076 /* Add the argument to the buffer list and get the buffer number. */
2077 fnum = buflist_add(eap->arg, BLN_LISTED);
2078
2079 /* Check if this argument is already in the argument list. */
2080 for (i = 0; i < ARGCOUNT; ++i)
2081 if (ARGLIST[i].ae_fnum == fnum)
2082 break;
2083 if (i == ARGCOUNT)
2084 {
2085 /* Can't find it, add it to the argument list. */
2086 s = vim_strsave(eap->arg);
2087 if (s == NULL)
2088 return;
2089 i = alist_add_list(1, &s,
2090 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2091 if (i < 0)
2092 return;
2093 curwin->w_arg_idx = i;
2094 }
2095
2096 alist_check_arg_idx();
2097
2098 /* Edit the argument. */
2099 do_argfile(eap, i);
2100}
2101
2102/*
2103 * ":argadd"
2104 */
2105 void
2106ex_argadd(eap)
2107 exarg_T *eap;
2108{
2109 do_arglist(eap->arg, AL_ADD,
2110 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2111#ifdef FEAT_TITLE
2112 maketitle();
2113#endif
2114}
2115
2116/*
2117 * ":argdelete"
2118 */
2119 void
2120ex_argdelete(eap)
2121 exarg_T *eap;
2122{
2123 int i;
2124 int n;
2125
2126 if (eap->addr_count > 0)
2127 {
2128 /* ":1,4argdel": Delete all arguments in the range. */
2129 if (eap->line2 > ARGCOUNT)
2130 eap->line2 = ARGCOUNT;
2131 n = eap->line2 - eap->line1 + 1;
2132 if (*eap->arg != NUL || n <= 0)
2133 EMSG(_(e_invarg));
2134 else
2135 {
2136 for (i = eap->line1; i <= eap->line2; ++i)
2137 vim_free(ARGLIST[i - 1].ae_fname);
2138 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2139 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2140 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002141 if (curwin->w_arg_idx >= eap->line2)
2142 curwin->w_arg_idx -= n;
2143 else if (curwin->w_arg_idx > eap->line1)
2144 curwin->w_arg_idx = eap->line1;
2145 }
2146 }
2147 else if (*eap->arg == NUL)
2148 EMSG(_(e_argreq));
2149 else
2150 do_arglist(eap->arg, AL_DEL, 0);
2151#ifdef FEAT_TITLE
2152 maketitle();
2153#endif
2154}
2155
2156/*
2157 * ":argdo", ":windo", ":bufdo"
2158 */
2159 void
2160ex_listdo(eap)
2161 exarg_T *eap;
2162{
2163 int i;
2164#ifdef FEAT_WINDOWS
2165 win_T *win;
2166#endif
2167 buf_T *buf;
2168 int next_fnum = 0;
2169#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2170 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002171#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002172 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002173
2174#ifndef FEAT_WINDOWS
2175 if (eap->cmdidx == CMD_windo)
2176 {
2177 ex_ni(eap);
2178 return;
2179 }
2180#endif
2181
2182#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2183 if (eap->cmdidx != CMD_windo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002184 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2185 * great speed improvement. */
2186 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002187#endif
2188
2189 if (eap->cmdidx == CMD_windo
2190 || P_HID(curbuf)
2191 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2192 {
2193 /* start at the first argument/window/buffer */
2194 i = 0;
2195#ifdef FEAT_WINDOWS
2196 win = firstwin;
2197#endif
2198 /* set pcmark now */
2199 if (eap->cmdidx == CMD_bufdo)
2200 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2201 else
2202 setpcmark();
2203 listcmd_busy = TRUE; /* avoids setting pcmark below */
2204
2205 while (!got_int)
2206 {
2207 if (eap->cmdidx == CMD_argdo)
2208 {
2209 /* go to argument "i" */
2210 if (i == ARGCOUNT)
2211 break;
2212 /* Don't call do_argfile() when already there, it will try
2213 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002214 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002215 {
2216 /* Clear 'shm' to avoid that the file message overwrites
2217 * any output from the command. */
2218 p_shm_save = vim_strsave(p_shm);
2219 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002221 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2222 vim_free(p_shm_save);
2223 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002224 if (curwin->w_arg_idx != i)
2225 break;
2226 ++i;
2227 }
2228#ifdef FEAT_WINDOWS
2229 else if (eap->cmdidx == CMD_windo)
2230 {
2231 /* go to window "win" */
2232 if (!win_valid(win))
2233 break;
2234 win_goto(win);
2235 win = win->w_next;
2236 }
2237#endif
2238 else if (eap->cmdidx == CMD_bufdo)
2239 {
2240 /* Remember the number of the next listed buffer, in case
2241 * ":bwipe" is used or autocommands do something strange. */
2242 next_fnum = -1;
2243 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2244 if (buf->b_p_bl)
2245 {
2246 next_fnum = buf->b_fnum;
2247 break;
2248 }
2249 }
2250
2251 /* execute the command */
2252 do_cmdline(eap->arg, eap->getline, eap->cookie,
2253 DOCMD_VERBOSE + DOCMD_NOWAIT);
2254
2255 if (eap->cmdidx == CMD_bufdo)
2256 {
2257 /* Done? */
2258 if (next_fnum < 0)
2259 break;
2260 /* Check if the buffer still exists. */
2261 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2262 if (buf->b_fnum == next_fnum)
2263 break;
2264 if (buf == NULL)
2265 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002266
2267 /* Go to the next buffer. Clear 'shm' to avoid that the file
2268 * message overwrites any output from the command. */
2269 p_shm_save = vim_strsave(p_shm);
2270 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002272 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2273 vim_free(p_shm_save);
2274
Bram Moolenaar071d4272004-06-13 20:20:40 +00002275 /* If autocommands took us elsewhere, quit here */
2276 if (curbuf->b_fnum != next_fnum)
2277 break;
2278 }
2279
2280 if (eap->cmdidx == CMD_windo)
2281 {
2282 validate_cursor(); /* cursor may have moved */
2283#ifdef FEAT_SCROLLBIND
2284 /* required when 'scrollbind' has been set */
2285 if (curwin->w_p_scb)
2286 do_check_scrollbind(TRUE);
2287#endif
2288 }
2289 }
2290 listcmd_busy = FALSE;
2291 }
2292
2293#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002294 if (save_ei != NULL)
2295 {
2296 au_event_restore(save_ei);
2297 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2298 curbuf->b_fname, TRUE, curbuf);
2299 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300#endif
2301}
2302
2303/*
2304 * Add files[count] to the arglist of the current window after arg "after".
2305 * The file names in files[count] must have been allocated and are taken over.
2306 * Files[] itself is not taken over.
2307 * Returns index of first added argument. Returns -1 when failed (out of mem).
2308 */
2309 static int
2310alist_add_list(count, files, after)
2311 int count;
2312 char_u **files;
2313 int after; /* where to add: 0 = before first one */
2314{
2315 int i;
2316
2317 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2318 {
2319 if (after < 0)
2320 after = 0;
2321 if (after > ARGCOUNT)
2322 after = ARGCOUNT;
2323 if (after < ARGCOUNT)
2324 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2325 (ARGCOUNT - after) * sizeof(aentry_T));
2326 for (i = 0; i < count; ++i)
2327 {
2328 ARGLIST[after + i].ae_fname = files[i];
2329 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2330 }
2331 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332 if (curwin->w_arg_idx >= after)
2333 ++curwin->w_arg_idx;
2334 return after;
2335 }
2336
2337 for (i = 0; i < count; ++i)
2338 vim_free(files[i]);
2339 return -1;
2340}
2341
2342#endif /* FEAT_LISTCMDS */
2343
2344#ifdef FEAT_EVAL
2345/*
2346 * ":compiler[!] {name}"
2347 */
2348 void
2349ex_compiler(eap)
2350 exarg_T *eap;
2351{
2352 char_u *buf;
2353 char_u *old_cur_comp = NULL;
2354 char_u *p;
2355
2356 if (*eap->arg == NUL)
2357 {
2358 /* List all compiler scripts. */
2359 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2360 /* ) keep the indenter happy... */
2361 }
2362 else
2363 {
2364 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2365 if (buf != NULL)
2366 {
2367 if (eap->forceit)
2368 {
2369 /* ":compiler! {name}" sets global options */
2370 do_cmdline_cmd((char_u *)
2371 "command -nargs=* CompilerSet set <args>");
2372 }
2373 else
2374 {
2375 /* ":compiler! {name}" sets local options.
2376 * To remain backwards compatible "current_compiler" is always
2377 * used. A user's compiler plugin may set it, the distributed
2378 * plugin will then skip the settings. Afterwards set
2379 * "b:current_compiler" and restore "current_compiler". */
2380 old_cur_comp = get_var_value((char_u *)"current_compiler");
2381 if (old_cur_comp != NULL)
2382 old_cur_comp = vim_strsave(old_cur_comp);
2383 do_cmdline_cmd((char_u *)
2384 "command -nargs=* CompilerSet setlocal <args>");
2385 }
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002386 do_unlet((char_u *)"current_compiler", TRUE);
2387 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388
2389 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002390 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002391 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2392 vim_free(buf);
2393
2394 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2395
2396 /* Set "b:current_compiler" from "current_compiler". */
2397 p = get_var_value((char_u *)"current_compiler");
2398 if (p != NULL)
2399 set_internal_string_var((char_u *)"b:current_compiler", p);
2400
2401 /* Restore "current_compiler" for ":compiler {name}". */
2402 if (!eap->forceit)
2403 {
2404 if (old_cur_comp != NULL)
2405 {
2406 set_internal_string_var((char_u *)"current_compiler",
2407 old_cur_comp);
2408 vim_free(old_cur_comp);
2409 }
2410 else
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002411 do_unlet((char_u *)"current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412 }
2413 }
2414 }
2415}
2416#endif
2417
2418/*
2419 * ":runtime {name}"
2420 */
2421 void
2422ex_runtime(eap)
2423 exarg_T *eap;
2424{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002425 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426}
2427
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002428static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002430/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00002431 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002432source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433 char_u *fname;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002434 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435{
2436 (void)do_source(fname, FALSE, FALSE);
2437}
2438
2439/*
2440 * Source the file "name" from all directories in 'runtimepath'.
2441 * "name" can contain wildcards.
2442 * When "all" is TRUE, source all files, otherwise only the first one.
2443 * return FAIL when no file could be sourced, OK otherwise.
2444 */
2445 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002446source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 char_u *name;
2448 int all;
2449{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002450 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451}
2452
2453/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002454 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2455 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2457 * used.
2458 * Returns OK when at least one match found, FAIL otherwise.
2459 */
2460 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002461do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002462 char_u *name;
2463 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002464 void (*callback)__ARGS((char_u *fname, void *ck));
2465 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466{
2467 char_u *rtp;
2468 char_u *np;
2469 char_u *buf;
2470 char_u *rtp_copy;
2471 char_u *tail;
2472 int num_files;
2473 char_u **files;
2474 int i;
2475 int did_one = FALSE;
2476#ifdef AMIGA
2477 struct Process *proc = (struct Process *)FindTask(0L);
2478 APTR save_winptr = proc->pr_WindowPtr;
2479
2480 /* Avoid a requester here for a volume that doesn't exist. */
2481 proc->pr_WindowPtr = (APTR)-1L;
2482#endif
2483
2484 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2485 * value. */
2486 rtp_copy = vim_strsave(p_rtp);
2487 buf = alloc(MAXPATHL);
2488 if (buf != NULL && rtp_copy != NULL)
2489 {
2490 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002491 {
2492 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002493 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002494 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002495 verbose_leave();
2496 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002497
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 /* Loop over all entries in 'runtimepath'. */
2499 rtp = rtp_copy;
2500 while (*rtp != NUL && (all || !did_one))
2501 {
2502 /* Copy the path from 'runtimepath' to buf[]. */
2503 copy_option_part(&rtp, buf, MAXPATHL, ",");
2504 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2505 {
2506 add_pathsep(buf);
2507 tail = buf + STRLEN(buf);
2508
2509 /* Loop over all patterns in "name" */
2510 np = name;
2511 while (*np != NUL && (all || !did_one))
2512 {
2513 /* Append the pattern from "name" to buf[]. */
2514 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2515 "\t ");
2516
2517 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002518 {
2519 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002520 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002521 verbose_leave();
2522 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002523
2524 /* Expand wildcards, invoke the callback for each match. */
2525 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2526 EW_FILE) == OK)
2527 {
2528 for (i = 0; i < num_files; ++i)
2529 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002530 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531 did_one = TRUE;
2532 if (!all)
2533 break;
2534 }
2535 FreeWild(num_files, files);
2536 }
2537 }
2538 }
2539 }
2540 }
2541 vim_free(buf);
2542 vim_free(rtp_copy);
2543 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002544 {
2545 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002546 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002547 verbose_leave();
2548 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002549
2550#ifdef AMIGA
2551 proc->pr_WindowPtr = save_winptr;
2552#endif
2553
2554 return did_one ? OK : FAIL;
2555}
2556
2557#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2558/*
2559 * ":options"
2560 */
2561/*ARGSUSED*/
2562 void
2563ex_options(eap)
2564 exarg_T *eap;
2565{
2566 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2567}
2568#endif
2569
2570/*
2571 * ":source {fname}"
2572 */
2573 void
2574ex_source(eap)
2575 exarg_T *eap;
2576{
2577#ifdef FEAT_BROWSE
2578 if (cmdmod.browse)
2579 {
2580 char_u *fname = NULL;
2581
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002582 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2584 if (fname != NULL)
2585 {
2586 cmd_source(fname, eap);
2587 vim_free(fname);
2588 }
2589 }
2590 else
2591#endif
2592 cmd_source(eap->arg, eap);
2593}
2594
2595 static void
2596cmd_source(fname, eap)
2597 char_u *fname;
2598 exarg_T *eap;
2599{
2600 if (*fname == NUL)
2601 EMSG(_(e_argreq));
2602
2603 /* ":source!" read vi commands */
2604 else if (eap != NULL && eap->forceit)
2605 /* Need to execute the commands directly when:
2606 * - ":g" command busy
2607 * - after ":argdo", ":windo" or ":bufdo"
2608 * - another command follows
2609 * - inside a loop
2610 */
2611 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2612#ifdef FEAT_EVAL
2613 || eap->cstack->cs_idx >= 0
2614#endif
2615 );
2616
2617 /* ":source" read ex commands */
2618 else if (do_source(fname, FALSE, FALSE) == FAIL)
2619 EMSG2(_(e_notopen), fname);
2620}
2621
2622/*
2623 * ":source" and associated commands.
2624 */
2625/*
2626 * Structure used to store info for each sourced file.
2627 * It is shared between do_source() and getsourceline().
2628 * This is required, because it needs to be handed to do_cmdline() and
2629 * sourcing can be done recursively.
2630 */
2631struct source_cookie
2632{
2633 FILE *fp; /* opened file for sourcing */
2634 char_u *nextline; /* if not NULL: line that was read ahead */
2635 int finished; /* ":finish" used */
2636#if defined (USE_CRNL) || defined (USE_CR)
2637 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2638 int error; /* TRUE if LF found after CR-LF */
2639#endif
2640#ifdef FEAT_EVAL
2641 linenr_T breakpoint; /* next line with breakpoint or zero */
2642 char_u *fname; /* name of sourced file */
2643 int dbg_tick; /* debug_tick when breakpoint was set */
2644 int level; /* top nesting level of sourced file */
2645#endif
2646#ifdef FEAT_MBYTE
2647 vimconv_T conv; /* type of conversion */
2648#endif
2649};
2650
2651#ifdef FEAT_EVAL
2652/*
2653 * Return the address holding the next breakpoint line for a source cookie.
2654 */
2655 linenr_T *
2656source_breakpoint(cookie)
2657 void *cookie;
2658{
2659 return &((struct source_cookie *)cookie)->breakpoint;
2660}
2661
2662/*
2663 * Return the address holding the debug tick for a source cookie.
2664 */
2665 int *
2666source_dbg_tick(cookie)
2667 void *cookie;
2668{
2669 return &((struct source_cookie *)cookie)->dbg_tick;
2670}
2671
2672/*
2673 * Return the nesting level for a source cookie.
2674 */
2675 int
2676source_level(cookie)
2677 void *cookie;
2678{
2679 return ((struct source_cookie *)cookie)->level;
2680}
2681#endif
2682
2683static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2684
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685#if defined(WIN32) && defined(FEAT_CSCOPE)
2686static FILE *fopen_noinh_readbin __ARGS((char *filename));
2687
2688/*
2689 * Special function to open a file without handle inheritance.
2690 */
2691 static FILE *
2692fopen_noinh_readbin(filename)
2693 char *filename;
2694{
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00002695 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696
2697 if (fd_tmp == -1)
2698 return NULL;
2699 return fdopen(fd_tmp, READBIN);
2700}
2701#endif
2702
2703
2704/*
2705 * do_source: Read the file "fname" and execute its lines as EX commands.
2706 *
2707 * This function may be called recursively!
2708 *
2709 * return FAIL if file could not be opened, OK otherwise
2710 */
2711 int
2712do_source(fname, check_other, is_vimrc)
2713 char_u *fname;
2714 int check_other; /* check for .vimrc and _vimrc */
2715 int is_vimrc; /* call vimrc_found() when file exists */
2716{
2717 struct source_cookie cookie;
2718 char_u *save_sourcing_name;
2719 linenr_T save_sourcing_lnum;
2720 char_u *p;
2721 char_u *fname_exp;
2722 int retval = FAIL;
2723#ifdef FEAT_EVAL
2724 scid_T save_current_SID;
2725 static scid_T last_current_SID = 0;
2726 void *save_funccalp;
2727 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002728 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729# ifdef UNIX
2730 struct stat st;
2731 int stat_ok;
2732# endif
2733#endif
2734#ifdef STARTUPTIME
2735 struct timeval tv_rel;
2736 struct timeval tv_start;
2737#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002738#ifdef FEAT_PROFILE
2739 proftime_T wait_start;
2740#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002741
2742#ifdef RISCOS
2743 p = mch_munge_fname(fname);
2744#else
2745 p = expand_env_save(fname);
2746#endif
2747 if (p == NULL)
2748 return retval;
2749 fname_exp = fix_fname(p);
2750 vim_free(p);
2751 if (fname_exp == NULL)
2752 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753 if (mch_isdir(fname_exp))
2754 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002755 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 goto theend;
2757 }
2758
2759#if defined(WIN32) && defined(FEAT_CSCOPE)
2760 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2761#else
2762 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2763#endif
2764 if (cookie.fp == NULL && check_other)
2765 {
2766 /*
2767 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2768 * and ".exrc" by "_exrc" or vice versa.
2769 */
2770 p = gettail(fname_exp);
2771 if ((*p == '.' || *p == '_')
2772 && (STRICMP(p + 1, "vimrc") == 0
2773 || STRICMP(p + 1, "gvimrc") == 0
2774 || STRICMP(p + 1, "exrc") == 0))
2775 {
2776 if (*p == '_')
2777 *p = '.';
2778 else
2779 *p = '_';
2780#if defined(WIN32) && defined(FEAT_CSCOPE)
2781 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2782#else
2783 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2784#endif
2785 }
2786 }
2787
2788 if (cookie.fp == NULL)
2789 {
2790 if (p_verbose > 0)
2791 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002792 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002793 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002794 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002795 else
2796 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002797 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002798 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 }
2800 goto theend;
2801 }
2802
2803 /*
2804 * The file exists.
2805 * - In verbose mode, give a message.
2806 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2807 */
2808 if (p_verbose > 1)
2809 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002810 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002812 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813 else
2814 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002815 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002816 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817 }
2818 if (is_vimrc)
2819 vimrc_found();
2820
2821#ifdef USE_CRNL
2822 /* If no automatic file format: Set default to CR-NL. */
2823 if (*p_ffs == NUL)
2824 cookie.fileformat = EOL_DOS;
2825 else
2826 cookie.fileformat = EOL_UNKNOWN;
2827 cookie.error = FALSE;
2828#endif
2829
2830#ifdef USE_CR
2831 /* If no automatic file format: Set default to CR. */
2832 if (*p_ffs == NUL)
2833 cookie.fileformat = EOL_MAC;
2834 else
2835 cookie.fileformat = EOL_UNKNOWN;
2836 cookie.error = FALSE;
2837#endif
2838
2839 cookie.nextline = NULL;
2840 cookie.finished = FALSE;
2841
2842#ifdef FEAT_EVAL
2843 /*
2844 * Check if this script has a breakpoint.
2845 */
2846 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2847 cookie.fname = fname_exp;
2848 cookie.dbg_tick = debug_tick;
2849
2850 cookie.level = ex_nesting_level;
2851#endif
2852#ifdef FEAT_MBYTE
2853 cookie.conv.vc_type = CONV_NONE; /* no conversion */
2854
2855 /* Try reading the first few bytes to check for a UTF-8 BOM. */
2856 {
2857 char_u buf[3];
2858
2859 if (fread((char *)buf, sizeof(char_u), (size_t)3, cookie.fp)
2860 == (size_t)3
2861 && buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf)
2862 /* Found BOM, setup conversion and skip over it. */
2863 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
2864 else
2865 /* No BOM found, rewind. */
2866 fseek(cookie.fp, 0L, SEEK_SET);
2867 }
2868#endif
2869
2870 /*
2871 * Keep the sourcing name/lnum, for recursive calls.
2872 */
2873 save_sourcing_name = sourcing_name;
2874 sourcing_name = fname_exp;
2875 save_sourcing_lnum = sourcing_lnum;
2876 sourcing_lnum = 0;
2877
2878#ifdef STARTUPTIME
2879 time_push(&tv_rel, &tv_start);
2880#endif
2881
2882#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00002883# ifdef FEAT_PROFILE
2884 if (do_profiling)
2885 prof_child_enter(&wait_start); /* entering a child now */
2886# endif
2887
2888 /* Don't use local function variables, if called from a function.
2889 * Also starts profiling timer for nested script. */
2890 save_funccalp = save_funccal();
2891
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892 /*
2893 * Check if this script was sourced before to finds its SID.
2894 * If it's new, generate a new SID.
2895 */
2896 save_current_SID = current_SID;
2897# ifdef UNIX
2898 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
2899# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002900 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
2901 {
2902 si = &SCRIPT_ITEM(current_SID);
2903 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904 && (
2905# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00002906 /* Compare dev/ino when possible, it catches symbolic
2907 * links. Also compare file names, the inode may change
2908 * when the file was edited. */
Bram Moolenaar05159a02005-02-26 23:04:13 +00002909 ((stat_ok && si->sn_dev != -1)
2910 && (si->sn_dev == st.st_dev
2911 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002913 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002915 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916 if (current_SID == 0)
2917 {
2918 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002919 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
2920 == FAIL)
2921 goto almosttheend;
2922 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00002924 ++script_items.ga_len;
2925 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
2926# ifdef FEAT_PROFILE
2927 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002929 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00002930 si = &SCRIPT_ITEM(current_SID);
2931 si->sn_name = fname_exp;
2932 fname_exp = NULL;
2933# ifdef UNIX
2934 if (stat_ok)
2935 {
2936 si->sn_dev = st.st_dev;
2937 si->sn_ino = st.st_ino;
2938 }
2939 else
2940 si->sn_dev = -1;
2941# endif
2942
Bram Moolenaar071d4272004-06-13 20:20:40 +00002943 /* Allocate the local script variables to use for this script. */
2944 new_script_vars(current_SID);
2945 }
2946
Bram Moolenaar05159a02005-02-26 23:04:13 +00002947# ifdef FEAT_PROFILE
2948 if (do_profiling)
2949 {
2950 int forceit;
2951
2952 /* Check if we do profiling for this script. */
2953 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
2954 {
2955 script_do_profile(si);
2956 si->sn_pr_force = forceit;
2957 }
2958 if (si->sn_prof_on)
2959 {
2960 ++si->sn_pr_count;
2961 profile_start(&si->sn_pr_start);
2962 profile_zero(&si->sn_pr_children);
2963 }
2964 }
2965# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002966#endif
2967
2968 /*
2969 * Call do_cmdline, which will call getsourceline() to get the lines.
2970 */
2971 do_cmdline(NULL, getsourceline, (void *)&cookie,
2972 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
2973
2974 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002975
2976#ifdef FEAT_PROFILE
2977 if (do_profiling)
2978 {
2979 /* Get "si" again, "script_items" may have been reallocated. */
2980 si = &SCRIPT_ITEM(current_SID);
2981 if (si->sn_prof_on)
2982 {
2983 profile_end(&si->sn_pr_start);
2984 profile_sub_wait(&wait_start, &si->sn_pr_start);
2985 profile_add(&si->sn_pr_total, &si->sn_pr_start);
2986 profile_add(&si->sn_pr_self, &si->sn_pr_start);
2987 profile_sub(&si->sn_pr_self, &si->sn_pr_children);
2988 }
2989 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990#endif
2991
2992 if (got_int)
2993 EMSG(_(e_interr));
2994 sourcing_name = save_sourcing_name;
2995 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002996 if (p_verbose > 1)
2997 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002998 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002999 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003001 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003002 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003003 }
3004#ifdef STARTUPTIME
Bram Moolenaar555b2802005-05-19 21:08:39 +00003005 vim_snprintf(IObuff, IOSIZE, "sourcing %s", fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003006 time_msg(IObuff, &tv_start);
3007 time_pop(&tv_rel);
3008#endif
3009
3010#ifdef FEAT_EVAL
3011 /*
3012 * After a "finish" in debug mode, need to break at first command of next
3013 * sourced file.
3014 */
3015 if (save_debug_break_level > ex_nesting_level
3016 && debug_break_level == ex_nesting_level)
3017 ++debug_break_level;
3018#endif
3019
Bram Moolenaar05159a02005-02-26 23:04:13 +00003020#ifdef FEAT_EVAL
3021almosttheend:
3022 current_SID = save_current_SID;
3023 restore_funccal(save_funccalp);
3024# ifdef FEAT_PROFILE
3025 if (do_profiling)
3026 prof_child_exit(&wait_start); /* leaving a child now */
3027# endif
3028#endif
3029 fclose(cookie.fp);
3030 vim_free(cookie.nextline);
3031#ifdef FEAT_MBYTE
3032 convert_setup(&cookie.conv, NULL, NULL);
3033#endif
3034
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035theend:
3036 vim_free(fname_exp);
3037 return retval;
3038}
3039
3040#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003041
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042/*
3043 * ":scriptnames"
3044 */
3045/*ARGSUSED*/
3046 void
3047ex_scriptnames(eap)
3048 exarg_T *eap;
3049{
3050 int i;
3051
Bram Moolenaar05159a02005-02-26 23:04:13 +00003052 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3053 if (SCRIPT_ITEM(i).sn_name != NULL)
3054 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055}
3056
3057# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3058/*
3059 * Fix slashes in the list of script names for 'shellslash'.
3060 */
3061 void
3062scriptnames_slash_adjust()
3063{
3064 int i;
3065
Bram Moolenaar05159a02005-02-26 23:04:13 +00003066 for (i = 1; i <= script_items.ga_len; ++i)
3067 if (SCRIPT_ITEM(i).sn_name != NULL)
3068 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069}
3070# endif
3071
3072/*
3073 * Get a pointer to a script name. Used for ":verbose set".
3074 */
3075 char_u *
3076get_scriptname(id)
3077 scid_T id;
3078{
3079 if (id == SID_MODELINE)
3080 return (char_u *)"modeline";
3081 if (id == SID_CMDARG)
3082 return (char_u *)"--cmd argument";
3083 if (id == SID_CARG)
3084 return (char_u *)"-c argument";
3085 if (id == SID_ENV)
3086 return (char_u *)"environment variable";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003087 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003089
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003090# if defined(EXITFREE) || defined(PROTO)
3091 void
3092free_scriptnames()
3093{
3094 int i;
3095
3096 for (i = script_items.ga_len; i > 0; --i)
3097 vim_free(SCRIPT_ITEM(i).sn_name);
3098 ga_clear(&script_items);
3099}
3100# endif
3101
Bram Moolenaar071d4272004-06-13 20:20:40 +00003102#endif
3103
3104#if defined(USE_CR) || defined(PROTO)
3105
3106# if defined(__MSL__) && (__MSL__ >= 22)
3107/*
3108 * Newer version of the Metrowerks library handle DOS and UNIX files
3109 * without help.
3110 * Test with earlier versions, MSL 2.2 is the library supplied with
3111 * Codewarrior Pro 2.
3112 */
3113 char *
3114fgets_cr(s, n, stream)
3115 char *s;
3116 int n;
3117 FILE *stream;
3118{
3119 return fgets(s, n, stream);
3120}
3121# else
3122/*
3123 * Version of fgets() which also works for lines ending in a <CR> only
3124 * (Macintosh format).
3125 * For older versions of the Metrowerks library.
3126 * At least CodeWarrior 9 needed this code.
3127 */
3128 char *
3129fgets_cr(s, n, stream)
3130 char *s;
3131 int n;
3132 FILE *stream;
3133{
3134 int c = 0;
3135 int char_read = 0;
3136
3137 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3138 {
3139 c = fgetc(stream);
3140 s[char_read++] = c;
3141 /* If the file is in DOS format, we need to skip a NL after a CR. I
3142 * thought it was the other way around, but this appears to work... */
3143 if (c == '\n')
3144 {
3145 c = fgetc(stream);
3146 if (c != '\r')
3147 ungetc(c, stream);
3148 }
3149 }
3150
3151 s[char_read] = 0;
3152 if (char_read == 0)
3153 return NULL;
3154
3155 if (feof(stream) && char_read == 1)
3156 return NULL;
3157
3158 return s;
3159}
3160# endif
3161#endif
3162
3163/*
3164 * Get one full line from a sourced file.
3165 * Called by do_cmdline() when it's called from do_source().
3166 *
3167 * Return a pointer to the line in allocated memory.
3168 * Return NULL for end-of-file or some error.
3169 */
3170/* ARGSUSED */
3171 char_u *
3172getsourceline(c, cookie, indent)
3173 int c; /* not used */
3174 void *cookie;
3175 int indent; /* not used */
3176{
3177 struct source_cookie *sp = (struct source_cookie *)cookie;
3178 char_u *line;
3179 char_u *p, *s;
3180
3181#ifdef FEAT_EVAL
3182 /* If breakpoints have been added/deleted need to check for it. */
3183 if (sp->dbg_tick < debug_tick)
3184 {
3185 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3186 sp->dbg_tick = debug_tick;
3187 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003188# ifdef FEAT_PROFILE
3189 if (do_profiling)
3190 script_line_end();
3191# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192#endif
3193 /*
3194 * Get current line. If there is a read-ahead line, use it, otherwise get
3195 * one now.
3196 */
3197 if (sp->finished)
3198 line = NULL;
3199 else if (sp->nextline == NULL)
3200 line = get_one_sourceline(sp);
3201 else
3202 {
3203 line = sp->nextline;
3204 sp->nextline = NULL;
3205 ++sourcing_lnum;
3206 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003207#ifdef FEAT_PROFILE
3208 if (line != NULL && do_profiling)
3209 script_line_start();
3210#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211
3212 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3213 * contain the 'C' flag. */
3214 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3215 {
3216 /* compensate for the one line read-ahead */
3217 --sourcing_lnum;
3218 for (;;)
3219 {
3220 sp->nextline = get_one_sourceline(sp);
3221 if (sp->nextline == NULL)
3222 break;
3223 p = skipwhite(sp->nextline);
3224 if (*p != '\\')
3225 break;
3226 s = alloc((int)(STRLEN(line) + STRLEN(p)));
3227 if (s == NULL) /* out of memory */
3228 break;
3229 STRCPY(s, line);
3230 STRCAT(s, p + 1);
3231 vim_free(line);
3232 line = s;
3233 vim_free(sp->nextline);
3234 }
3235 }
3236
3237#ifdef FEAT_MBYTE
3238 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3239 {
3240 /* Convert the encoding of the script line. */
3241 s = string_convert(&sp->conv, line, NULL);
3242 if (s != NULL)
3243 {
3244 vim_free(line);
3245 line = s;
3246 }
3247 }
3248#endif
3249
3250#ifdef FEAT_EVAL
3251 /* Did we encounter a breakpoint? */
3252 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3253 {
3254 dbg_breakpoint(sp->fname, sourcing_lnum);
3255 /* Find next breakpoint. */
3256 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3257 sp->dbg_tick = debug_tick;
3258 }
3259#endif
3260
3261 return line;
3262}
3263
3264 static char_u *
3265get_one_sourceline(sp)
3266 struct source_cookie *sp;
3267{
3268 garray_T ga;
3269 int len;
3270 int c;
3271 char_u *buf;
3272#ifdef USE_CRNL
3273 int has_cr; /* CR-LF found */
3274#endif
3275#ifdef USE_CR
3276 char_u *scan;
3277#endif
3278 int have_read = FALSE;
3279
3280 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003281 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003282
3283 /*
3284 * Loop until there is a finished line (or end-of-file).
3285 */
3286 sourcing_lnum++;
3287 for (;;)
3288 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003289 /* make room to read at least 120 (more) characters */
3290 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291 break;
3292 buf = (char_u *)ga.ga_data;
3293
3294#ifdef USE_CR
3295 if (sp->fileformat == EOL_MAC)
3296 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003297 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3298 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299 break;
3300 }
3301 else
3302#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003303 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3304 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003305 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003306 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307#ifdef USE_CRNL
3308 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3309 * CTRL-Z by its own, or after a NL. */
3310 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3311 && sp->fileformat == EOL_DOS
3312 && buf[len - 1] == Ctrl_Z)
3313 {
3314 buf[len - 1] = NUL;
3315 break;
3316 }
3317#endif
3318
3319#ifdef USE_CR
3320 /* If the read doesn't stop on a new line, and there's
3321 * some CR then we assume a Mac format */
3322 if (sp->fileformat == EOL_UNKNOWN)
3323 {
3324 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3325 sp->fileformat = EOL_MAC;
3326 else
3327 sp->fileformat = EOL_UNIX;
3328 }
3329
3330 if (sp->fileformat == EOL_MAC)
3331 {
3332 scan = vim_strchr(buf, '\r');
3333
3334 if (scan != NULL)
3335 {
3336 *scan = '\n';
3337 if (*(scan + 1) != 0)
3338 {
3339 *(scan + 1) = 0;
3340 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3341 }
3342 }
3343 len = STRLEN(buf);
3344 }
3345#endif
3346
3347 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003348 ga.ga_len = len;
3349
3350 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003351 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352 continue;
3353
3354 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3355 {
3356#ifdef USE_CRNL
3357 has_cr = (len >= 2 && buf[len - 2] == '\r');
3358 if (sp->fileformat == EOL_UNKNOWN)
3359 {
3360 if (has_cr)
3361 sp->fileformat = EOL_DOS;
3362 else
3363 sp->fileformat = EOL_UNIX;
3364 }
3365
3366 if (sp->fileformat == EOL_DOS)
3367 {
3368 if (has_cr) /* replace trailing CR */
3369 {
3370 buf[len - 2] = '\n';
3371 --len;
3372 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373 }
3374 else /* lines like ":map xx yy^M" will have failed */
3375 {
3376 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003377 {
3378 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003380 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381 sp->error = TRUE;
3382 sp->fileformat = EOL_UNIX;
3383 }
3384 }
3385#endif
3386 /* The '\n' is escaped if there is an odd number of ^V's just
3387 * before it, first set "c" just before the 'V's and then check
3388 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3389 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3390 ;
3391 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3392 {
3393 sourcing_lnum++;
3394 continue;
3395 }
3396
3397 buf[len - 1] = NUL; /* remove the NL */
3398 }
3399
3400 /*
3401 * Check for ^C here now and then, so recursive :so can be broken.
3402 */
3403 line_breakcheck();
3404 break;
3405 }
3406
3407 if (have_read)
3408 return (char_u *)ga.ga_data;
3409
3410 vim_free(ga.ga_data);
3411 return NULL;
3412}
3413
Bram Moolenaar05159a02005-02-26 23:04:13 +00003414#if defined(FEAT_PROFILE) || defined(PROTO)
3415/*
3416 * Called when starting to read a script line.
3417 * "sourcing_lnum" must be correct!
3418 * When skipping lines it may not actually be executed, but we won't find out
3419 * until later and we need to store the time now.
3420 */
3421 void
3422script_line_start()
3423{
3424 scriptitem_T *si;
3425 sn_prl_T *pp;
3426
3427 if (current_SID <= 0 || current_SID > script_items.ga_len)
3428 return;
3429 si = &SCRIPT_ITEM(current_SID);
3430 if (si->sn_prof_on && sourcing_lnum >= 1)
3431 {
3432 /* Grow the array before starting the timer, so that the time spend
3433 * here isn't counted. */
3434 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3435 si->sn_prl_idx = sourcing_lnum - 1;
3436 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3437 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3438 {
3439 /* Zero counters for a line that was not used before. */
3440 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3441 pp->snp_count = 0;
3442 profile_zero(&pp->sn_prl_total);
3443 profile_zero(&pp->sn_prl_self);
3444 ++si->sn_prl_ga.ga_len;
3445 }
3446 si->sn_prl_execed = FALSE;
3447 profile_start(&si->sn_prl_start);
3448 profile_zero(&si->sn_prl_children);
3449 profile_get_wait(&si->sn_prl_wait);
3450 }
3451}
3452
3453/*
3454 * Called when actually executing a function line.
3455 */
3456 void
3457script_line_exec()
3458{
3459 scriptitem_T *si;
3460
3461 if (current_SID <= 0 || current_SID > script_items.ga_len)
3462 return;
3463 si = &SCRIPT_ITEM(current_SID);
3464 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3465 si->sn_prl_execed = TRUE;
3466}
3467
3468/*
3469 * Called when done with a function line.
3470 */
3471 void
3472script_line_end()
3473{
3474 scriptitem_T *si;
3475 sn_prl_T *pp;
3476
3477 if (current_SID <= 0 || current_SID > script_items.ga_len)
3478 return;
3479 si = &SCRIPT_ITEM(current_SID);
3480 if (si->sn_prof_on && si->sn_prl_idx >= 0
3481 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3482 {
3483 if (si->sn_prl_execed)
3484 {
3485 pp = &PRL_ITEM(si, si->sn_prl_idx);
3486 ++pp->snp_count;
3487 profile_end(&si->sn_prl_start);
3488 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
3489 profile_add(&pp->sn_prl_self, &si->sn_prl_start);
3490 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
3491 profile_sub(&pp->sn_prl_self, &si->sn_prl_children);
3492 }
3493 si->sn_prl_idx = -1;
3494 }
3495}
3496#endif
3497
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498/*
3499 * ":scriptencoding": Set encoding conversion for a sourced script.
3500 * Without the multi-byte feature it's simply ignored.
3501 */
3502/*ARGSUSED*/
3503 void
3504ex_scriptencoding(eap)
3505 exarg_T *eap;
3506{
3507#ifdef FEAT_MBYTE
3508 struct source_cookie *sp;
3509 char_u *name;
3510
3511 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3512 {
3513 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3514 return;
3515 }
3516
3517 if (*eap->arg != NUL)
3518 {
3519 name = enc_canonize(eap->arg);
3520 if (name == NULL) /* out of memory */
3521 return;
3522 }
3523 else
3524 name = eap->arg;
3525
3526 /* Setup for conversion from the specified encoding to 'encoding'. */
3527 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3528 convert_setup(&sp->conv, name, p_enc);
3529
3530 if (name != eap->arg)
3531 vim_free(name);
3532#endif
3533}
3534
3535#if defined(FEAT_EVAL) || defined(PROTO)
3536/*
3537 * ":finish": Mark a sourced file as finished.
3538 */
3539 void
3540ex_finish(eap)
3541 exarg_T *eap;
3542{
3543 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3544 do_finish(eap, FALSE);
3545 else
3546 EMSG(_("E168: :finish used outside of a sourced file"));
3547}
3548
3549/*
3550 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3551 * Also called for a pending finish at the ":endtry" or after returning from
3552 * an extra do_cmdline(). "reanimate" is used in the latter case.
3553 */
3554 void
3555do_finish(eap, reanimate)
3556 exarg_T *eap;
3557 int reanimate;
3558{
3559 int idx;
3560
3561 if (reanimate)
3562 ((struct source_cookie *)getline_cookie(eap->getline,
3563 eap->cookie))->finished = FALSE;
3564
3565 /*
3566 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3567 * not in its finally clause (which then is to be executed next) is found.
3568 * In this case, make the ":finish" pending for execution at the ":endtry".
3569 * Otherwise, finish normally.
3570 */
3571 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3572 if (idx >= 0)
3573 {
3574 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3575 report_make_pending(CSTP_FINISH, NULL);
3576 }
3577 else
3578 ((struct source_cookie *)getline_cookie(eap->getline,
3579 eap->cookie))->finished = TRUE;
3580}
3581
3582
3583/*
3584 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3585 * message for missing ":endif".
3586 * Return FALSE when not sourcing a file.
3587 */
3588 int
3589source_finished(getline, cookie)
3590 char_u *(*getline) __ARGS((int, void *, int));
3591 void *cookie;
3592{
3593 return (getline_equal(getline, cookie, getsourceline)
3594 && ((struct source_cookie *)getline_cookie(
3595 getline, cookie))->finished);
3596}
3597#endif
3598
3599#if defined(FEAT_LISTCMDS) || defined(PROTO)
3600/*
3601 * ":checktime [buffer]"
3602 */
3603 void
3604ex_checktime(eap)
3605 exarg_T *eap;
3606{
3607 buf_T *buf;
3608 int save_no_check_timestamps = no_check_timestamps;
3609
3610 no_check_timestamps = 0;
3611 if (eap->addr_count == 0) /* default is all buffers */
3612 check_timestamps(FALSE);
3613 else
3614 {
3615 buf = buflist_findnr((int)eap->line2);
3616 if (buf != NULL) /* cannot happen? */
3617 (void)buf_check_timestamp(buf, FALSE);
3618 }
3619 no_check_timestamps = save_no_check_timestamps;
3620}
3621#endif
3622
Bram Moolenaar071d4272004-06-13 20:20:40 +00003623#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3624 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3625static char *get_locale_val __ARGS((int what));
3626
3627 static char *
3628get_locale_val(what)
3629 int what;
3630{
3631 char *loc;
3632
3633 /* Obtain the locale value from the libraries. For DJGPP this is
3634 * redefined and it doesn't use the arguments. */
3635 loc = setlocale(what, NULL);
3636
3637# if defined(__BORLANDC__)
3638 if (loc != NULL)
3639 {
3640 char_u *p;
3641
3642 /* Borland returns something like "LC_CTYPE=<name>\n"
3643 * Let's try to fix that bug here... */
3644 p = vim_strchr(loc, '=');
3645 if (p != NULL)
3646 {
3647 loc = ++p;
3648 while (*p != NUL) /* remove trailing newline */
3649 {
3650 if (*p < ' ')
3651 {
3652 *p = NUL;
3653 break;
3654 }
3655 ++p;
3656 }
3657 }
3658 }
3659# endif
3660
3661 return loc;
3662}
3663#endif
3664
3665
3666#ifdef WIN32
3667/*
3668 * On MS-Windows locale names are strings like "German_Germany.1252", but
3669 * gettext expects "de". Try to translate one into another here for a few
3670 * supported languages.
3671 */
3672 static char_u *
3673gettext_lang(char_u *name)
3674{
3675 int i;
3676 static char *(mtable[]) = {
3677 "afrikaans", "af",
3678 "czech", "cs",
3679 "dutch", "nl",
3680 "german", "de",
3681 "english_united kingdom", "en_GB",
3682 "spanish", "es",
3683 "french", "fr",
3684 "italian", "it",
3685 "japanese", "ja",
3686 "korean", "ko",
3687 "norwegian", "no",
3688 "polish", "pl",
3689 "russian", "ru",
3690 "slovak", "sk",
3691 "swedish", "sv",
3692 "ukrainian", "uk",
3693 "chinese_china", "zh_CN",
3694 "chinese_taiwan", "zh_TW",
3695 NULL};
3696
3697 for (i = 0; mtable[i] != NULL; i += 2)
3698 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3699 return mtable[i + 1];
3700 return name;
3701}
3702#endif
3703
3704#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3705/*
3706 * Obtain the current messages language. Used to set the default for
3707 * 'helplang'. May return NULL or an empty string.
3708 */
3709 char_u *
3710get_mess_lang()
3711{
3712 char_u *p;
3713
3714# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3715# if defined(LC_MESSAGES)
3716 p = (char_u *)get_locale_val(LC_MESSAGES);
3717# else
3718 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
3719 * may be set to the LCID number. */
3720 p = (char_u *)get_locale_val(LC_ALL);
3721# endif
3722# else
3723 p = mch_getenv((char_u *)"LC_ALL");
3724 if (p == NULL || *p == NUL)
3725 {
3726 p = mch_getenv((char_u *)"LC_MESSAGES");
3727 if (p == NULL || *p == NUL)
3728 p = mch_getenv((char_u *)"LANG");
3729 }
3730# endif
3731# ifdef WIN32
3732 p = gettext_lang(p);
3733# endif
3734 return p;
3735}
3736#endif
3737
Bram Moolenaardef9e822004-12-31 20:58:58 +00003738/* Complicated #if; matches with where get_mess_env() is used below. */
3739#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3740 && defined(LC_MESSAGES))) \
3741 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3742 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3743 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003744static char_u *get_mess_env __ARGS((void));
3745
3746/*
3747 * Get the language used for messages from the environment.
3748 */
3749 static char_u *
3750get_mess_env()
3751{
3752 char_u *p;
3753
3754 p = mch_getenv((char_u *)"LC_ALL");
3755 if (p == NULL || *p == NUL)
3756 {
3757 p = mch_getenv((char_u *)"LC_MESSAGES");
3758 if (p == NULL || *p == NUL)
3759 {
3760 p = mch_getenv((char_u *)"LANG");
3761 if (p != NULL && VIM_ISDIGIT(*p))
3762 p = NULL; /* ignore something like "1043" */
3763# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3764 if (p == NULL || *p == NUL)
3765 p = (char_u *)get_locale_val(LC_CTYPE);
3766# endif
3767 }
3768 }
3769 return p;
3770}
3771#endif
3772
3773#if defined(FEAT_EVAL) || defined(PROTO)
3774
3775/*
3776 * Set the "v:lang" variable according to the current locale setting.
3777 * Also do "v:lc_time"and "v:ctype".
3778 */
3779 void
3780set_lang_var()
3781{
3782 char_u *loc;
3783
3784# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3785 loc = (char_u *)get_locale_val(LC_CTYPE);
3786# else
3787 /* setlocale() not supported: use the default value */
3788 loc = (char_u *)"C";
3789# endif
3790 set_vim_var_string(VV_CTYPE, loc, -1);
3791
3792 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3793 * back to LC_CTYPE if it's empty. */
3794# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
3795 loc = (char_u *)get_locale_val(LC_MESSAGES);
3796# else
3797 loc = get_mess_env();
3798# endif
3799 set_vim_var_string(VV_LANG, loc, -1);
3800
3801# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3802 loc = (char_u *)get_locale_val(LC_TIME);
3803# endif
3804 set_vim_var_string(VV_LC_TIME, loc, -1);
3805}
3806#endif
3807
3808#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3809 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
3810/*
3811 * ":language": Set the language (locale).
3812 */
3813 void
3814ex_language(eap)
3815 exarg_T *eap;
3816{
3817 char *loc;
3818 char_u *p;
3819 char_u *name;
3820 int what = LC_ALL;
3821 char *whatstr = "";
3822#ifdef LC_MESSAGES
3823# define VIM_LC_MESSAGES LC_MESSAGES
3824#else
3825# define VIM_LC_MESSAGES 6789
3826#endif
3827
3828 name = eap->arg;
3829
3830 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3831 * Allow abbreviation, but require at least 3 characters to avoid
3832 * confusion with a two letter language name "me" or "ct". */
3833 p = skiptowhite(eap->arg);
3834 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
3835 {
3836 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3837 {
3838 what = VIM_LC_MESSAGES;
3839 name = skipwhite(p);
3840 whatstr = "messages ";
3841 }
3842 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3843 {
3844 what = LC_CTYPE;
3845 name = skipwhite(p);
3846 whatstr = "ctype ";
3847 }
3848 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
3849 {
3850 what = LC_TIME;
3851 name = skipwhite(p);
3852 whatstr = "time ";
3853 }
3854 }
3855
3856 if (*name == NUL)
3857 {
3858#ifndef LC_MESSAGES
3859 if (what == VIM_LC_MESSAGES)
3860 p = get_mess_env();
3861 else
3862#endif
3863 p = (char_u *)setlocale(what, NULL);
3864 if (p == NULL || *p == NUL)
3865 p = (char_u *)"Unknown";
3866 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
3867 }
3868 else
3869 {
3870#ifndef LC_MESSAGES
3871 if (what == VIM_LC_MESSAGES)
3872 loc = "";
3873 else
3874#endif
3875 loc = setlocale(what, (char *)name);
3876 if (loc == NULL)
3877 EMSG2(_("E197: Cannot set language to \"%s\""), name);
3878 else
3879 {
3880#ifdef HAVE_NL_MSG_CAT_CNTR
3881 /* Need to do this for GNU gettext, otherwise cached translations
3882 * will be used again. */
3883 extern int _nl_msg_cat_cntr;
3884
3885 ++_nl_msg_cat_cntr;
3886#endif
3887 /* Reset $LC_ALL, otherwise it would overrule everyting. */
3888 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
3889
3890 if (what != LC_TIME)
3891 {
3892 /* Tell gettext() what to translate to. It apparently doesn't
3893 * use the currently effective locale. Also do this when
3894 * FEAT_GETTEXT isn't defined, so that shell commands use this
3895 * value. */
3896 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003897 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003899# ifdef WIN32
3900 /* Apparently MS-Windows printf() may cause a crash when
3901 * we give it 8-bit text while it's expecting text in the
3902 * current locale. This call avoids that. */
3903 setlocale(LC_CTYPE, "C");
3904# endif
3905 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906 if (what != LC_CTYPE)
3907 {
3908 char_u *mname;
3909#ifdef WIN32
3910 mname = gettext_lang(name);
3911#else
3912 mname = name;
3913#endif
3914 vim_setenv((char_u *)"LC_MESSAGES", mname);
3915#ifdef FEAT_MULTI_LANG
3916 set_helplang_default(mname);
3917#endif
3918 }
3919
3920 /* Set $LC_CTYPE, because it overrules $LANG, and
3921 * gtk_set_locale() calls setlocale() again. gnome_init()
3922 * sets $LC_CTYPE to "en_US" (that's a bug!). */
3923 if (what != VIM_LC_MESSAGES)
3924 vim_setenv((char_u *)"LC_CTYPE", name);
3925# ifdef FEAT_GUI_GTK
3926 /* Let GTK know what locale we're using. Not sure this is
3927 * really needed... */
3928 if (gui.in_use)
3929 (void)gtk_set_locale();
3930# endif
3931 }
3932
3933# ifdef FEAT_EVAL
3934 /* Set v:lang, v:lc_time and v:ctype to the final result. */
3935 set_lang_var();
3936# endif
3937 }
3938 }
3939}
3940
3941# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
3942/*
3943 * Function given to ExpandGeneric() to obtain the possible arguments of the
3944 * ":language" command.
3945 */
3946/*ARGSUSED*/
3947 char_u *
3948get_lang_arg(xp, idx)
3949 expand_T *xp;
3950 int idx;
3951{
3952 if (idx == 0)
3953 return (char_u *)"messages";
3954 if (idx == 1)
3955 return (char_u *)"ctype";
3956 if (idx == 2)
3957 return (char_u *)"time";
3958 return NULL;
3959}
3960# endif
3961
3962#endif