blob: c85f0b6a6215662c9a4d123c6d208c72d4149d1b [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)
Bram Moolenaar362e1a32006-03-06 23:29:24 +000015# include "vimio.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000016#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/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000914 * Add the "self" time from the total time and the children's time.
915 */
916 void
917profile_self(self, total, children)
918 proftime_T *self, *total, *children;
919{
920 /* Check that the result won't be negative. Can happen with recursive
921 * calls. */
922#ifdef WIN3264
923 if (total->QuadPart <= children->QuadPart)
924 return;
925#else
926 if (total->tv_sec < children->tv_sec
927 || (total->tv_sec == children->tv_sec
928 && total->tv_usec <= children->tv_usec))
929 return;
930#endif
931 profile_add(self, total);
932 profile_sub(self, children);
933}
934
935/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000936 * Get the current waittime.
937 */
938 void
939profile_get_wait(tm)
940 proftime_T *tm;
941{
942 *tm = prof_wait_time;
943}
944
945/*
946 * Subtract the passed waittime since "tm" from "tma".
947 */
948 void
949profile_sub_wait(tm, tma)
950 proftime_T *tm, *tma;
951{
952 proftime_T tm3 = prof_wait_time;
953
954 profile_sub(&tm3, tm);
955 profile_sub(tma, &tm3);
956}
957
958/*
959 * Return TRUE if "tm1" and "tm2" are equal.
960 */
961 int
962profile_equal(tm1, tm2)
963 proftime_T *tm1, *tm2;
964{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000965# ifdef WIN3264
966 return (tm1->QuadPart == tm2->QuadPart);
967# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000968 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000969# endif
970}
971
972/*
973 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
974 */
975 int
976profile_cmp(tm1, tm2)
977 proftime_T *tm1, *tm2;
978{
979# ifdef WIN3264
980 return (int)(tm2->QuadPart - tm1->QuadPart);
981# else
982 if (tm1->tv_sec == tm2->tv_sec)
983 return tm2->tv_usec - tm1->tv_usec;
984 return tm2->tv_sec - tm1->tv_sec;
985# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000986}
987
988/*
989 * Return a string that represents a time.
990 * Uses a static buffer!
991 */
992 char *
993profile_msg(tm)
994 proftime_T *tm;
995{
996 static char buf[50];
997
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000998# ifdef WIN3264
999 LARGE_INTEGER fr;
1000
1001 QueryPerformanceFrequency(&fr);
1002 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1003# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001004 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001005#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001006 return buf;
1007}
1008
1009static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001010static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001011
1012/*
1013 * ":profile cmd args"
1014 */
1015 void
1016ex_profile(eap)
1017 exarg_T *eap;
1018{
1019 char_u *e;
1020 int len;
1021
1022 e = skiptowhite(eap->arg);
1023 len = e - eap->arg;
1024 e = skipwhite(e);
1025
1026 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1027 {
1028 vim_free(profile_fname);
1029 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001030 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001031 profile_zero(&prof_wait_time);
1032 set_vim_var_nr(VV_PROFILING, 1L);
1033 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001034 else if (do_profiling == PROF_NONE)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001035 EMSG(_("E750: First use :profile start <fname>"));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001036 else if (STRCMP(eap->arg, "pause") == 0)
1037 {
1038 if (do_profiling == PROF_YES)
1039 profile_start(&pause_time);
1040 do_profiling = PROF_PAUSED;
1041 }
1042 else if (STRCMP(eap->arg, "continue") == 0)
1043 {
1044 if (do_profiling == PROF_PAUSED)
1045 {
1046 profile_end(&pause_time);
1047 profile_add(&prof_wait_time, &pause_time);
1048 }
1049 do_profiling = PROF_YES;
1050 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001051 else
1052 {
1053 /* The rest is similar to ":breakadd". */
1054 ex_breakadd(eap);
1055 }
1056}
1057
1058/*
1059 * Dump the profiling info.
1060 */
1061 void
1062profile_dump()
1063{
1064 FILE *fd;
1065
1066 if (profile_fname != NULL)
1067 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001068 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001069 if (fd == NULL)
1070 EMSG2(_(e_notopen), profile_fname);
1071 else
1072 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001073 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001074 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001075 fclose(fd);
1076 }
1077 }
1078}
1079
1080/*
1081 * Start profiling script "fp".
1082 */
1083 static void
1084script_do_profile(si)
1085 scriptitem_T *si;
1086{
1087 si->sn_pr_count = 0;
1088 profile_zero(&si->sn_pr_total);
1089 profile_zero(&si->sn_pr_self);
1090
1091 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1092 si->sn_prl_idx = -1;
1093 si->sn_prof_on = TRUE;
1094 si->sn_pr_nest = 0;
1095}
1096
1097/*
1098 * save time when starting to invoke another script or function.
1099 */
1100 void
1101script_prof_save(tm)
1102 proftime_T *tm; /* place to store wait time */
1103{
1104 scriptitem_T *si;
1105
1106 if (current_SID > 0 && current_SID <= script_items.ga_len)
1107 {
1108 si = &SCRIPT_ITEM(current_SID);
1109 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1110 profile_start(&si->sn_pr_child);
1111 }
1112 profile_get_wait(tm);
1113}
1114
1115/*
1116 * Count time spent in children after invoking another script or function.
1117 */
1118 void
1119script_prof_restore(tm)
1120 proftime_T *tm;
1121{
1122 scriptitem_T *si;
1123
1124 if (current_SID > 0 && current_SID <= script_items.ga_len)
1125 {
1126 si = &SCRIPT_ITEM(current_SID);
1127 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1128 {
1129 profile_end(&si->sn_pr_child);
1130 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1131 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1132 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1133 }
1134 }
1135}
1136
1137static proftime_T inchar_time;
1138
1139/*
1140 * Called when starting to wait for the user to type a character.
1141 */
1142 void
1143prof_inchar_enter()
1144{
1145 profile_start(&inchar_time);
1146}
1147
1148/*
1149 * Called when finished waiting for the user to type a character.
1150 */
1151 void
1152prof_inchar_exit()
1153{
1154 profile_end(&inchar_time);
1155 profile_add(&prof_wait_time, &inchar_time);
1156}
1157
1158/*
1159 * Dump the profiling results for all scripts in file "fd".
1160 */
1161 static void
1162script_dump_profile(fd)
1163 FILE *fd;
1164{
1165 int id;
1166 scriptitem_T *si;
1167 int i;
1168 FILE *sfd;
1169 sn_prl_T *pp;
1170
1171 for (id = 1; id <= script_items.ga_len; ++id)
1172 {
1173 si = &SCRIPT_ITEM(id);
1174 if (si->sn_prof_on)
1175 {
1176 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1177 if (si->sn_pr_count == 1)
1178 fprintf(fd, "Sourced 1 time\n");
1179 else
1180 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1181 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1182 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1183 fprintf(fd, "\n");
1184 fprintf(fd, "count total (s) self (s)\n");
1185
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001186 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001187 if (sfd == NULL)
1188 fprintf(fd, "Cannot open file!\n");
1189 else
1190 {
1191 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1192 {
1193 if (vim_fgets(IObuff, IOSIZE, sfd))
1194 break;
1195 pp = &PRL_ITEM(si, i);
1196 if (pp->snp_count > 0)
1197 {
1198 fprintf(fd, "%5d ", pp->snp_count);
1199 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1200 fprintf(fd, " ");
1201 else
1202 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1203 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1204 }
1205 else
1206 fprintf(fd, " ");
1207 fprintf(fd, "%s", IObuff);
1208 }
1209 fclose(sfd);
1210 }
1211 fprintf(fd, "\n");
1212 }
1213 }
1214}
1215
1216/*
1217 * Return TRUE when a function defined in the current script should be
1218 * profiled.
1219 */
1220 int
1221prof_def_func()
1222{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001223 if (current_SID > 0)
1224 return SCRIPT_ITEM(current_SID).sn_pr_force;
1225 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001226}
1227
1228# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229#endif
1230
1231/*
1232 * If 'autowrite' option set, try to write the file.
1233 * Careful: autocommands may make "buf" invalid!
1234 *
1235 * return FAIL for failure, OK otherwise
1236 */
1237 int
1238autowrite(buf, forceit)
1239 buf_T *buf;
1240 int forceit;
1241{
1242 if (!(p_aw || p_awa) || !p_write
1243#ifdef FEAT_QUICKFIX
1244 /* never autowrite a "nofile" or "nowrite" buffer */
1245 || bt_dontwrite(buf)
1246#endif
1247 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
1248 return FAIL;
1249 return buf_write_all(buf, forceit);
1250}
1251
1252/*
1253 * flush all buffers, except the ones that are readonly
1254 */
1255 void
1256autowrite_all()
1257{
1258 buf_T *buf;
1259
1260 if (!(p_aw || p_awa) || !p_write)
1261 return;
1262 for (buf = firstbuf; buf; buf = buf->b_next)
1263 if (bufIsChanged(buf) && !buf->b_p_ro)
1264 {
1265 (void)buf_write_all(buf, FALSE);
1266#ifdef FEAT_AUTOCMD
1267 /* an autocommand may have deleted the buffer */
1268 if (!buf_valid(buf))
1269 buf = firstbuf;
1270#endif
1271 }
1272}
1273
1274/*
1275 * return TRUE if buffer was changed and cannot be abandoned.
1276 */
1277/*ARGSUSED*/
1278 int
1279check_changed(buf, checkaw, mult_win, forceit, allbuf)
1280 buf_T *buf;
1281 int checkaw; /* do autowrite if buffer was changed */
1282 int mult_win; /* check also when several wins for the buf */
1283 int forceit;
1284 int allbuf; /* may write all buffers */
1285{
1286 if ( !forceit
1287 && bufIsChanged(buf)
1288 && (mult_win || buf->b_nwindows <= 1)
1289 && (!checkaw || autowrite(buf, forceit) == FAIL))
1290 {
1291#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1292 if ((p_confirm || cmdmod.confirm) && p_write)
1293 {
1294 buf_T *buf2;
1295 int count = 0;
1296
1297 if (allbuf)
1298 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1299 if (bufIsChanged(buf2)
1300 && (buf2->b_ffname != NULL
1301# ifdef FEAT_BROWSE
1302 || cmdmod.browse
1303# endif
1304 ))
1305 ++count;
1306# ifdef FEAT_AUTOCMD
1307 if (!buf_valid(buf))
1308 /* Autocommand deleted buffer, oops! It's not changed now. */
1309 return FALSE;
1310# endif
1311 dialog_changed(buf, count > 1);
1312# ifdef FEAT_AUTOCMD
1313 if (!buf_valid(buf))
1314 /* Autocommand deleted buffer, oops! It's not changed now. */
1315 return FALSE;
1316# endif
1317 return bufIsChanged(buf);
1318 }
1319#endif
1320 EMSG(_(e_nowrtmsg));
1321 return TRUE;
1322 }
1323 return FALSE;
1324}
1325
1326#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1327
1328#if defined(FEAT_BROWSE) || defined(PROTO)
1329/*
1330 * When wanting to write a file without a file name, ask the user for a name.
1331 */
1332 void
1333browse_save_fname(buf)
1334 buf_T *buf;
1335{
1336 if (buf->b_fname == NULL)
1337 {
1338 char_u *fname;
1339
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001340 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1341 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001342 if (fname != NULL)
1343 {
1344 if (setfname(buf, fname, NULL, TRUE) == OK)
1345 buf->b_flags |= BF_NOTEDITED;
1346 vim_free(fname);
1347 }
1348 }
1349}
1350#endif
1351
1352/*
1353 * Ask the user what to do when abondoning a changed buffer.
1354 * Must check 'write' option first!
1355 */
1356 void
1357dialog_changed(buf, checkall)
1358 buf_T *buf;
1359 int checkall; /* may abandon all changed buffers */
1360{
1361 char_u buff[IOSIZE];
1362 int ret;
1363 buf_T *buf2;
1364
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001365 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001366 (buf->b_fname != NULL) ?
1367 buf->b_fname : (char_u *)_("Untitled"));
1368 if (checkall)
1369 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1370 else
1371 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1372
1373 if (ret == VIM_YES)
1374 {
1375#ifdef FEAT_BROWSE
1376 /* May get file name, when there is none */
1377 browse_save_fname(buf);
1378#endif
1379 if (buf->b_fname != NULL) /* didn't hit Cancel */
1380 (void)buf_write_all(buf, FALSE);
1381 }
1382 else if (ret == VIM_NO)
1383 {
1384 unchanged(buf, TRUE);
1385 }
1386 else if (ret == VIM_ALL)
1387 {
1388 /*
1389 * Write all modified files that can be written.
1390 * Skip readonly buffers, these need to be confirmed
1391 * individually.
1392 */
1393 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1394 {
1395 if (bufIsChanged(buf2)
1396 && (buf2->b_ffname != NULL
1397#ifdef FEAT_BROWSE
1398 || cmdmod.browse
1399#endif
1400 )
1401 && !buf2->b_p_ro)
1402 {
1403#ifdef FEAT_BROWSE
1404 /* May get file name, when there is none */
1405 browse_save_fname(buf2);
1406#endif
1407 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1408 (void)buf_write_all(buf2, FALSE);
1409#ifdef FEAT_AUTOCMD
1410 /* an autocommand may have deleted the buffer */
1411 if (!buf_valid(buf2))
1412 buf2 = firstbuf;
1413#endif
1414 }
1415 }
1416 }
1417 else if (ret == VIM_DISCARDALL)
1418 {
1419 /*
1420 * mark all buffers as unchanged
1421 */
1422 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1423 unchanged(buf2, TRUE);
1424 }
1425}
1426#endif
1427
1428/*
1429 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1430 * hidden, autowriting it or unloading it.
1431 */
1432 int
1433can_abandon(buf, forceit)
1434 buf_T *buf;
1435 int forceit;
1436{
1437 return ( P_HID(buf)
1438 || !bufIsChanged(buf)
1439 || buf->b_nwindows > 1
1440 || autowrite(buf, forceit) == OK
1441 || forceit);
1442}
1443
1444/*
1445 * Return TRUE if any buffer was changed and cannot be abandoned.
1446 * That changed buffer becomes the current buffer.
1447 */
1448 int
1449check_changed_any(hidden)
1450 int hidden; /* Only check hidden buffers */
1451{
1452 buf_T *buf;
1453 int save;
1454#ifdef FEAT_WINDOWS
1455 win_T *wp;
1456#endif
1457
1458 for (;;)
1459 {
1460 /* check curbuf first: if it was changed we can't abandon it */
1461 if (!hidden && curbufIsChanged())
1462 buf = curbuf;
1463 else
1464 {
1465 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1466 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1467 break;
1468 }
1469 if (buf == NULL) /* No buffers changed */
1470 return FALSE;
1471
1472 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1473 break; /* didn't save - still changes */
1474 }
1475
1476 exiting = FALSE;
1477#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1478 /*
1479 * When ":confirm" used, don't give an error message.
1480 */
1481 if (!(p_confirm || cmdmod.confirm))
1482#endif
1483 {
1484 /* There must be a wait_return for this message, do_buffer()
1485 * may cause a redraw. But wait_return() is a no-op when vgetc()
1486 * is busy (Quit used from window menu), then make sure we don't
1487 * cause a scroll up. */
1488 if (vgetc_busy)
1489 {
1490 msg_row = cmdline_row;
1491 msg_col = 0;
1492 msg_didout = FALSE;
1493 }
1494 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1495 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1496 buf->b_fname))
1497 {
1498 save = no_wait_return;
1499 no_wait_return = FALSE;
1500 wait_return(FALSE);
1501 no_wait_return = save;
1502 }
1503 }
1504
1505#ifdef FEAT_WINDOWS
1506 /* Try to find a window that contains the buffer. */
1507 if (buf != curbuf)
1508 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1509 if (wp->w_buffer == buf)
1510 {
1511 win_goto(wp);
1512# ifdef FEAT_AUTOCMD
1513 /* Paranoia: did autocms wipe out the buffer with changes? */
1514 if (!buf_valid(buf))
1515 return TRUE;
1516# endif
1517 break;
1518 }
1519#endif
1520
1521 /* Open the changed buffer in the current window. */
1522 if (buf != curbuf)
1523 set_curbuf(buf, DOBUF_GOTO);
1524
1525 return TRUE;
1526}
1527
1528/*
1529 * return FAIL if there is no file name, OK if there is one
1530 * give error message for FAIL
1531 */
1532 int
1533check_fname()
1534{
1535 if (curbuf->b_ffname == NULL)
1536 {
1537 EMSG(_(e_noname));
1538 return FAIL;
1539 }
1540 return OK;
1541}
1542
1543/*
1544 * flush the contents of a buffer, unless it has no file name
1545 *
1546 * return FAIL for failure, OK otherwise
1547 */
1548 int
1549buf_write_all(buf, forceit)
1550 buf_T *buf;
1551 int forceit;
1552{
1553 int retval;
1554#ifdef FEAT_AUTOCMD
1555 buf_T *old_curbuf = curbuf;
1556#endif
1557
1558 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1559 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1560 FALSE, forceit, TRUE, FALSE));
1561#ifdef FEAT_AUTOCMD
1562 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001563 {
1564 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001566 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001567#endif
1568 return retval;
1569}
1570
1571/*
1572 * Code to handle the argument list.
1573 */
1574
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001575static char_u *do_one_arg __ARGS((char_u *str));
1576static int do_arglist __ARGS((char_u *str, int what, int after));
1577static void alist_check_arg_idx __ARGS((void));
1578static int editing_arg_idx __ARGS((win_T *win));
1579#ifdef FEAT_LISTCMDS
1580static int alist_add_list __ARGS((int count, char_u **files, int after));
1581#endif
1582#define AL_SET 1
1583#define AL_ADD 2
1584#define AL_DEL 3
1585
Bram Moolenaar071d4272004-06-13 20:20:40 +00001586/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001587 * Isolate one argument, taking backticks.
1588 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589 * Return a pointer to the start of the next argument.
1590 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001591 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001592do_one_arg(str)
1593 char_u *str;
1594{
1595 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596 int inbacktick;
1597
Bram Moolenaar071d4272004-06-13 20:20:40 +00001598 inbacktick = FALSE;
1599 for (p = str; *str; ++str)
1600 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001601 /* When the backslash is used for escaping the special meaning of a
1602 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001603 if (rem_backslash(str))
1604 {
1605 *p++ = *str++;
1606 *p++ = *str;
1607 }
1608 else
1609 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001610 /* An item ends at a space not in backticks */
1611 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001612 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001613 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001615 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 }
1617 }
1618 str = skipwhite(str);
1619 *p = NUL;
1620
1621 return str;
1622}
1623
Bram Moolenaar86b68352004-12-27 21:59:20 +00001624/*
1625 * Separate the arguments in "str" and return a list of pointers in the
1626 * growarray "gap".
1627 */
1628 int
1629get_arglist(gap, str)
1630 garray_T *gap;
1631 char_u *str;
1632{
1633 ga_init2(gap, (int)sizeof(char_u *), 20);
1634 while (*str != NUL)
1635 {
1636 if (ga_grow(gap, 1) == FAIL)
1637 {
1638 ga_clear(gap);
1639 return FAIL;
1640 }
1641 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1642
1643 /* Isolate one argument, change it in-place, put a NUL after it. */
1644 str = do_one_arg(str);
1645 }
1646 return OK;
1647}
1648
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001649#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001650/*
1651 * Parse a list of arguments (file names), expand them and return in
1652 * "fnames[fcountp]".
1653 * Return FAIL or OK.
1654 */
1655 int
1656get_arglist_exp(str, fcountp, fnamesp)
1657 char_u *str;
1658 int *fcountp;
1659 char_u ***fnamesp;
1660{
1661 garray_T ga;
1662 int i;
1663
1664 if (get_arglist(&ga, str) == FAIL)
1665 return FAIL;
1666 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1667 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1668 ga_clear(&ga);
1669 return i;
1670}
1671#endif
1672
Bram Moolenaar071d4272004-06-13 20:20:40 +00001673#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1674/*
1675 * Redefine the argument list.
1676 */
1677 void
1678set_arglist(str)
1679 char_u *str;
1680{
1681 do_arglist(str, AL_SET, 0);
1682}
1683#endif
1684
1685/*
1686 * "what" == AL_SET: Redefine the argument list to 'str'.
1687 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1688 * "what" == AL_DEL: remove files in 'str' from the argument list.
1689 *
1690 * Return FAIL for failure, OK otherwise.
1691 */
1692/*ARGSUSED*/
1693 static int
1694do_arglist(str, what, after)
1695 char_u *str;
1696 int what;
1697 int after; /* 0 means before first one */
1698{
1699 garray_T new_ga;
1700 int exp_count;
1701 char_u **exp_files;
1702 int i;
1703#ifdef FEAT_LISTCMDS
1704 char_u *p;
1705 int match;
1706#endif
1707
1708 /*
1709 * Collect all file name arguments in "new_ga".
1710 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001711 if (get_arglist(&new_ga, str) == FAIL)
1712 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001713
1714#ifdef FEAT_LISTCMDS
1715 if (what == AL_DEL)
1716 {
1717 regmatch_T regmatch;
1718 int didone;
1719
1720 /*
1721 * Delete the items: use each item as a regexp and find a match in the
1722 * argument list.
1723 */
1724#ifdef CASE_INSENSITIVE_FILENAME
1725 regmatch.rm_ic = TRUE; /* Always ignore case */
1726#else
1727 regmatch.rm_ic = FALSE; /* Never ignore case */
1728#endif
1729 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1730 {
1731 p = ((char_u **)new_ga.ga_data)[i];
1732 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1733 if (p == NULL)
1734 break;
1735 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1736 if (regmatch.regprog == NULL)
1737 {
1738 vim_free(p);
1739 break;
1740 }
1741
1742 didone = FALSE;
1743 for (match = 0; match < ARGCOUNT; ++match)
1744 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1745 (colnr_T)0))
1746 {
1747 didone = TRUE;
1748 vim_free(ARGLIST[match].ae_fname);
1749 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1750 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1751 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752 if (curwin->w_arg_idx > match)
1753 --curwin->w_arg_idx;
1754 --match;
1755 }
1756
1757 vim_free(regmatch.regprog);
1758 vim_free(p);
1759 if (!didone)
1760 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1761 }
1762 ga_clear(&new_ga);
1763 }
1764 else
1765#endif
1766 {
1767 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1768 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1769 ga_clear(&new_ga);
1770 if (i == FAIL)
1771 return FAIL;
1772 if (exp_count == 0)
1773 {
1774 EMSG(_(e_nomatch));
1775 return FAIL;
1776 }
1777
1778#ifdef FEAT_LISTCMDS
1779 if (what == AL_ADD)
1780 {
1781 (void)alist_add_list(exp_count, exp_files, after);
1782 vim_free(exp_files);
1783 }
1784 else /* what == AL_SET */
1785#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00001786 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001787 }
1788
1789 alist_check_arg_idx();
1790
1791 return OK;
1792}
1793
1794/*
1795 * Check the validity of the arg_idx for each other window.
1796 */
1797 static void
1798alist_check_arg_idx()
1799{
1800#ifdef FEAT_WINDOWS
1801 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001802 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803
Bram Moolenaarf740b292006-02-16 22:11:02 +00001804 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001805 if (win->w_alist == curwin->w_alist)
1806 check_arg_idx(win);
1807#else
1808 check_arg_idx(curwin);
1809#endif
1810}
1811
1812/*
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001813 * Return TRUE if window "win" is editing then file at the current argument
1814 * index.
1815 */
1816 static int
1817editing_arg_idx(win)
1818 win_T *win;
1819{
1820 return !(win->w_arg_idx >= WARGCOUNT(win)
1821 || (win->w_buffer->b_fnum
1822 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1823 && (win->w_buffer->b_ffname == NULL
1824 || !(fullpathcmp(
1825 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1826 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1827}
1828
1829/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001830 * Check if window "win" is editing the w_arg_idx file in its argument list.
1831 */
1832 void
1833check_arg_idx(win)
1834 win_T *win;
1835{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001836 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001837 {
1838 /* We are not editing the current entry in the argument list.
1839 * Set "arg_had_last" if we are editing the last one. */
1840 win->w_arg_idx_invalid = TRUE;
1841 if (win->w_arg_idx != WARGCOUNT(win) - 1
1842 && arg_had_last == FALSE
1843#ifdef FEAT_WINDOWS
1844 && ALIST(win) == &global_alist
1845#endif
1846 && GARGCOUNT > 0
1847 && win->w_arg_idx < GARGCOUNT
1848 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1849 || (win->w_buffer->b_ffname != NULL
1850 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1851 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1852 arg_had_last = TRUE;
1853 }
1854 else
1855 {
1856 /* We are editing the current entry in the argument list.
1857 * Set "arg_had_last" if it's also the last one */
1858 win->w_arg_idx_invalid = FALSE;
1859 if (win->w_arg_idx == WARGCOUNT(win) - 1
1860#ifdef FEAT_WINDOWS
1861 && win->w_alist == &global_alist
1862#endif
1863 )
1864 arg_had_last = TRUE;
1865 }
1866}
1867
1868/*
1869 * ":args", ":argslocal" and ":argsglobal".
1870 */
1871 void
1872ex_args(eap)
1873 exarg_T *eap;
1874{
1875 int i;
1876
1877 if (eap->cmdidx != CMD_args)
1878 {
1879#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1880 alist_unlink(ALIST(curwin));
1881 if (eap->cmdidx == CMD_argglobal)
1882 ALIST(curwin) = &global_alist;
1883 else /* eap->cmdidx == CMD_arglocal */
1884 alist_new();
1885#else
1886 ex_ni(eap);
1887 return;
1888#endif
1889 }
1890
1891 if (!ends_excmd(*eap->arg))
1892 {
1893 /*
1894 * ":args file ..": define new argument list, handle like ":next"
1895 * Also for ":argslocal file .." and ":argsglobal file ..".
1896 */
1897 ex_next(eap);
1898 }
1899 else
1900#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1901 if (eap->cmdidx == CMD_args)
1902#endif
1903 {
1904 /*
1905 * ":args": list arguments.
1906 */
1907 if (ARGCOUNT > 0)
1908 {
1909 /* Overwrite the command, for a short list there is no scrolling
1910 * required and no wait_return(). */
1911 gotocmdline(TRUE);
1912 for (i = 0; i < ARGCOUNT; ++i)
1913 {
1914 if (i == curwin->w_arg_idx)
1915 msg_putchar('[');
1916 msg_outtrans(alist_name(&ARGLIST[i]));
1917 if (i == curwin->w_arg_idx)
1918 msg_putchar(']');
1919 msg_putchar(' ');
1920 }
1921 }
1922 }
1923#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1924 else if (eap->cmdidx == CMD_arglocal)
1925 {
1926 garray_T *gap = &curwin->w_alist->al_ga;
1927
1928 /*
1929 * ":argslocal": make a local copy of the global argument list.
1930 */
1931 if (ga_grow(gap, GARGCOUNT) == OK)
1932 for (i = 0; i < GARGCOUNT; ++i)
1933 if (GARGLIST[i].ae_fname != NULL)
1934 {
1935 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1936 vim_strsave(GARGLIST[i].ae_fname);
1937 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1938 GARGLIST[i].ae_fnum;
1939 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 }
1941 }
1942#endif
1943}
1944
1945/*
1946 * ":previous", ":sprevious", ":Next" and ":sNext".
1947 */
1948 void
1949ex_previous(eap)
1950 exarg_T *eap;
1951{
1952 /* If past the last one already, go to the last one. */
1953 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1954 do_argfile(eap, ARGCOUNT - 1);
1955 else
1956 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1957}
1958
1959/*
1960 * ":rewind", ":first", ":sfirst" and ":srewind".
1961 */
1962 void
1963ex_rewind(eap)
1964 exarg_T *eap;
1965{
1966 do_argfile(eap, 0);
1967}
1968
1969/*
1970 * ":last" and ":slast".
1971 */
1972 void
1973ex_last(eap)
1974 exarg_T *eap;
1975{
1976 do_argfile(eap, ARGCOUNT - 1);
1977}
1978
1979/*
1980 * ":argument" and ":sargument".
1981 */
1982 void
1983ex_argument(eap)
1984 exarg_T *eap;
1985{
1986 int i;
1987
1988 if (eap->addr_count > 0)
1989 i = eap->line2 - 1;
1990 else
1991 i = curwin->w_arg_idx;
1992 do_argfile(eap, i);
1993}
1994
1995/*
1996 * Edit file "argn" of the argument lists.
1997 */
1998 void
1999do_argfile(eap, argn)
2000 exarg_T *eap;
2001 int argn;
2002{
2003 int other;
2004 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002005 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002006
2007 if (argn < 0 || argn >= ARGCOUNT)
2008 {
2009 if (ARGCOUNT <= 1)
2010 EMSG(_("E163: There is only one file to edit"));
2011 else if (argn < 0)
2012 EMSG(_("E164: Cannot go before first file"));
2013 else
2014 EMSG(_("E165: Cannot go beyond last file"));
2015 }
2016 else
2017 {
2018 setpcmark();
2019#ifdef FEAT_GUI
2020 need_mouse_correct = TRUE;
2021#endif
2022
2023#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002024 /* split window or create new tab page first */
2025 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026 {
2027 if (win_split(0, 0) == FAIL)
2028 return;
2029# ifdef FEAT_SCROLLBIND
2030 curwin->w_p_scb = FALSE;
2031# endif
2032 }
2033 else
2034#endif
2035 {
2036 /*
2037 * if 'hidden' set, only check for changed file when re-editing
2038 * the same buffer
2039 */
2040 other = TRUE;
2041 if (P_HID(curbuf))
2042 {
2043 p = fix_fname(alist_name(&ARGLIST[argn]));
2044 other = otherfile(p);
2045 vim_free(p);
2046 }
2047 if ((!P_HID(curbuf) || !other)
2048 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2049 return;
2050 }
2051
2052 curwin->w_arg_idx = argn;
2053 if (argn == ARGCOUNT - 1
2054#ifdef FEAT_WINDOWS
2055 && curwin->w_alist == &global_alist
2056#endif
2057 )
2058 arg_had_last = TRUE;
2059
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002060 /* Edit the file; always use the last known line number.
2061 * When it fails (e.g. Abort for already edited file) restore the
2062 * argument index. */
2063 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002064 eap, ECMD_LAST,
2065 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) +
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002066 (eap->forceit ? ECMD_FORCEIT : 0)) == FAIL)
2067 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002069 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002070 setmark('\'');
2071 }
2072}
2073
2074/*
2075 * ":next", and commands that behave like it.
2076 */
2077 void
2078ex_next(eap)
2079 exarg_T *eap;
2080{
2081 int i;
2082
2083 /*
2084 * check for changed buffer now, if this fails the argument list is not
2085 * redefined.
2086 */
2087 if ( P_HID(curbuf)
2088 || eap->cmdidx == CMD_snext
2089 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2090 {
2091 if (*eap->arg != NUL) /* redefine file list */
2092 {
2093 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2094 return;
2095 i = 0;
2096 }
2097 else
2098 i = curwin->w_arg_idx + (int)eap->line2;
2099 do_argfile(eap, i);
2100 }
2101}
2102
2103#ifdef FEAT_LISTCMDS
2104/*
2105 * ":argedit"
2106 */
2107 void
2108ex_argedit(eap)
2109 exarg_T *eap;
2110{
2111 int fnum;
2112 int i;
2113 char_u *s;
2114
2115 /* Add the argument to the buffer list and get the buffer number. */
2116 fnum = buflist_add(eap->arg, BLN_LISTED);
2117
2118 /* Check if this argument is already in the argument list. */
2119 for (i = 0; i < ARGCOUNT; ++i)
2120 if (ARGLIST[i].ae_fnum == fnum)
2121 break;
2122 if (i == ARGCOUNT)
2123 {
2124 /* Can't find it, add it to the argument list. */
2125 s = vim_strsave(eap->arg);
2126 if (s == NULL)
2127 return;
2128 i = alist_add_list(1, &s,
2129 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2130 if (i < 0)
2131 return;
2132 curwin->w_arg_idx = i;
2133 }
2134
2135 alist_check_arg_idx();
2136
2137 /* Edit the argument. */
2138 do_argfile(eap, i);
2139}
2140
2141/*
2142 * ":argadd"
2143 */
2144 void
2145ex_argadd(eap)
2146 exarg_T *eap;
2147{
2148 do_arglist(eap->arg, AL_ADD,
2149 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2150#ifdef FEAT_TITLE
2151 maketitle();
2152#endif
2153}
2154
2155/*
2156 * ":argdelete"
2157 */
2158 void
2159ex_argdelete(eap)
2160 exarg_T *eap;
2161{
2162 int i;
2163 int n;
2164
2165 if (eap->addr_count > 0)
2166 {
2167 /* ":1,4argdel": Delete all arguments in the range. */
2168 if (eap->line2 > ARGCOUNT)
2169 eap->line2 = ARGCOUNT;
2170 n = eap->line2 - eap->line1 + 1;
2171 if (*eap->arg != NUL || n <= 0)
2172 EMSG(_(e_invarg));
2173 else
2174 {
2175 for (i = eap->line1; i <= eap->line2; ++i)
2176 vim_free(ARGLIST[i - 1].ae_fname);
2177 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2178 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2179 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180 if (curwin->w_arg_idx >= eap->line2)
2181 curwin->w_arg_idx -= n;
2182 else if (curwin->w_arg_idx > eap->line1)
2183 curwin->w_arg_idx = eap->line1;
2184 }
2185 }
2186 else if (*eap->arg == NUL)
2187 EMSG(_(e_argreq));
2188 else
2189 do_arglist(eap->arg, AL_DEL, 0);
2190#ifdef FEAT_TITLE
2191 maketitle();
2192#endif
2193}
2194
2195/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002196 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002197 */
2198 void
2199ex_listdo(eap)
2200 exarg_T *eap;
2201{
2202 int i;
2203#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002204 win_T *wp;
2205 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002206#endif
2207 buf_T *buf;
2208 int next_fnum = 0;
2209#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2210 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002212 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002213
2214#ifndef FEAT_WINDOWS
2215 if (eap->cmdidx == CMD_windo)
2216 {
2217 ex_ni(eap);
2218 return;
2219 }
2220#endif
2221
2222#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2223 if (eap->cmdidx != CMD_windo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002224 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2225 * great speed improvement. */
2226 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227#endif
2228
2229 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002230 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002231 || P_HID(curbuf)
2232 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2233 {
2234 /* start at the first argument/window/buffer */
2235 i = 0;
2236#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002237 wp = firstwin;
2238 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002239#endif
2240 /* set pcmark now */
2241 if (eap->cmdidx == CMD_bufdo)
2242 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2243 else
2244 setpcmark();
2245 listcmd_busy = TRUE; /* avoids setting pcmark below */
2246
2247 while (!got_int)
2248 {
2249 if (eap->cmdidx == CMD_argdo)
2250 {
2251 /* go to argument "i" */
2252 if (i == ARGCOUNT)
2253 break;
2254 /* Don't call do_argfile() when already there, it will try
2255 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002256 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002257 {
2258 /* Clear 'shm' to avoid that the file message overwrites
2259 * any output from the command. */
2260 p_shm_save = vim_strsave(p_shm);
2261 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002263 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2264 vim_free(p_shm_save);
2265 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 if (curwin->w_arg_idx != i)
2267 break;
2268 ++i;
2269 }
2270#ifdef FEAT_WINDOWS
2271 else if (eap->cmdidx == CMD_windo)
2272 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002273 /* go to window "wp" */
2274 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002275 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002276 win_goto(wp);
2277 wp = curwin->w_next;
2278 }
2279 else if (eap->cmdidx == CMD_tabdo)
2280 {
2281 /* go to window "tp" */
2282 if (!valid_tabpage(tp))
2283 break;
2284 goto_tabpage_tp(tp);
2285 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 }
2287#endif
2288 else if (eap->cmdidx == CMD_bufdo)
2289 {
2290 /* Remember the number of the next listed buffer, in case
2291 * ":bwipe" is used or autocommands do something strange. */
2292 next_fnum = -1;
2293 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2294 if (buf->b_p_bl)
2295 {
2296 next_fnum = buf->b_fnum;
2297 break;
2298 }
2299 }
2300
2301 /* execute the command */
2302 do_cmdline(eap->arg, eap->getline, eap->cookie,
2303 DOCMD_VERBOSE + DOCMD_NOWAIT);
2304
2305 if (eap->cmdidx == CMD_bufdo)
2306 {
2307 /* Done? */
2308 if (next_fnum < 0)
2309 break;
2310 /* Check if the buffer still exists. */
2311 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2312 if (buf->b_fnum == next_fnum)
2313 break;
2314 if (buf == NULL)
2315 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002316
2317 /* Go to the next buffer. Clear 'shm' to avoid that the file
2318 * message overwrites any output from the command. */
2319 p_shm_save = vim_strsave(p_shm);
2320 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002322 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2323 vim_free(p_shm_save);
2324
Bram Moolenaar071d4272004-06-13 20:20:40 +00002325 /* If autocommands took us elsewhere, quit here */
2326 if (curbuf->b_fnum != next_fnum)
2327 break;
2328 }
2329
2330 if (eap->cmdidx == CMD_windo)
2331 {
2332 validate_cursor(); /* cursor may have moved */
2333#ifdef FEAT_SCROLLBIND
2334 /* required when 'scrollbind' has been set */
2335 if (curwin->w_p_scb)
2336 do_check_scrollbind(TRUE);
2337#endif
2338 }
2339 }
2340 listcmd_busy = FALSE;
2341 }
2342
2343#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002344 if (save_ei != NULL)
2345 {
2346 au_event_restore(save_ei);
2347 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2348 curbuf->b_fname, TRUE, curbuf);
2349 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350#endif
2351}
2352
2353/*
2354 * Add files[count] to the arglist of the current window after arg "after".
2355 * The file names in files[count] must have been allocated and are taken over.
2356 * Files[] itself is not taken over.
2357 * Returns index of first added argument. Returns -1 when failed (out of mem).
2358 */
2359 static int
2360alist_add_list(count, files, after)
2361 int count;
2362 char_u **files;
2363 int after; /* where to add: 0 = before first one */
2364{
2365 int i;
2366
2367 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2368 {
2369 if (after < 0)
2370 after = 0;
2371 if (after > ARGCOUNT)
2372 after = ARGCOUNT;
2373 if (after < ARGCOUNT)
2374 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2375 (ARGCOUNT - after) * sizeof(aentry_T));
2376 for (i = 0; i < count; ++i)
2377 {
2378 ARGLIST[after + i].ae_fname = files[i];
2379 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2380 }
2381 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002382 if (curwin->w_arg_idx >= after)
2383 ++curwin->w_arg_idx;
2384 return after;
2385 }
2386
2387 for (i = 0; i < count; ++i)
2388 vim_free(files[i]);
2389 return -1;
2390}
2391
2392#endif /* FEAT_LISTCMDS */
2393
2394#ifdef FEAT_EVAL
2395/*
2396 * ":compiler[!] {name}"
2397 */
2398 void
2399ex_compiler(eap)
2400 exarg_T *eap;
2401{
2402 char_u *buf;
2403 char_u *old_cur_comp = NULL;
2404 char_u *p;
2405
2406 if (*eap->arg == NUL)
2407 {
2408 /* List all compiler scripts. */
2409 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2410 /* ) keep the indenter happy... */
2411 }
2412 else
2413 {
2414 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2415 if (buf != NULL)
2416 {
2417 if (eap->forceit)
2418 {
2419 /* ":compiler! {name}" sets global options */
2420 do_cmdline_cmd((char_u *)
2421 "command -nargs=* CompilerSet set <args>");
2422 }
2423 else
2424 {
2425 /* ":compiler! {name}" sets local options.
2426 * To remain backwards compatible "current_compiler" is always
2427 * used. A user's compiler plugin may set it, the distributed
2428 * plugin will then skip the settings. Afterwards set
2429 * "b:current_compiler" and restore "current_compiler". */
2430 old_cur_comp = get_var_value((char_u *)"current_compiler");
2431 if (old_cur_comp != NULL)
2432 old_cur_comp = vim_strsave(old_cur_comp);
2433 do_cmdline_cmd((char_u *)
2434 "command -nargs=* CompilerSet setlocal <args>");
2435 }
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002436 do_unlet((char_u *)"current_compiler", TRUE);
2437 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438
2439 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002440 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002441 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2442 vim_free(buf);
2443
2444 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2445
2446 /* Set "b:current_compiler" from "current_compiler". */
2447 p = get_var_value((char_u *)"current_compiler");
2448 if (p != NULL)
2449 set_internal_string_var((char_u *)"b:current_compiler", p);
2450
2451 /* Restore "current_compiler" for ":compiler {name}". */
2452 if (!eap->forceit)
2453 {
2454 if (old_cur_comp != NULL)
2455 {
2456 set_internal_string_var((char_u *)"current_compiler",
2457 old_cur_comp);
2458 vim_free(old_cur_comp);
2459 }
2460 else
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002461 do_unlet((char_u *)"current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002462 }
2463 }
2464 }
2465}
2466#endif
2467
2468/*
2469 * ":runtime {name}"
2470 */
2471 void
2472ex_runtime(eap)
2473 exarg_T *eap;
2474{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002475 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476}
2477
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002478static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002480/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002482source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002483 char_u *fname;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002484 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485{
2486 (void)do_source(fname, FALSE, FALSE);
2487}
2488
2489/*
2490 * Source the file "name" from all directories in 'runtimepath'.
2491 * "name" can contain wildcards.
2492 * When "all" is TRUE, source all files, otherwise only the first one.
2493 * return FAIL when no file could be sourced, OK otherwise.
2494 */
2495 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002496source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002497 char_u *name;
2498 int all;
2499{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002500 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002501}
2502
2503/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002504 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2505 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002506 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2507 * used.
2508 * Returns OK when at least one match found, FAIL otherwise.
2509 */
2510 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002511do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512 char_u *name;
2513 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002514 void (*callback)__ARGS((char_u *fname, void *ck));
2515 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516{
2517 char_u *rtp;
2518 char_u *np;
2519 char_u *buf;
2520 char_u *rtp_copy;
2521 char_u *tail;
2522 int num_files;
2523 char_u **files;
2524 int i;
2525 int did_one = FALSE;
2526#ifdef AMIGA
2527 struct Process *proc = (struct Process *)FindTask(0L);
2528 APTR save_winptr = proc->pr_WindowPtr;
2529
2530 /* Avoid a requester here for a volume that doesn't exist. */
2531 proc->pr_WindowPtr = (APTR)-1L;
2532#endif
2533
2534 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2535 * value. */
2536 rtp_copy = vim_strsave(p_rtp);
2537 buf = alloc(MAXPATHL);
2538 if (buf != NULL && rtp_copy != NULL)
2539 {
2540 if (p_verbose > 1)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002541 {
2542 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002543 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002544 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002545 verbose_leave();
2546 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002547
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548 /* Loop over all entries in 'runtimepath'. */
2549 rtp = rtp_copy;
2550 while (*rtp != NUL && (all || !did_one))
2551 {
2552 /* Copy the path from 'runtimepath' to buf[]. */
2553 copy_option_part(&rtp, buf, MAXPATHL, ",");
2554 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2555 {
2556 add_pathsep(buf);
2557 tail = buf + STRLEN(buf);
2558
2559 /* Loop over all patterns in "name" */
2560 np = name;
2561 while (*np != NUL && (all || !did_one))
2562 {
2563 /* Append the pattern from "name" to buf[]. */
2564 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2565 "\t ");
2566
2567 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002568 {
2569 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002570 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002571 verbose_leave();
2572 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573
2574 /* Expand wildcards, invoke the callback for each match. */
2575 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2576 EW_FILE) == OK)
2577 {
2578 for (i = 0; i < num_files; ++i)
2579 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002580 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002581 did_one = TRUE;
2582 if (!all)
2583 break;
2584 }
2585 FreeWild(num_files, files);
2586 }
2587 }
2588 }
2589 }
2590 }
2591 vim_free(buf);
2592 vim_free(rtp_copy);
2593 if (p_verbose > 0 && !did_one)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002594 {
2595 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002596 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002597 verbose_leave();
2598 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002599
2600#ifdef AMIGA
2601 proc->pr_WindowPtr = save_winptr;
2602#endif
2603
2604 return did_one ? OK : FAIL;
2605}
2606
2607#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2608/*
2609 * ":options"
2610 */
2611/*ARGSUSED*/
2612 void
2613ex_options(eap)
2614 exarg_T *eap;
2615{
2616 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2617}
2618#endif
2619
2620/*
2621 * ":source {fname}"
2622 */
2623 void
2624ex_source(eap)
2625 exarg_T *eap;
2626{
2627#ifdef FEAT_BROWSE
2628 if (cmdmod.browse)
2629 {
2630 char_u *fname = NULL;
2631
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002632 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2634 if (fname != NULL)
2635 {
2636 cmd_source(fname, eap);
2637 vim_free(fname);
2638 }
2639 }
2640 else
2641#endif
2642 cmd_source(eap->arg, eap);
2643}
2644
2645 static void
2646cmd_source(fname, eap)
2647 char_u *fname;
2648 exarg_T *eap;
2649{
2650 if (*fname == NUL)
2651 EMSG(_(e_argreq));
2652
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653 else if (eap != NULL && eap->forceit)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002654 /* ":source!": read Normal mdoe commands
2655 * Need to execute the commands directly. This is required at least
2656 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002657 * - ":g" command busy
2658 * - after ":argdo", ":windo" or ":bufdo"
2659 * - another command follows
2660 * - inside a loop
2661 */
2662 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2663#ifdef FEAT_EVAL
2664 || eap->cstack->cs_idx >= 0
2665#endif
2666 );
2667
2668 /* ":source" read ex commands */
2669 else if (do_source(fname, FALSE, FALSE) == FAIL)
2670 EMSG2(_(e_notopen), fname);
2671}
2672
2673/*
2674 * ":source" and associated commands.
2675 */
2676/*
2677 * Structure used to store info for each sourced file.
2678 * It is shared between do_source() and getsourceline().
2679 * This is required, because it needs to be handed to do_cmdline() and
2680 * sourcing can be done recursively.
2681 */
2682struct source_cookie
2683{
2684 FILE *fp; /* opened file for sourcing */
2685 char_u *nextline; /* if not NULL: line that was read ahead */
2686 int finished; /* ":finish" used */
2687#if defined (USE_CRNL) || defined (USE_CR)
2688 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2689 int error; /* TRUE if LF found after CR-LF */
2690#endif
2691#ifdef FEAT_EVAL
2692 linenr_T breakpoint; /* next line with breakpoint or zero */
2693 char_u *fname; /* name of sourced file */
2694 int dbg_tick; /* debug_tick when breakpoint was set */
2695 int level; /* top nesting level of sourced file */
2696#endif
2697#ifdef FEAT_MBYTE
2698 vimconv_T conv; /* type of conversion */
2699#endif
2700};
2701
2702#ifdef FEAT_EVAL
2703/*
2704 * Return the address holding the next breakpoint line for a source cookie.
2705 */
2706 linenr_T *
2707source_breakpoint(cookie)
2708 void *cookie;
2709{
2710 return &((struct source_cookie *)cookie)->breakpoint;
2711}
2712
2713/*
2714 * Return the address holding the debug tick for a source cookie.
2715 */
2716 int *
2717source_dbg_tick(cookie)
2718 void *cookie;
2719{
2720 return &((struct source_cookie *)cookie)->dbg_tick;
2721}
2722
2723/*
2724 * Return the nesting level for a source cookie.
2725 */
2726 int
2727source_level(cookie)
2728 void *cookie;
2729{
2730 return ((struct source_cookie *)cookie)->level;
2731}
2732#endif
2733
2734static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2735
Bram Moolenaar071d4272004-06-13 20:20:40 +00002736#if defined(WIN32) && defined(FEAT_CSCOPE)
2737static FILE *fopen_noinh_readbin __ARGS((char *filename));
2738
2739/*
2740 * Special function to open a file without handle inheritance.
2741 */
2742 static FILE *
2743fopen_noinh_readbin(filename)
2744 char *filename;
2745{
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00002746 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747
2748 if (fd_tmp == -1)
2749 return NULL;
2750 return fdopen(fd_tmp, READBIN);
2751}
2752#endif
2753
2754
2755/*
2756 * do_source: Read the file "fname" and execute its lines as EX commands.
2757 *
2758 * This function may be called recursively!
2759 *
2760 * return FAIL if file could not be opened, OK otherwise
2761 */
2762 int
2763do_source(fname, check_other, is_vimrc)
2764 char_u *fname;
2765 int check_other; /* check for .vimrc and _vimrc */
2766 int is_vimrc; /* call vimrc_found() when file exists */
2767{
2768 struct source_cookie cookie;
2769 char_u *save_sourcing_name;
2770 linenr_T save_sourcing_lnum;
2771 char_u *p;
2772 char_u *fname_exp;
2773 int retval = FAIL;
2774#ifdef FEAT_EVAL
2775 scid_T save_current_SID;
2776 static scid_T last_current_SID = 0;
2777 void *save_funccalp;
2778 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002779 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002780# ifdef UNIX
2781 struct stat st;
2782 int stat_ok;
2783# endif
2784#endif
2785#ifdef STARTUPTIME
2786 struct timeval tv_rel;
2787 struct timeval tv_start;
2788#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002789#ifdef FEAT_PROFILE
2790 proftime_T wait_start;
2791#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792
2793#ifdef RISCOS
2794 p = mch_munge_fname(fname);
2795#else
2796 p = expand_env_save(fname);
2797#endif
2798 if (p == NULL)
2799 return retval;
2800 fname_exp = fix_fname(p);
2801 vim_free(p);
2802 if (fname_exp == NULL)
2803 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804 if (mch_isdir(fname_exp))
2805 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00002806 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807 goto theend;
2808 }
2809
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002810#ifdef FEAT_AUTOCMD
2811 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2812#endif
2813
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814#if defined(WIN32) && defined(FEAT_CSCOPE)
2815 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2816#else
2817 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2818#endif
2819 if (cookie.fp == NULL && check_other)
2820 {
2821 /*
2822 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2823 * and ".exrc" by "_exrc" or vice versa.
2824 */
2825 p = gettail(fname_exp);
2826 if ((*p == '.' || *p == '_')
2827 && (STRICMP(p + 1, "vimrc") == 0
2828 || STRICMP(p + 1, "gvimrc") == 0
2829 || STRICMP(p + 1, "exrc") == 0))
2830 {
2831 if (*p == '_')
2832 *p = '.';
2833 else
2834 *p = '_';
2835#if defined(WIN32) && defined(FEAT_CSCOPE)
2836 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2837#else
2838 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2839#endif
2840 }
2841 }
2842
2843 if (cookie.fp == NULL)
2844 {
2845 if (p_verbose > 0)
2846 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002847 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002849 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850 else
2851 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002852 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002853 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002854 }
2855 goto theend;
2856 }
2857
2858 /*
2859 * The file exists.
2860 * - In verbose mode, give a message.
2861 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2862 */
2863 if (p_verbose > 1)
2864 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002865 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002866 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00002867 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002868 else
2869 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002870 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002871 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872 }
2873 if (is_vimrc)
2874 vimrc_found();
2875
2876#ifdef USE_CRNL
2877 /* If no automatic file format: Set default to CR-NL. */
2878 if (*p_ffs == NUL)
2879 cookie.fileformat = EOL_DOS;
2880 else
2881 cookie.fileformat = EOL_UNKNOWN;
2882 cookie.error = FALSE;
2883#endif
2884
2885#ifdef USE_CR
2886 /* If no automatic file format: Set default to CR. */
2887 if (*p_ffs == NUL)
2888 cookie.fileformat = EOL_MAC;
2889 else
2890 cookie.fileformat = EOL_UNKNOWN;
2891 cookie.error = FALSE;
2892#endif
2893
2894 cookie.nextline = NULL;
2895 cookie.finished = FALSE;
2896
2897#ifdef FEAT_EVAL
2898 /*
2899 * Check if this script has a breakpoint.
2900 */
2901 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2902 cookie.fname = fname_exp;
2903 cookie.dbg_tick = debug_tick;
2904
2905 cookie.level = ex_nesting_level;
2906#endif
2907#ifdef FEAT_MBYTE
2908 cookie.conv.vc_type = CONV_NONE; /* no conversion */
2909
2910 /* Try reading the first few bytes to check for a UTF-8 BOM. */
2911 {
2912 char_u buf[3];
2913
2914 if (fread((char *)buf, sizeof(char_u), (size_t)3, cookie.fp)
2915 == (size_t)3
2916 && buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf)
2917 /* Found BOM, setup conversion and skip over it. */
2918 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
2919 else
2920 /* No BOM found, rewind. */
2921 fseek(cookie.fp, 0L, SEEK_SET);
2922 }
2923#endif
2924
2925 /*
2926 * Keep the sourcing name/lnum, for recursive calls.
2927 */
2928 save_sourcing_name = sourcing_name;
2929 sourcing_name = fname_exp;
2930 save_sourcing_lnum = sourcing_lnum;
2931 sourcing_lnum = 0;
2932
2933#ifdef STARTUPTIME
2934 time_push(&tv_rel, &tv_start);
2935#endif
2936
2937#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00002938# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002939 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002940 prof_child_enter(&wait_start); /* entering a child now */
2941# endif
2942
2943 /* Don't use local function variables, if called from a function.
2944 * Also starts profiling timer for nested script. */
2945 save_funccalp = save_funccal();
2946
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947 /*
2948 * Check if this script was sourced before to finds its SID.
2949 * If it's new, generate a new SID.
2950 */
2951 save_current_SID = current_SID;
2952# ifdef UNIX
2953 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
2954# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002955 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
2956 {
2957 si = &SCRIPT_ITEM(current_SID);
2958 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959 && (
2960# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00002961 /* Compare dev/ino when possible, it catches symbolic
2962 * links. Also compare file names, the inode may change
2963 * when the file was edited. */
Bram Moolenaar05159a02005-02-26 23:04:13 +00002964 ((stat_ok && si->sn_dev != -1)
2965 && (si->sn_dev == st.st_dev
2966 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002968 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002969 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002970 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971 if (current_SID == 0)
2972 {
2973 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002974 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
2975 == FAIL)
2976 goto almosttheend;
2977 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002978 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00002979 ++script_items.ga_len;
2980 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
2981# ifdef FEAT_PROFILE
2982 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002984 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00002985 si = &SCRIPT_ITEM(current_SID);
2986 si->sn_name = fname_exp;
2987 fname_exp = NULL;
2988# ifdef UNIX
2989 if (stat_ok)
2990 {
2991 si->sn_dev = st.st_dev;
2992 si->sn_ino = st.st_ino;
2993 }
2994 else
2995 si->sn_dev = -1;
2996# endif
2997
Bram Moolenaar071d4272004-06-13 20:20:40 +00002998 /* Allocate the local script variables to use for this script. */
2999 new_script_vars(current_SID);
3000 }
3001
Bram Moolenaar05159a02005-02-26 23:04:13 +00003002# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003003 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003004 {
3005 int forceit;
3006
3007 /* Check if we do profiling for this script. */
3008 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3009 {
3010 script_do_profile(si);
3011 si->sn_pr_force = forceit;
3012 }
3013 if (si->sn_prof_on)
3014 {
3015 ++si->sn_pr_count;
3016 profile_start(&si->sn_pr_start);
3017 profile_zero(&si->sn_pr_children);
3018 }
3019 }
3020# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021#endif
3022
3023 /*
3024 * Call do_cmdline, which will call getsourceline() to get the lines.
3025 */
3026 do_cmdline(NULL, getsourceline, (void *)&cookie,
3027 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
3028
3029 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003030
3031#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003032 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003033 {
3034 /* Get "si" again, "script_items" may have been reallocated. */
3035 si = &SCRIPT_ITEM(current_SID);
3036 if (si->sn_prof_on)
3037 {
3038 profile_end(&si->sn_pr_start);
3039 profile_sub_wait(&wait_start, &si->sn_pr_start);
3040 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003041 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3042 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003043 }
3044 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003045#endif
3046
3047 if (got_int)
3048 EMSG(_(e_interr));
3049 sourcing_name = save_sourcing_name;
3050 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051 if (p_verbose > 1)
3052 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003053 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003054 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003056 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003057 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058 }
3059#ifdef STARTUPTIME
Bram Moolenaar555b2802005-05-19 21:08:39 +00003060 vim_snprintf(IObuff, IOSIZE, "sourcing %s", fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061 time_msg(IObuff, &tv_start);
3062 time_pop(&tv_rel);
3063#endif
3064
3065#ifdef FEAT_EVAL
3066 /*
3067 * After a "finish" in debug mode, need to break at first command of next
3068 * sourced file.
3069 */
3070 if (save_debug_break_level > ex_nesting_level
3071 && debug_break_level == ex_nesting_level)
3072 ++debug_break_level;
3073#endif
3074
Bram Moolenaar05159a02005-02-26 23:04:13 +00003075#ifdef FEAT_EVAL
3076almosttheend:
3077 current_SID = save_current_SID;
3078 restore_funccal(save_funccalp);
3079# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003080 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003081 prof_child_exit(&wait_start); /* leaving a child now */
3082# endif
3083#endif
3084 fclose(cookie.fp);
3085 vim_free(cookie.nextline);
3086#ifdef FEAT_MBYTE
3087 convert_setup(&cookie.conv, NULL, NULL);
3088#endif
3089
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090theend:
3091 vim_free(fname_exp);
3092 return retval;
3093}
3094
3095#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003096
Bram Moolenaar071d4272004-06-13 20:20:40 +00003097/*
3098 * ":scriptnames"
3099 */
3100/*ARGSUSED*/
3101 void
3102ex_scriptnames(eap)
3103 exarg_T *eap;
3104{
3105 int i;
3106
Bram Moolenaar05159a02005-02-26 23:04:13 +00003107 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3108 if (SCRIPT_ITEM(i).sn_name != NULL)
3109 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003110}
3111
3112# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3113/*
3114 * Fix slashes in the list of script names for 'shellslash'.
3115 */
3116 void
3117scriptnames_slash_adjust()
3118{
3119 int i;
3120
Bram Moolenaar05159a02005-02-26 23:04:13 +00003121 for (i = 1; i <= script_items.ga_len; ++i)
3122 if (SCRIPT_ITEM(i).sn_name != NULL)
3123 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003124}
3125# endif
3126
3127/*
3128 * Get a pointer to a script name. Used for ":verbose set".
3129 */
3130 char_u *
3131get_scriptname(id)
3132 scid_T id;
3133{
3134 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003135 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003137 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003139 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003140 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003141 return (char_u *)_("environment variable");
3142 if (id == SID_ERROR)
3143 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003144 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003146
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003147# if defined(EXITFREE) || defined(PROTO)
3148 void
3149free_scriptnames()
3150{
3151 int i;
3152
3153 for (i = script_items.ga_len; i > 0; --i)
3154 vim_free(SCRIPT_ITEM(i).sn_name);
3155 ga_clear(&script_items);
3156}
3157# endif
3158
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159#endif
3160
3161#if defined(USE_CR) || defined(PROTO)
3162
3163# if defined(__MSL__) && (__MSL__ >= 22)
3164/*
3165 * Newer version of the Metrowerks library handle DOS and UNIX files
3166 * without help.
3167 * Test with earlier versions, MSL 2.2 is the library supplied with
3168 * Codewarrior Pro 2.
3169 */
3170 char *
3171fgets_cr(s, n, stream)
3172 char *s;
3173 int n;
3174 FILE *stream;
3175{
3176 return fgets(s, n, stream);
3177}
3178# else
3179/*
3180 * Version of fgets() which also works for lines ending in a <CR> only
3181 * (Macintosh format).
3182 * For older versions of the Metrowerks library.
3183 * At least CodeWarrior 9 needed this code.
3184 */
3185 char *
3186fgets_cr(s, n, stream)
3187 char *s;
3188 int n;
3189 FILE *stream;
3190{
3191 int c = 0;
3192 int char_read = 0;
3193
3194 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3195 {
3196 c = fgetc(stream);
3197 s[char_read++] = c;
3198 /* If the file is in DOS format, we need to skip a NL after a CR. I
3199 * thought it was the other way around, but this appears to work... */
3200 if (c == '\n')
3201 {
3202 c = fgetc(stream);
3203 if (c != '\r')
3204 ungetc(c, stream);
3205 }
3206 }
3207
3208 s[char_read] = 0;
3209 if (char_read == 0)
3210 return NULL;
3211
3212 if (feof(stream) && char_read == 1)
3213 return NULL;
3214
3215 return s;
3216}
3217# endif
3218#endif
3219
3220/*
3221 * Get one full line from a sourced file.
3222 * Called by do_cmdline() when it's called from do_source().
3223 *
3224 * Return a pointer to the line in allocated memory.
3225 * Return NULL for end-of-file or some error.
3226 */
3227/* ARGSUSED */
3228 char_u *
3229getsourceline(c, cookie, indent)
3230 int c; /* not used */
3231 void *cookie;
3232 int indent; /* not used */
3233{
3234 struct source_cookie *sp = (struct source_cookie *)cookie;
3235 char_u *line;
3236 char_u *p, *s;
3237
3238#ifdef FEAT_EVAL
3239 /* If breakpoints have been added/deleted need to check for it. */
3240 if (sp->dbg_tick < debug_tick)
3241 {
3242 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3243 sp->dbg_tick = debug_tick;
3244 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003245# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003246 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003247 script_line_end();
3248# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249#endif
3250 /*
3251 * Get current line. If there is a read-ahead line, use it, otherwise get
3252 * one now.
3253 */
3254 if (sp->finished)
3255 line = NULL;
3256 else if (sp->nextline == NULL)
3257 line = get_one_sourceline(sp);
3258 else
3259 {
3260 line = sp->nextline;
3261 sp->nextline = NULL;
3262 ++sourcing_lnum;
3263 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003264#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003265 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003266 script_line_start();
3267#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268
3269 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3270 * contain the 'C' flag. */
3271 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3272 {
3273 /* compensate for the one line read-ahead */
3274 --sourcing_lnum;
3275 for (;;)
3276 {
3277 sp->nextline = get_one_sourceline(sp);
3278 if (sp->nextline == NULL)
3279 break;
3280 p = skipwhite(sp->nextline);
3281 if (*p != '\\')
3282 break;
3283 s = alloc((int)(STRLEN(line) + STRLEN(p)));
3284 if (s == NULL) /* out of memory */
3285 break;
3286 STRCPY(s, line);
3287 STRCAT(s, p + 1);
3288 vim_free(line);
3289 line = s;
3290 vim_free(sp->nextline);
3291 }
3292 }
3293
3294#ifdef FEAT_MBYTE
3295 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3296 {
3297 /* Convert the encoding of the script line. */
3298 s = string_convert(&sp->conv, line, NULL);
3299 if (s != NULL)
3300 {
3301 vim_free(line);
3302 line = s;
3303 }
3304 }
3305#endif
3306
3307#ifdef FEAT_EVAL
3308 /* Did we encounter a breakpoint? */
3309 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3310 {
3311 dbg_breakpoint(sp->fname, sourcing_lnum);
3312 /* Find next breakpoint. */
3313 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3314 sp->dbg_tick = debug_tick;
3315 }
3316#endif
3317
3318 return line;
3319}
3320
3321 static char_u *
3322get_one_sourceline(sp)
3323 struct source_cookie *sp;
3324{
3325 garray_T ga;
3326 int len;
3327 int c;
3328 char_u *buf;
3329#ifdef USE_CRNL
3330 int has_cr; /* CR-LF found */
3331#endif
3332#ifdef USE_CR
3333 char_u *scan;
3334#endif
3335 int have_read = FALSE;
3336
3337 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003338 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339
3340 /*
3341 * Loop until there is a finished line (or end-of-file).
3342 */
3343 sourcing_lnum++;
3344 for (;;)
3345 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003346 /* make room to read at least 120 (more) characters */
3347 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003348 break;
3349 buf = (char_u *)ga.ga_data;
3350
3351#ifdef USE_CR
3352 if (sp->fileformat == EOL_MAC)
3353 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003354 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3355 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356 break;
3357 }
3358 else
3359#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003360 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3361 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003362 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003363 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003364#ifdef USE_CRNL
3365 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3366 * CTRL-Z by its own, or after a NL. */
3367 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3368 && sp->fileformat == EOL_DOS
3369 && buf[len - 1] == Ctrl_Z)
3370 {
3371 buf[len - 1] = NUL;
3372 break;
3373 }
3374#endif
3375
3376#ifdef USE_CR
3377 /* If the read doesn't stop on a new line, and there's
3378 * some CR then we assume a Mac format */
3379 if (sp->fileformat == EOL_UNKNOWN)
3380 {
3381 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3382 sp->fileformat = EOL_MAC;
3383 else
3384 sp->fileformat = EOL_UNIX;
3385 }
3386
3387 if (sp->fileformat == EOL_MAC)
3388 {
3389 scan = vim_strchr(buf, '\r');
3390
3391 if (scan != NULL)
3392 {
3393 *scan = '\n';
3394 if (*(scan + 1) != 0)
3395 {
3396 *(scan + 1) = 0;
3397 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3398 }
3399 }
3400 len = STRLEN(buf);
3401 }
3402#endif
3403
3404 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405 ga.ga_len = len;
3406
3407 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003408 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003409 continue;
3410
3411 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3412 {
3413#ifdef USE_CRNL
3414 has_cr = (len >= 2 && buf[len - 2] == '\r');
3415 if (sp->fileformat == EOL_UNKNOWN)
3416 {
3417 if (has_cr)
3418 sp->fileformat = EOL_DOS;
3419 else
3420 sp->fileformat = EOL_UNIX;
3421 }
3422
3423 if (sp->fileformat == EOL_DOS)
3424 {
3425 if (has_cr) /* replace trailing CR */
3426 {
3427 buf[len - 2] = '\n';
3428 --len;
3429 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003430 }
3431 else /* lines like ":map xx yy^M" will have failed */
3432 {
3433 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003434 {
3435 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003436 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003437 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438 sp->error = TRUE;
3439 sp->fileformat = EOL_UNIX;
3440 }
3441 }
3442#endif
3443 /* The '\n' is escaped if there is an odd number of ^V's just
3444 * before it, first set "c" just before the 'V's and then check
3445 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3446 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3447 ;
3448 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3449 {
3450 sourcing_lnum++;
3451 continue;
3452 }
3453
3454 buf[len - 1] = NUL; /* remove the NL */
3455 }
3456
3457 /*
3458 * Check for ^C here now and then, so recursive :so can be broken.
3459 */
3460 line_breakcheck();
3461 break;
3462 }
3463
3464 if (have_read)
3465 return (char_u *)ga.ga_data;
3466
3467 vim_free(ga.ga_data);
3468 return NULL;
3469}
3470
Bram Moolenaar05159a02005-02-26 23:04:13 +00003471#if defined(FEAT_PROFILE) || defined(PROTO)
3472/*
3473 * Called when starting to read a script line.
3474 * "sourcing_lnum" must be correct!
3475 * When skipping lines it may not actually be executed, but we won't find out
3476 * until later and we need to store the time now.
3477 */
3478 void
3479script_line_start()
3480{
3481 scriptitem_T *si;
3482 sn_prl_T *pp;
3483
3484 if (current_SID <= 0 || current_SID > script_items.ga_len)
3485 return;
3486 si = &SCRIPT_ITEM(current_SID);
3487 if (si->sn_prof_on && sourcing_lnum >= 1)
3488 {
3489 /* Grow the array before starting the timer, so that the time spend
3490 * here isn't counted. */
3491 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3492 si->sn_prl_idx = sourcing_lnum - 1;
3493 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3494 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3495 {
3496 /* Zero counters for a line that was not used before. */
3497 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3498 pp->snp_count = 0;
3499 profile_zero(&pp->sn_prl_total);
3500 profile_zero(&pp->sn_prl_self);
3501 ++si->sn_prl_ga.ga_len;
3502 }
3503 si->sn_prl_execed = FALSE;
3504 profile_start(&si->sn_prl_start);
3505 profile_zero(&si->sn_prl_children);
3506 profile_get_wait(&si->sn_prl_wait);
3507 }
3508}
3509
3510/*
3511 * Called when actually executing a function line.
3512 */
3513 void
3514script_line_exec()
3515{
3516 scriptitem_T *si;
3517
3518 if (current_SID <= 0 || current_SID > script_items.ga_len)
3519 return;
3520 si = &SCRIPT_ITEM(current_SID);
3521 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3522 si->sn_prl_execed = TRUE;
3523}
3524
3525/*
3526 * Called when done with a function line.
3527 */
3528 void
3529script_line_end()
3530{
3531 scriptitem_T *si;
3532 sn_prl_T *pp;
3533
3534 if (current_SID <= 0 || current_SID > script_items.ga_len)
3535 return;
3536 si = &SCRIPT_ITEM(current_SID);
3537 if (si->sn_prof_on && si->sn_prl_idx >= 0
3538 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3539 {
3540 if (si->sn_prl_execed)
3541 {
3542 pp = &PRL_ITEM(si, si->sn_prl_idx);
3543 ++pp->snp_count;
3544 profile_end(&si->sn_prl_start);
3545 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003546 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003547 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3548 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003549 }
3550 si->sn_prl_idx = -1;
3551 }
3552}
3553#endif
3554
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555/*
3556 * ":scriptencoding": Set encoding conversion for a sourced script.
3557 * Without the multi-byte feature it's simply ignored.
3558 */
3559/*ARGSUSED*/
3560 void
3561ex_scriptencoding(eap)
3562 exarg_T *eap;
3563{
3564#ifdef FEAT_MBYTE
3565 struct source_cookie *sp;
3566 char_u *name;
3567
3568 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3569 {
3570 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3571 return;
3572 }
3573
3574 if (*eap->arg != NUL)
3575 {
3576 name = enc_canonize(eap->arg);
3577 if (name == NULL) /* out of memory */
3578 return;
3579 }
3580 else
3581 name = eap->arg;
3582
3583 /* Setup for conversion from the specified encoding to 'encoding'. */
3584 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3585 convert_setup(&sp->conv, name, p_enc);
3586
3587 if (name != eap->arg)
3588 vim_free(name);
3589#endif
3590}
3591
3592#if defined(FEAT_EVAL) || defined(PROTO)
3593/*
3594 * ":finish": Mark a sourced file as finished.
3595 */
3596 void
3597ex_finish(eap)
3598 exarg_T *eap;
3599{
3600 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3601 do_finish(eap, FALSE);
3602 else
3603 EMSG(_("E168: :finish used outside of a sourced file"));
3604}
3605
3606/*
3607 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3608 * Also called for a pending finish at the ":endtry" or after returning from
3609 * an extra do_cmdline(). "reanimate" is used in the latter case.
3610 */
3611 void
3612do_finish(eap, reanimate)
3613 exarg_T *eap;
3614 int reanimate;
3615{
3616 int idx;
3617
3618 if (reanimate)
3619 ((struct source_cookie *)getline_cookie(eap->getline,
3620 eap->cookie))->finished = FALSE;
3621
3622 /*
3623 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3624 * not in its finally clause (which then is to be executed next) is found.
3625 * In this case, make the ":finish" pending for execution at the ":endtry".
3626 * Otherwise, finish normally.
3627 */
3628 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3629 if (idx >= 0)
3630 {
3631 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3632 report_make_pending(CSTP_FINISH, NULL);
3633 }
3634 else
3635 ((struct source_cookie *)getline_cookie(eap->getline,
3636 eap->cookie))->finished = TRUE;
3637}
3638
3639
3640/*
3641 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3642 * message for missing ":endif".
3643 * Return FALSE when not sourcing a file.
3644 */
3645 int
3646source_finished(getline, cookie)
3647 char_u *(*getline) __ARGS((int, void *, int));
3648 void *cookie;
3649{
3650 return (getline_equal(getline, cookie, getsourceline)
3651 && ((struct source_cookie *)getline_cookie(
3652 getline, cookie))->finished);
3653}
3654#endif
3655
3656#if defined(FEAT_LISTCMDS) || defined(PROTO)
3657/*
3658 * ":checktime [buffer]"
3659 */
3660 void
3661ex_checktime(eap)
3662 exarg_T *eap;
3663{
3664 buf_T *buf;
3665 int save_no_check_timestamps = no_check_timestamps;
3666
3667 no_check_timestamps = 0;
3668 if (eap->addr_count == 0) /* default is all buffers */
3669 check_timestamps(FALSE);
3670 else
3671 {
3672 buf = buflist_findnr((int)eap->line2);
3673 if (buf != NULL) /* cannot happen? */
3674 (void)buf_check_timestamp(buf, FALSE);
3675 }
3676 no_check_timestamps = save_no_check_timestamps;
3677}
3678#endif
3679
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3681 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3682static char *get_locale_val __ARGS((int what));
3683
3684 static char *
3685get_locale_val(what)
3686 int what;
3687{
3688 char *loc;
3689
3690 /* Obtain the locale value from the libraries. For DJGPP this is
3691 * redefined and it doesn't use the arguments. */
3692 loc = setlocale(what, NULL);
3693
3694# if defined(__BORLANDC__)
3695 if (loc != NULL)
3696 {
3697 char_u *p;
3698
3699 /* Borland returns something like "LC_CTYPE=<name>\n"
3700 * Let's try to fix that bug here... */
3701 p = vim_strchr(loc, '=');
3702 if (p != NULL)
3703 {
3704 loc = ++p;
3705 while (*p != NUL) /* remove trailing newline */
3706 {
3707 if (*p < ' ')
3708 {
3709 *p = NUL;
3710 break;
3711 }
3712 ++p;
3713 }
3714 }
3715 }
3716# endif
3717
3718 return loc;
3719}
3720#endif
3721
3722
3723#ifdef WIN32
3724/*
3725 * On MS-Windows locale names are strings like "German_Germany.1252", but
3726 * gettext expects "de". Try to translate one into another here for a few
3727 * supported languages.
3728 */
3729 static char_u *
3730gettext_lang(char_u *name)
3731{
3732 int i;
3733 static char *(mtable[]) = {
3734 "afrikaans", "af",
3735 "czech", "cs",
3736 "dutch", "nl",
3737 "german", "de",
3738 "english_united kingdom", "en_GB",
3739 "spanish", "es",
3740 "french", "fr",
3741 "italian", "it",
3742 "japanese", "ja",
3743 "korean", "ko",
3744 "norwegian", "no",
3745 "polish", "pl",
3746 "russian", "ru",
3747 "slovak", "sk",
3748 "swedish", "sv",
3749 "ukrainian", "uk",
3750 "chinese_china", "zh_CN",
3751 "chinese_taiwan", "zh_TW",
3752 NULL};
3753
3754 for (i = 0; mtable[i] != NULL; i += 2)
3755 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3756 return mtable[i + 1];
3757 return name;
3758}
3759#endif
3760
3761#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3762/*
3763 * Obtain the current messages language. Used to set the default for
3764 * 'helplang'. May return NULL or an empty string.
3765 */
3766 char_u *
3767get_mess_lang()
3768{
3769 char_u *p;
3770
3771# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3772# if defined(LC_MESSAGES)
3773 p = (char_u *)get_locale_val(LC_MESSAGES);
3774# else
3775 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
3776 * may be set to the LCID number. */
3777 p = (char_u *)get_locale_val(LC_ALL);
3778# endif
3779# else
3780 p = mch_getenv((char_u *)"LC_ALL");
3781 if (p == NULL || *p == NUL)
3782 {
3783 p = mch_getenv((char_u *)"LC_MESSAGES");
3784 if (p == NULL || *p == NUL)
3785 p = mch_getenv((char_u *)"LANG");
3786 }
3787# endif
3788# ifdef WIN32
3789 p = gettext_lang(p);
3790# endif
3791 return p;
3792}
3793#endif
3794
Bram Moolenaardef9e822004-12-31 20:58:58 +00003795/* Complicated #if; matches with where get_mess_env() is used below. */
3796#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3797 && defined(LC_MESSAGES))) \
3798 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3799 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3800 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003801static char_u *get_mess_env __ARGS((void));
3802
3803/*
3804 * Get the language used for messages from the environment.
3805 */
3806 static char_u *
3807get_mess_env()
3808{
3809 char_u *p;
3810
3811 p = mch_getenv((char_u *)"LC_ALL");
3812 if (p == NULL || *p == NUL)
3813 {
3814 p = mch_getenv((char_u *)"LC_MESSAGES");
3815 if (p == NULL || *p == NUL)
3816 {
3817 p = mch_getenv((char_u *)"LANG");
3818 if (p != NULL && VIM_ISDIGIT(*p))
3819 p = NULL; /* ignore something like "1043" */
3820# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3821 if (p == NULL || *p == NUL)
3822 p = (char_u *)get_locale_val(LC_CTYPE);
3823# endif
3824 }
3825 }
3826 return p;
3827}
3828#endif
3829
3830#if defined(FEAT_EVAL) || defined(PROTO)
3831
3832/*
3833 * Set the "v:lang" variable according to the current locale setting.
3834 * Also do "v:lc_time"and "v:ctype".
3835 */
3836 void
3837set_lang_var()
3838{
3839 char_u *loc;
3840
3841# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3842 loc = (char_u *)get_locale_val(LC_CTYPE);
3843# else
3844 /* setlocale() not supported: use the default value */
3845 loc = (char_u *)"C";
3846# endif
3847 set_vim_var_string(VV_CTYPE, loc, -1);
3848
3849 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3850 * back to LC_CTYPE if it's empty. */
3851# if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
3852 loc = (char_u *)get_locale_val(LC_MESSAGES);
3853# else
3854 loc = get_mess_env();
3855# endif
3856 set_vim_var_string(VV_LANG, loc, -1);
3857
3858# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3859 loc = (char_u *)get_locale_val(LC_TIME);
3860# endif
3861 set_vim_var_string(VV_LC_TIME, loc, -1);
3862}
3863#endif
3864
3865#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3866 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
3867/*
3868 * ":language": Set the language (locale).
3869 */
3870 void
3871ex_language(eap)
3872 exarg_T *eap;
3873{
3874 char *loc;
3875 char_u *p;
3876 char_u *name;
3877 int what = LC_ALL;
3878 char *whatstr = "";
3879#ifdef LC_MESSAGES
3880# define VIM_LC_MESSAGES LC_MESSAGES
3881#else
3882# define VIM_LC_MESSAGES 6789
3883#endif
3884
3885 name = eap->arg;
3886
3887 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3888 * Allow abbreviation, but require at least 3 characters to avoid
3889 * confusion with a two letter language name "me" or "ct". */
3890 p = skiptowhite(eap->arg);
3891 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
3892 {
3893 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3894 {
3895 what = VIM_LC_MESSAGES;
3896 name = skipwhite(p);
3897 whatstr = "messages ";
3898 }
3899 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3900 {
3901 what = LC_CTYPE;
3902 name = skipwhite(p);
3903 whatstr = "ctype ";
3904 }
3905 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
3906 {
3907 what = LC_TIME;
3908 name = skipwhite(p);
3909 whatstr = "time ";
3910 }
3911 }
3912
3913 if (*name == NUL)
3914 {
3915#ifndef LC_MESSAGES
3916 if (what == VIM_LC_MESSAGES)
3917 p = get_mess_env();
3918 else
3919#endif
3920 p = (char_u *)setlocale(what, NULL);
3921 if (p == NULL || *p == NUL)
3922 p = (char_u *)"Unknown";
3923 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
3924 }
3925 else
3926 {
3927#ifndef LC_MESSAGES
3928 if (what == VIM_LC_MESSAGES)
3929 loc = "";
3930 else
3931#endif
3932 loc = setlocale(what, (char *)name);
3933 if (loc == NULL)
3934 EMSG2(_("E197: Cannot set language to \"%s\""), name);
3935 else
3936 {
3937#ifdef HAVE_NL_MSG_CAT_CNTR
3938 /* Need to do this for GNU gettext, otherwise cached translations
3939 * will be used again. */
3940 extern int _nl_msg_cat_cntr;
3941
3942 ++_nl_msg_cat_cntr;
3943#endif
3944 /* Reset $LC_ALL, otherwise it would overrule everyting. */
3945 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
3946
3947 if (what != LC_TIME)
3948 {
3949 /* Tell gettext() what to translate to. It apparently doesn't
3950 * use the currently effective locale. Also do this when
3951 * FEAT_GETTEXT isn't defined, so that shell commands use this
3952 * value. */
3953 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003954 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955 vim_setenv((char_u *)"LANG", name);
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003956# ifdef WIN32
3957 /* Apparently MS-Windows printf() may cause a crash when
3958 * we give it 8-bit text while it's expecting text in the
3959 * current locale. This call avoids that. */
3960 setlocale(LC_CTYPE, "C");
3961# endif
3962 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003963 if (what != LC_CTYPE)
3964 {
3965 char_u *mname;
3966#ifdef WIN32
3967 mname = gettext_lang(name);
3968#else
3969 mname = name;
3970#endif
3971 vim_setenv((char_u *)"LC_MESSAGES", mname);
3972#ifdef FEAT_MULTI_LANG
3973 set_helplang_default(mname);
3974#endif
3975 }
3976
3977 /* Set $LC_CTYPE, because it overrules $LANG, and
3978 * gtk_set_locale() calls setlocale() again. gnome_init()
3979 * sets $LC_CTYPE to "en_US" (that's a bug!). */
3980 if (what != VIM_LC_MESSAGES)
3981 vim_setenv((char_u *)"LC_CTYPE", name);
3982# ifdef FEAT_GUI_GTK
3983 /* Let GTK know what locale we're using. Not sure this is
3984 * really needed... */
3985 if (gui.in_use)
3986 (void)gtk_set_locale();
3987# endif
3988 }
3989
3990# ifdef FEAT_EVAL
3991 /* Set v:lang, v:lc_time and v:ctype to the final result. */
3992 set_lang_var();
3993# endif
3994 }
3995 }
3996}
3997
3998# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
3999/*
4000 * Function given to ExpandGeneric() to obtain the possible arguments of the
4001 * ":language" command.
4002 */
4003/*ARGSUSED*/
4004 char_u *
4005get_lang_arg(xp, idx)
4006 expand_T *xp;
4007 int idx;
4008{
4009 if (idx == 0)
4010 return (char_u *)"messages";
4011 if (idx == 1)
4012 return (char_u *)"ctype";
4013 if (idx == 2)
4014 return (char_u *)"time";
4015 return NULL;
4016}
4017# endif
4018
4019#endif