Merge branch 'vim'
[MacVim.git] / src / ex_cmds2.c
blob35ad1ae8f1497cba1b2813c123578d1aca30de46
1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
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 */
11 * ex_cmds2.c: some more functions for command line commands
14 #if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
15 # include "vimio.h" /* for mch_open(), must be before vim.h */
16 #endif
18 #include "vim.h"
19 #include "version.h"
21 static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
23 #ifdef FEAT_EVAL
24 /* Growarray to store info about already sourced scripts.
25 * For Unix also store the dev/ino, so that we don't have to stat() each
26 * script when going through the list. */
27 typedef struct scriptitem_S
29 char_u *sn_name;
30 # ifdef UNIX
31 int sn_dev_valid;
32 dev_t sn_dev;
33 ino_t sn_ino;
34 # endif
35 # ifdef FEAT_PROFILE
36 int sn_prof_on; /* TRUE when script is/was profiled */
37 int sn_pr_force; /* forceit: profile functions in this script */
38 proftime_T sn_pr_child; /* time set when going into first child */
39 int sn_pr_nest; /* nesting for sn_pr_child */
40 /* profiling the script as a whole */
41 int sn_pr_count; /* nr of times sourced */
42 proftime_T sn_pr_total; /* time spent in script + children */
43 proftime_T sn_pr_self; /* time spent in script itself */
44 proftime_T sn_pr_start; /* time at script start */
45 proftime_T sn_pr_children; /* time in children after script start */
46 /* profiling the script per line */
47 garray_T sn_prl_ga; /* things stored for every line */
48 proftime_T sn_prl_start; /* start time for current line */
49 proftime_T sn_prl_children; /* time spent in children for this line */
50 proftime_T sn_prl_wait; /* wait start time for current line */
51 int sn_prl_idx; /* index of line being timed; -1 if none */
52 int sn_prl_execed; /* line being timed was executed */
53 # endif
54 } scriptitem_T;
56 static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
57 #define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
59 # ifdef FEAT_PROFILE
60 /* Struct used in sn_prl_ga for every line of a script. */
61 typedef struct sn_prl_S
63 int snp_count; /* nr of times line was executed */
64 proftime_T sn_prl_total; /* time spent in a line + children */
65 proftime_T sn_prl_self; /* time spent in a line itself */
66 } sn_prl_T;
68 # define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
69 # endif
70 #endif
72 #if defined(FEAT_EVAL) || defined(PROTO)
73 static int debug_greedy = FALSE; /* batch mode debugging: don't save
74 and restore typeahead. */
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
80 void
81 do_debug(cmd)
82 char_u *cmd;
84 int save_msg_scroll = msg_scroll;
85 int save_State = State;
86 int save_did_emsg = did_emsg;
87 int save_cmd_silent = cmd_silent;
88 int save_msg_silent = msg_silent;
89 int save_emsg_silent = emsg_silent;
90 int save_redir_off = redir_off;
91 tasave_T typeaheadbuf;
92 int typeahead_saved = FALSE;
93 int save_ignore_script = 0;
94 # ifdef FEAT_EX_EXTRA
95 int save_ex_normal_busy;
96 # endif
97 int n;
98 char_u *cmdline = NULL;
99 char_u *p;
100 char *tail = NULL;
101 static int last_cmd = 0;
102 #define CMD_CONT 1
103 #define CMD_NEXT 2
104 #define CMD_STEP 3
105 #define CMD_FINISH 4
106 #define CMD_QUIT 5
107 #define CMD_INTERRUPT 6
109 #ifdef ALWAYS_USE_GUI
110 /* Can't do this when there is no terminal for input/output. */
111 if (!gui.in_use)
113 /* Break as soon as possible. */
114 debug_break_level = 9999;
115 return;
117 #endif
119 /* Make sure we are in raw mode and start termcap mode. Might have side
120 * effects... */
121 settmode(TMODE_RAW);
122 starttermcap();
124 ++RedrawingDisabled; /* don't redisplay the window */
125 ++no_wait_return; /* don't wait for return */
126 did_emsg = FALSE; /* don't use error from debugged stuff */
127 cmd_silent = FALSE; /* display commands */
128 msg_silent = FALSE; /* display messages */
129 emsg_silent = FALSE; /* display error messages */
130 redir_off = TRUE; /* don't redirect debug commands */
132 State = NORMAL;
133 #ifdef FEAT_SNIFF
134 want_sniff_request = 0; /* No K_SNIFF wanted */
135 #endif
137 if (!debug_did_msg)
138 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
139 if (sourcing_name != NULL)
140 msg(sourcing_name);
141 if (sourcing_lnum != 0)
142 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
143 else
144 smsg((char_u *)_("cmd: %s"), cmd);
147 * Repeat getting a command and executing it.
149 for (;;)
151 msg_scroll = TRUE;
152 need_wait_return = FALSE;
153 #ifdef FEAT_SNIFF
154 ProcessSniffRequests();
155 #endif
156 /* Save the current typeahead buffer and replace it with an empty one.
157 * This makes sure we get input from the user here and don't interfere
158 * with the commands being executed. Reset "ex_normal_busy" to avoid
159 * the side effects of using ":normal". Save the stuff buffer and make
160 * it empty. Set ignore_script to avoid reading from script input. */
161 # ifdef FEAT_EX_EXTRA
162 save_ex_normal_busy = ex_normal_busy;
163 ex_normal_busy = 0;
164 # endif
165 if (!debug_greedy)
167 save_typeahead(&typeaheadbuf);
168 typeahead_saved = TRUE;
169 save_ignore_script = ignore_script;
170 ignore_script = TRUE;
173 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
175 if (typeahead_saved)
177 restore_typeahead(&typeaheadbuf);
178 ignore_script = save_ignore_script;
180 # ifdef FEAT_EX_EXTRA
181 ex_normal_busy = save_ex_normal_busy;
182 # endif
184 cmdline_row = msg_row;
185 if (cmdline != NULL)
187 /* If this is a debug command, set "last_cmd".
188 * If not, reset "last_cmd".
189 * For a blank line use previous command. */
190 p = skipwhite(cmdline);
191 if (*p != NUL)
193 switch (*p)
195 case 'c': last_cmd = CMD_CONT;
196 tail = "ont";
197 break;
198 case 'n': last_cmd = CMD_NEXT;
199 tail = "ext";
200 break;
201 case 's': last_cmd = CMD_STEP;
202 tail = "tep";
203 break;
204 case 'f': last_cmd = CMD_FINISH;
205 tail = "inish";
206 break;
207 case 'q': last_cmd = CMD_QUIT;
208 tail = "uit";
209 break;
210 case 'i': last_cmd = CMD_INTERRUPT;
211 tail = "nterrupt";
212 break;
213 default: last_cmd = 0;
215 if (last_cmd != 0)
217 /* Check that the tail matches. */
218 ++p;
219 while (*p != NUL && *p == *tail)
221 ++p;
222 ++tail;
224 if (ASCII_ISALPHA(*p))
225 last_cmd = 0;
229 if (last_cmd != 0)
231 /* Execute debug command: decided where to break next and
232 * return. */
233 switch (last_cmd)
235 case CMD_CONT:
236 debug_break_level = -1;
237 break;
238 case CMD_NEXT:
239 debug_break_level = ex_nesting_level;
240 break;
241 case CMD_STEP:
242 debug_break_level = 9999;
243 break;
244 case CMD_FINISH:
245 debug_break_level = ex_nesting_level - 1;
246 break;
247 case CMD_QUIT:
248 got_int = TRUE;
249 debug_break_level = -1;
250 break;
251 case CMD_INTERRUPT:
252 got_int = TRUE;
253 debug_break_level = 9999;
254 /* Do not repeat ">interrupt" cmd, continue stepping. */
255 last_cmd = CMD_STEP;
256 break;
258 break;
261 /* don't debug this command */
262 n = debug_break_level;
263 debug_break_level = -1;
264 (void)do_cmdline(cmdline, getexline, NULL,
265 DOCMD_VERBOSE|DOCMD_EXCRESET);
266 debug_break_level = n;
268 vim_free(cmdline);
270 lines_left = Rows - 1;
272 vim_free(cmdline);
274 --RedrawingDisabled;
275 --no_wait_return;
276 redraw_all_later(NOT_VALID);
277 need_wait_return = FALSE;
278 msg_scroll = save_msg_scroll;
279 lines_left = Rows - 1;
280 State = save_State;
281 did_emsg = save_did_emsg;
282 cmd_silent = save_cmd_silent;
283 msg_silent = save_msg_silent;
284 emsg_silent = save_emsg_silent;
285 redir_off = save_redir_off;
287 /* Only print the message again when typing a command before coming back
288 * here. */
289 debug_did_msg = TRUE;
293 * ":debug".
295 void
296 ex_debug(eap)
297 exarg_T *eap;
299 int debug_break_level_save = debug_break_level;
301 debug_break_level = 9999;
302 do_cmdline_cmd(eap->arg);
303 debug_break_level = debug_break_level_save;
306 static char_u *debug_breakpoint_name = NULL;
307 static linenr_T debug_breakpoint_lnum;
310 * When debugging or a breakpoint is set on a skipped command, no debug prompt
311 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
312 * debug_skipped_name is then set to the source name in the breakpoint case. If
313 * a skipped command decides itself that a debug prompt should be displayed, it
314 * can do so by calling dbg_check_skipped().
316 static int debug_skipped;
317 static char_u *debug_skipped_name;
320 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
321 * at or below the break level. But only when the line is actually
322 * executed. Return TRUE and set breakpoint_name for skipped commands that
323 * decide to execute something themselves.
324 * Called from do_one_cmd() before executing a command.
326 void
327 dbg_check_breakpoint(eap)
328 exarg_T *eap;
330 char_u *p;
332 debug_skipped = FALSE;
333 if (debug_breakpoint_name != NULL)
335 if (!eap->skip)
337 /* replace K_SNR with "<SNR>" */
338 if (debug_breakpoint_name[0] == K_SPECIAL
339 && debug_breakpoint_name[1] == KS_EXTRA
340 && debug_breakpoint_name[2] == (int)KE_SNR)
341 p = (char_u *)"<SNR>";
342 else
343 p = (char_u *)"";
344 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
346 debug_breakpoint_name + (*p == NUL ? 0 : 3),
347 (long)debug_breakpoint_lnum);
348 debug_breakpoint_name = NULL;
349 do_debug(eap->cmd);
351 else
353 debug_skipped = TRUE;
354 debug_skipped_name = debug_breakpoint_name;
355 debug_breakpoint_name = NULL;
358 else if (ex_nesting_level <= debug_break_level)
360 if (!eap->skip)
361 do_debug(eap->cmd);
362 else
364 debug_skipped = TRUE;
365 debug_skipped_name = NULL;
371 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
372 * set. Return TRUE when the debug mode is entered this time.
375 dbg_check_skipped(eap)
376 exarg_T *eap;
378 int prev_got_int;
380 if (debug_skipped)
383 * Save the value of got_int and reset it. We don't want a previous
384 * interruption cause flushing the input buffer.
386 prev_got_int = got_int;
387 got_int = FALSE;
388 debug_breakpoint_name = debug_skipped_name;
389 /* eap->skip is TRUE */
390 eap->skip = FALSE;
391 (void)dbg_check_breakpoint(eap);
392 eap->skip = TRUE;
393 got_int |= prev_got_int;
394 return TRUE;
396 return FALSE;
400 * The list of breakpoints: dbg_breakp.
401 * This is a grow-array of structs.
403 struct debuggy
405 int dbg_nr; /* breakpoint number */
406 int dbg_type; /* DBG_FUNC or DBG_FILE */
407 char_u *dbg_name; /* function or file name */
408 regprog_T *dbg_prog; /* regexp program */
409 linenr_T dbg_lnum; /* line number in function or file */
410 int dbg_forceit; /* ! used */
413 static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
414 #define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
415 #define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
416 static int last_breakp = 0; /* nr of last defined breakpoint */
418 #ifdef FEAT_PROFILE
419 /* Profiling uses file and func names similar to breakpoints. */
420 static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
421 #endif
422 #define DBG_FUNC 1
423 #define DBG_FILE 2
425 static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
426 static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, garray_T *gap, int *fp));
429 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
430 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
431 * is allocated.
432 * Returns FAIL for failure.
434 static int
435 dbg_parsearg(arg, gap)
436 char_u *arg;
437 garray_T *gap; /* either &dbg_breakp or &prof_ga */
439 char_u *p = arg;
440 char_u *q;
441 struct debuggy *bp;
442 int here = FALSE;
444 if (ga_grow(gap, 1) == FAIL)
445 return FAIL;
446 bp = &DEBUGGY(gap, gap->ga_len);
448 /* Find "func" or "file". */
449 if (STRNCMP(p, "func", 4) == 0)
450 bp->dbg_type = DBG_FUNC;
451 else if (STRNCMP(p, "file", 4) == 0)
452 bp->dbg_type = DBG_FILE;
453 else if (
454 #ifdef FEAT_PROFILE
455 gap != &prof_ga &&
456 #endif
457 STRNCMP(p, "here", 4) == 0)
459 if (curbuf->b_ffname == NULL)
461 EMSG(_(e_noname));
462 return FAIL;
464 bp->dbg_type = DBG_FILE;
465 here = TRUE;
467 else
469 EMSG2(_(e_invarg2), p);
470 return FAIL;
472 p = skipwhite(p + 4);
474 /* Find optional line number. */
475 if (here)
476 bp->dbg_lnum = curwin->w_cursor.lnum;
477 else if (
478 #ifdef FEAT_PROFILE
479 gap != &prof_ga &&
480 #endif
481 VIM_ISDIGIT(*p))
483 bp->dbg_lnum = getdigits(&p);
484 p = skipwhite(p);
486 else
487 bp->dbg_lnum = 0;
489 /* Find the function or file name. Don't accept a function name with (). */
490 if ((!here && *p == NUL)
491 || (here && *p != NUL)
492 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
494 EMSG2(_(e_invarg2), arg);
495 return FAIL;
498 if (bp->dbg_type == DBG_FUNC)
499 bp->dbg_name = vim_strsave(p);
500 else if (here)
501 bp->dbg_name = vim_strsave(curbuf->b_ffname);
502 else
504 /* Expand the file name in the same way as do_source(). This means
505 * doing it twice, so that $DIR/file gets expanded when $DIR is
506 * "~/dir". */
507 #ifdef RISCOS
508 q = mch_munge_fname(p);
509 #else
510 q = expand_env_save(p);
511 #endif
512 if (q == NULL)
513 return FAIL;
514 #ifdef RISCOS
515 p = mch_munge_fname(q);
516 #else
517 p = expand_env_save(q);
518 #endif
519 vim_free(q);
520 if (p == NULL)
521 return FAIL;
522 if (*p != '*')
524 bp->dbg_name = fix_fname(p);
525 vim_free(p);
527 else
528 bp->dbg_name = p;
531 if (bp->dbg_name == NULL)
532 return FAIL;
533 return OK;
537 * ":breakadd".
539 void
540 ex_breakadd(eap)
541 exarg_T *eap;
543 struct debuggy *bp;
544 char_u *pat;
545 garray_T *gap;
547 gap = &dbg_breakp;
548 #ifdef FEAT_PROFILE
549 if (eap->cmdidx == CMD_profile)
550 gap = &prof_ga;
551 #endif
553 if (dbg_parsearg(eap->arg, gap) == OK)
555 bp = &DEBUGGY(gap, gap->ga_len);
556 bp->dbg_forceit = eap->forceit;
558 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
559 if (pat != NULL)
561 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
562 vim_free(pat);
564 if (pat == NULL || bp->dbg_prog == NULL)
565 vim_free(bp->dbg_name);
566 else
568 if (bp->dbg_lnum == 0) /* default line number is 1 */
569 bp->dbg_lnum = 1;
570 #ifdef FEAT_PROFILE
571 if (eap->cmdidx != CMD_profile)
572 #endif
574 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
575 ++debug_tick;
577 ++gap->ga_len;
583 * ":debuggreedy".
585 void
586 ex_debuggreedy(eap)
587 exarg_T *eap;
589 if (eap->addr_count == 0 || eap->line2 != 0)
590 debug_greedy = TRUE;
591 else
592 debug_greedy = FALSE;
596 * ":breakdel" and ":profdel".
598 void
599 ex_breakdel(eap)
600 exarg_T *eap;
602 struct debuggy *bp, *bpi;
603 int nr;
604 int todel = -1;
605 int del_all = FALSE;
606 int i;
607 linenr_T best_lnum = 0;
608 garray_T *gap;
610 gap = &dbg_breakp;
611 #ifdef FEAT_PROFILE
612 if (eap->cmdidx == CMD_profdel)
613 gap = &prof_ga;
614 #endif
616 if (vim_isdigit(*eap->arg))
618 /* ":breakdel {nr}" */
619 nr = atol((char *)eap->arg);
620 for (i = 0; i < gap->ga_len; ++i)
621 if (DEBUGGY(gap, i).dbg_nr == nr)
623 todel = i;
624 break;
627 else if (*eap->arg == '*')
629 todel = 0;
630 del_all = TRUE;
632 else
634 /* ":breakdel {func|file} [lnum] {name}" */
635 if (dbg_parsearg(eap->arg, gap) == FAIL)
636 return;
637 bp = &DEBUGGY(gap, gap->ga_len);
638 for (i = 0; i < gap->ga_len; ++i)
640 bpi = &DEBUGGY(gap, i);
641 if (bp->dbg_type == bpi->dbg_type
642 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
643 && (bp->dbg_lnum == bpi->dbg_lnum
644 || (bp->dbg_lnum == 0
645 && (best_lnum == 0
646 || bpi->dbg_lnum < best_lnum))))
648 todel = i;
649 best_lnum = bpi->dbg_lnum;
652 vim_free(bp->dbg_name);
655 if (todel < 0)
656 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
657 else
659 while (gap->ga_len > 0)
661 vim_free(DEBUGGY(gap, todel).dbg_name);
662 vim_free(DEBUGGY(gap, todel).dbg_prog);
663 --gap->ga_len;
664 if (todel < gap->ga_len)
665 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
666 (gap->ga_len - todel) * sizeof(struct debuggy));
667 #ifdef FEAT_PROFILE
668 if (eap->cmdidx == CMD_breakdel)
669 #endif
670 ++debug_tick;
671 if (!del_all)
672 break;
675 /* If all breakpoints were removed clear the array. */
676 if (gap->ga_len == 0)
677 ga_clear(gap);
682 * ":breaklist".
684 void
685 ex_breaklist(eap)
686 exarg_T *eap UNUSED;
688 struct debuggy *bp;
689 int i;
691 if (dbg_breakp.ga_len == 0)
692 MSG(_("No breakpoints defined"));
693 else
694 for (i = 0; i < dbg_breakp.ga_len; ++i)
696 bp = &BREAKP(i);
697 smsg((char_u *)_("%3d %s %s line %ld"),
698 bp->dbg_nr,
699 bp->dbg_type == DBG_FUNC ? "func" : "file",
700 bp->dbg_name,
701 (long)bp->dbg_lnum);
706 * Find a breakpoint for a function or sourced file.
707 * Returns line number at which to break; zero when no matching breakpoint.
709 linenr_T
710 dbg_find_breakpoint(file, fname, after)
711 int file; /* TRUE for a file, FALSE for a function */
712 char_u *fname; /* file or function name */
713 linenr_T after; /* after this line number */
715 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
718 #if defined(FEAT_PROFILE) || defined(PROTO)
720 * Return TRUE if profiling is on for a function or sourced file.
723 has_profiling(file, fname, fp)
724 int file; /* TRUE for a file, FALSE for a function */
725 char_u *fname; /* file or function name */
726 int *fp; /* return: forceit */
728 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
729 != (linenr_T)0);
731 #endif
734 * Common code for dbg_find_breakpoint() and has_profiling().
736 static linenr_T
737 debuggy_find(file, fname, after, gap, fp)
738 int file; /* TRUE for a file, FALSE for a function */
739 char_u *fname; /* file or function name */
740 linenr_T after; /* after this line number */
741 garray_T *gap; /* either &dbg_breakp or &prof_ga */
742 int *fp; /* if not NULL: return forceit */
744 struct debuggy *bp;
745 int i;
746 linenr_T lnum = 0;
747 regmatch_T regmatch;
748 char_u *name = fname;
749 int prev_got_int;
751 /* Return quickly when there are no breakpoints. */
752 if (gap->ga_len == 0)
753 return (linenr_T)0;
755 /* Replace K_SNR in function name with "<SNR>". */
756 if (!file && fname[0] == K_SPECIAL)
758 name = alloc((unsigned)STRLEN(fname) + 3);
759 if (name == NULL)
760 name = fname;
761 else
763 STRCPY(name, "<SNR>");
764 STRCPY(name + 5, fname + 3);
768 for (i = 0; i < gap->ga_len; ++i)
770 /* Skip entries that are not useful or are for a line that is beyond
771 * an already found breakpoint. */
772 bp = &DEBUGGY(gap, i);
773 if (((bp->dbg_type == DBG_FILE) == file && (
774 #ifdef FEAT_PROFILE
775 gap == &prof_ga ||
776 #endif
777 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
779 regmatch.regprog = bp->dbg_prog;
780 regmatch.rm_ic = FALSE;
782 * Save the value of got_int and reset it. We don't want a
783 * previous interruption cancel matching, only hitting CTRL-C
784 * while matching should abort it.
786 prev_got_int = got_int;
787 got_int = FALSE;
788 if (vim_regexec(&regmatch, name, (colnr_T)0))
790 lnum = bp->dbg_lnum;
791 if (fp != NULL)
792 *fp = bp->dbg_forceit;
794 got_int |= prev_got_int;
797 if (name != fname)
798 vim_free(name);
800 return lnum;
804 * Called when a breakpoint was encountered.
806 void
807 dbg_breakpoint(name, lnum)
808 char_u *name;
809 linenr_T lnum;
811 /* We need to check if this line is actually executed in do_one_cmd() */
812 debug_breakpoint_name = name;
813 debug_breakpoint_lnum = lnum;
817 # if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
819 * Store the current time in "tm".
821 void
822 profile_start(tm)
823 proftime_T *tm;
825 # ifdef WIN3264
826 QueryPerformanceCounter(tm);
827 # else
828 gettimeofday(tm, NULL);
829 # endif
833 * Compute the elapsed time from "tm" till now and store in "tm".
835 void
836 profile_end(tm)
837 proftime_T *tm;
839 proftime_T now;
841 # ifdef WIN3264
842 QueryPerformanceCounter(&now);
843 tm->QuadPart = now.QuadPart - tm->QuadPart;
844 # else
845 gettimeofday(&now, NULL);
846 tm->tv_usec = now.tv_usec - tm->tv_usec;
847 tm->tv_sec = now.tv_sec - tm->tv_sec;
848 if (tm->tv_usec < 0)
850 tm->tv_usec += 1000000;
851 --tm->tv_sec;
853 # endif
857 * Subtract the time "tm2" from "tm".
859 void
860 profile_sub(tm, tm2)
861 proftime_T *tm, *tm2;
863 # ifdef WIN3264
864 tm->QuadPart -= tm2->QuadPart;
865 # else
866 tm->tv_usec -= tm2->tv_usec;
867 tm->tv_sec -= tm2->tv_sec;
868 if (tm->tv_usec < 0)
870 tm->tv_usec += 1000000;
871 --tm->tv_sec;
873 # endif
877 * Return a string that represents the time in "tm".
878 * Uses a static buffer!
880 char *
881 profile_msg(tm)
882 proftime_T *tm;
884 static char buf[50];
886 # ifdef WIN3264
887 LARGE_INTEGER fr;
889 QueryPerformanceFrequency(&fr);
890 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
891 # else
892 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
893 # endif
894 return buf;
898 * Put the time "msec" past now in "tm".
900 void
901 profile_setlimit(msec, tm)
902 long msec;
903 proftime_T *tm;
905 if (msec <= 0) /* no limit */
906 profile_zero(tm);
907 else
909 # ifdef WIN3264
910 LARGE_INTEGER fr;
912 QueryPerformanceCounter(tm);
913 QueryPerformanceFrequency(&fr);
914 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
915 # else
916 long usec;
918 gettimeofday(tm, NULL);
919 usec = (long)tm->tv_usec + (long)msec * 1000;
920 tm->tv_usec = usec % 1000000L;
921 tm->tv_sec += usec / 1000000L;
922 # endif
927 * Return TRUE if the current time is past "tm".
930 profile_passed_limit(tm)
931 proftime_T *tm;
933 proftime_T now;
935 # ifdef WIN3264
936 if (tm->QuadPart == 0) /* timer was not set */
937 return FALSE;
938 QueryPerformanceCounter(&now);
939 return (now.QuadPart > tm->QuadPart);
940 # else
941 if (tm->tv_sec == 0) /* timer was not set */
942 return FALSE;
943 gettimeofday(&now, NULL);
944 return (now.tv_sec > tm->tv_sec
945 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
946 # endif
950 * Set the time in "tm" to zero.
952 void
953 profile_zero(tm)
954 proftime_T *tm;
956 # ifdef WIN3264
957 tm->QuadPart = 0;
958 # else
959 tm->tv_usec = 0;
960 tm->tv_sec = 0;
961 # endif
964 # endif /* FEAT_PROFILE || FEAT_RELTIME */
966 # if defined(FEAT_PROFILE) || defined(PROTO)
968 * Functions for profiling.
970 static void script_do_profile __ARGS((scriptitem_T *si));
971 static void script_dump_profile __ARGS((FILE *fd));
972 static proftime_T prof_wait_time;
975 * Add the time "tm2" to "tm".
977 void
978 profile_add(tm, tm2)
979 proftime_T *tm, *tm2;
981 # ifdef WIN3264
982 tm->QuadPart += tm2->QuadPart;
983 # else
984 tm->tv_usec += tm2->tv_usec;
985 tm->tv_sec += tm2->tv_sec;
986 if (tm->tv_usec >= 1000000)
988 tm->tv_usec -= 1000000;
989 ++tm->tv_sec;
991 # endif
995 * Add the "self" time from the total time and the children's time.
997 void
998 profile_self(self, total, children)
999 proftime_T *self, *total, *children;
1001 /* Check that the result won't be negative. Can happen with recursive
1002 * calls. */
1003 #ifdef WIN3264
1004 if (total->QuadPart <= children->QuadPart)
1005 return;
1006 #else
1007 if (total->tv_sec < children->tv_sec
1008 || (total->tv_sec == children->tv_sec
1009 && total->tv_usec <= children->tv_usec))
1010 return;
1011 #endif
1012 profile_add(self, total);
1013 profile_sub(self, children);
1017 * Get the current waittime.
1019 void
1020 profile_get_wait(tm)
1021 proftime_T *tm;
1023 *tm = prof_wait_time;
1027 * Subtract the passed waittime since "tm" from "tma".
1029 void
1030 profile_sub_wait(tm, tma)
1031 proftime_T *tm, *tma;
1033 proftime_T tm3 = prof_wait_time;
1035 profile_sub(&tm3, tm);
1036 profile_sub(tma, &tm3);
1040 * Return TRUE if "tm1" and "tm2" are equal.
1043 profile_equal(tm1, tm2)
1044 proftime_T *tm1, *tm2;
1046 # ifdef WIN3264
1047 return (tm1->QuadPart == tm2->QuadPart);
1048 # else
1049 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
1050 # endif
1054 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1057 profile_cmp(tm1, tm2)
1058 proftime_T *tm1, *tm2;
1060 # ifdef WIN3264
1061 return (int)(tm2->QuadPart - tm1->QuadPart);
1062 # else
1063 if (tm1->tv_sec == tm2->tv_sec)
1064 return tm2->tv_usec - tm1->tv_usec;
1065 return tm2->tv_sec - tm1->tv_sec;
1066 # endif
1069 static char_u *profile_fname = NULL;
1070 static proftime_T pause_time;
1073 * ":profile cmd args"
1075 void
1076 ex_profile(eap)
1077 exarg_T *eap;
1079 char_u *e;
1080 int len;
1082 e = skiptowhite(eap->arg);
1083 len = (int)(e - eap->arg);
1084 e = skipwhite(e);
1086 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1088 vim_free(profile_fname);
1089 profile_fname = vim_strsave(e);
1090 do_profiling = PROF_YES;
1091 profile_zero(&prof_wait_time);
1092 set_vim_var_nr(VV_PROFILING, 1L);
1094 else if (do_profiling == PROF_NONE)
1095 EMSG(_("E750: First use \":profile start {fname}\""));
1096 else if (STRCMP(eap->arg, "pause") == 0)
1098 if (do_profiling == PROF_YES)
1099 profile_start(&pause_time);
1100 do_profiling = PROF_PAUSED;
1102 else if (STRCMP(eap->arg, "continue") == 0)
1104 if (do_profiling == PROF_PAUSED)
1106 profile_end(&pause_time);
1107 profile_add(&prof_wait_time, &pause_time);
1109 do_profiling = PROF_YES;
1111 else
1113 /* The rest is similar to ":breakadd". */
1114 ex_breakadd(eap);
1118 /* Command line expansion for :profile. */
1119 static enum
1121 PEXP_SUBCMD, /* expand :profile sub-commands */
1122 PEXP_FUNC, /* expand :profile func {funcname} */
1123 } pexpand_what;
1125 static char *pexpand_cmds[] = {
1126 "start",
1127 #define PROFCMD_START 0
1128 "pause",
1129 #define PROFCMD_PAUSE 1
1130 "continue",
1131 #define PROFCMD_CONTINUE 2
1132 "func",
1133 #define PROFCMD_FUNC 3
1134 "file",
1135 #define PROFCMD_FILE 4
1136 NULL
1137 #define PROFCMD_LAST 5
1141 * Function given to ExpandGeneric() to obtain the profile command
1142 * specific expansion.
1144 char_u *
1145 get_profile_name(xp, idx)
1146 expand_T *xp UNUSED;
1147 int idx;
1149 switch (pexpand_what)
1151 case PEXP_SUBCMD:
1152 return (char_u *)pexpand_cmds[idx];
1153 /* case PEXP_FUNC: TODO */
1154 default:
1155 return NULL;
1160 * Handle command line completion for :profile command.
1162 void
1163 set_context_in_profile_cmd(xp, arg)
1164 expand_T *xp;
1165 char_u *arg;
1167 char_u *end_subcmd;
1168 int len;
1170 /* Default: expand subcommands. */
1171 xp->xp_context = EXPAND_PROFILE;
1172 pexpand_what = PEXP_SUBCMD;
1173 xp->xp_pattern = arg;
1175 end_subcmd = skiptowhite(arg);
1176 if (*end_subcmd == NUL)
1177 return;
1179 len = end_subcmd - arg;
1180 if (len == 5 && STRNCMP(arg, "start", 5) == 0)
1182 xp->xp_context = EXPAND_FILES;
1183 xp->xp_pattern = skipwhite(end_subcmd);
1184 return;
1187 /* TODO: expand function names after "func" */
1188 xp->xp_context = EXPAND_NOTHING;
1192 * Dump the profiling info.
1194 void
1195 profile_dump()
1197 FILE *fd;
1199 if (profile_fname != NULL)
1201 fd = mch_fopen((char *)profile_fname, "w");
1202 if (fd == NULL)
1203 EMSG2(_(e_notopen), profile_fname);
1204 else
1206 script_dump_profile(fd);
1207 func_dump_profile(fd);
1208 fclose(fd);
1214 * Start profiling script "fp".
1216 static void
1217 script_do_profile(si)
1218 scriptitem_T *si;
1220 si->sn_pr_count = 0;
1221 profile_zero(&si->sn_pr_total);
1222 profile_zero(&si->sn_pr_self);
1224 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1225 si->sn_prl_idx = -1;
1226 si->sn_prof_on = TRUE;
1227 si->sn_pr_nest = 0;
1231 * save time when starting to invoke another script or function.
1233 void
1234 script_prof_save(tm)
1235 proftime_T *tm; /* place to store wait time */
1237 scriptitem_T *si;
1239 if (current_SID > 0 && current_SID <= script_items.ga_len)
1241 si = &SCRIPT_ITEM(current_SID);
1242 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1243 profile_start(&si->sn_pr_child);
1245 profile_get_wait(tm);
1249 * Count time spent in children after invoking another script or function.
1251 void
1252 script_prof_restore(tm)
1253 proftime_T *tm;
1255 scriptitem_T *si;
1257 if (current_SID > 0 && current_SID <= script_items.ga_len)
1259 si = &SCRIPT_ITEM(current_SID);
1260 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1262 profile_end(&si->sn_pr_child);
1263 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1264 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1265 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1270 static proftime_T inchar_time;
1273 * Called when starting to wait for the user to type a character.
1275 void
1276 prof_inchar_enter()
1278 profile_start(&inchar_time);
1282 * Called when finished waiting for the user to type a character.
1284 void
1285 prof_inchar_exit()
1287 profile_end(&inchar_time);
1288 profile_add(&prof_wait_time, &inchar_time);
1292 * Dump the profiling results for all scripts in file "fd".
1294 static void
1295 script_dump_profile(fd)
1296 FILE *fd;
1298 int id;
1299 scriptitem_T *si;
1300 int i;
1301 FILE *sfd;
1302 sn_prl_T *pp;
1304 for (id = 1; id <= script_items.ga_len; ++id)
1306 si = &SCRIPT_ITEM(id);
1307 if (si->sn_prof_on)
1309 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1310 if (si->sn_pr_count == 1)
1311 fprintf(fd, "Sourced 1 time\n");
1312 else
1313 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1314 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1315 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1316 fprintf(fd, "\n");
1317 fprintf(fd, "count total (s) self (s)\n");
1319 sfd = mch_fopen((char *)si->sn_name, "r");
1320 if (sfd == NULL)
1321 fprintf(fd, "Cannot open file!\n");
1322 else
1324 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1326 if (vim_fgets(IObuff, IOSIZE, sfd))
1327 break;
1328 pp = &PRL_ITEM(si, i);
1329 if (pp->snp_count > 0)
1331 fprintf(fd, "%5d ", pp->snp_count);
1332 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1333 fprintf(fd, " ");
1334 else
1335 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1336 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1338 else
1339 fprintf(fd, " ");
1340 fprintf(fd, "%s", IObuff);
1342 fclose(sfd);
1344 fprintf(fd, "\n");
1350 * Return TRUE when a function defined in the current script should be
1351 * profiled.
1354 prof_def_func()
1356 if (current_SID > 0)
1357 return SCRIPT_ITEM(current_SID).sn_pr_force;
1358 return FALSE;
1361 # endif
1362 #endif
1365 * If 'autowrite' option set, try to write the file.
1366 * Careful: autocommands may make "buf" invalid!
1368 * return FAIL for failure, OK otherwise
1371 autowrite(buf, forceit)
1372 buf_T *buf;
1373 int forceit;
1375 int r;
1377 if (!(p_aw || p_awa) || !p_write
1378 #ifdef FEAT_QUICKFIX
1379 /* never autowrite a "nofile" or "nowrite" buffer */
1380 || bt_dontwrite(buf)
1381 #endif
1382 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
1383 return FAIL;
1384 r = buf_write_all(buf, forceit);
1386 /* Writing may succeed but the buffer still changed, e.g., when there is a
1387 * conversion error. We do want to return FAIL then. */
1388 if (buf_valid(buf) && bufIsChanged(buf))
1389 r = FAIL;
1390 return r;
1394 * flush all buffers, except the ones that are readonly
1396 void
1397 autowrite_all()
1399 buf_T *buf;
1401 if (!(p_aw || p_awa) || !p_write)
1402 return;
1403 for (buf = firstbuf; buf; buf = buf->b_next)
1404 if (bufIsChanged(buf) && !buf->b_p_ro)
1406 (void)buf_write_all(buf, FALSE);
1407 #ifdef FEAT_AUTOCMD
1408 /* an autocommand may have deleted the buffer */
1409 if (!buf_valid(buf))
1410 buf = firstbuf;
1411 #endif
1416 * return TRUE if buffer was changed and cannot be abandoned.
1419 check_changed(buf, checkaw, mult_win, forceit, allbuf)
1420 buf_T *buf;
1421 int checkaw; /* do autowrite if buffer was changed */
1422 int mult_win; /* check also when several wins for the buf */
1423 int forceit;
1424 int allbuf UNUSED; /* may write all buffers */
1426 if ( !forceit
1427 && bufIsChanged(buf)
1428 && (mult_win || buf->b_nwindows <= 1)
1429 && (!checkaw || autowrite(buf, forceit) == FAIL))
1431 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1432 if ((p_confirm || cmdmod.confirm) && p_write)
1434 buf_T *buf2;
1435 int count = 0;
1437 if (allbuf)
1438 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1439 if (bufIsChanged(buf2)
1440 && (buf2->b_ffname != NULL
1441 # ifdef FEAT_BROWSE
1442 || cmdmod.browse
1443 # endif
1445 ++count;
1446 # ifdef FEAT_AUTOCMD
1447 if (!buf_valid(buf))
1448 /* Autocommand deleted buffer, oops! It's not changed now. */
1449 return FALSE;
1450 # endif
1451 dialog_changed(buf, count > 1);
1452 # ifdef FEAT_AUTOCMD
1453 if (!buf_valid(buf))
1454 /* Autocommand deleted buffer, oops! It's not changed now. */
1455 return FALSE;
1456 # endif
1457 return bufIsChanged(buf);
1459 #endif
1460 EMSG(_(e_nowrtmsg));
1461 return TRUE;
1463 return FALSE;
1466 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1468 #if defined(FEAT_BROWSE) || defined(PROTO)
1470 * When wanting to write a file without a file name, ask the user for a name.
1472 void
1473 browse_save_fname(buf)
1474 buf_T *buf;
1476 if (buf->b_fname == NULL)
1478 char_u *fname;
1480 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1481 NULL, NULL, NULL, NULL, buf);
1482 if (fname != NULL)
1484 if (setfname(buf, fname, NULL, TRUE) == OK)
1485 buf->b_flags |= BF_NOTEDITED;
1486 vim_free(fname);
1490 #endif
1492 #ifdef FEAT_GUI_MACVIM
1494 * "Save changes" dialog that conforms to the Apple HIG.
1497 vim_dialog_save_changes(buf)
1498 buf_T *buf;
1500 char_u buff[IOSIZE];
1502 dialog_msg(buff, _("Do you want to save the changes you made in the "
1503 "document \"%s\"?"), buf->b_fname);
1504 switch (do_dialog(VIM_QUESTION, buff,
1505 (char_u*) _("Your changes will be lost if you don't save "
1506 "them."),
1507 (buf->b_fname != NULL)
1508 ? (char_u *)_("&Save\n&Cancel\n&Don't Save")
1509 : (char_u *)_("&Save...\n&Cancel\n&Don't Save"),
1510 1, NULL))
1512 case 1: return VIM_YES;
1513 case 3: return VIM_NO;
1516 return VIM_CANCEL;
1520 * "Save all changes" dialog that tries to emulate the above "Save changes"
1521 * dialog for the case of several modified buffers.
1524 vim_dialog_save_all_changes(buf)
1525 buf_T *buf;
1527 char_u buff[IOSIZE];
1529 dialog_msg(buff, _("There are several documents with unsaved changes. "
1530 "Do you want to save the changes you made in the "
1531 "document \"%s\"?"), buf->b_fname);
1532 switch (do_dialog(VIM_QUESTION, buff,
1533 (char_u*) _("Your changes will be lost if you don't save "
1534 "them."),
1535 (char_u *)_("&Save\n&Don't Save\nS&ave All\nD&iscard All\n"
1536 "&Cancel"),
1537 1, NULL))
1539 case 1: return VIM_YES;
1540 case 2: return VIM_NO;
1541 case 3: return VIM_ALL;
1542 case 4: return VIM_DISCARDALL;
1545 return VIM_CANCEL;
1547 #endif
1550 * Ask the user what to do when abondoning a changed buffer.
1551 * Must check 'write' option first!
1553 void
1554 dialog_changed(buf, checkall)
1555 buf_T *buf;
1556 int checkall; /* may abandon all changed buffers */
1558 char_u buff[IOSIZE];
1559 int ret;
1560 buf_T *buf2;
1562 #ifdef FEAT_GUI_MACVIM
1563 /* Save dialogs on Mac OS X are standardized so in case the GUI is enabled
1564 * and "c" isn't in 'guioptions' we use a OS X specific dialog. */
1565 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
1567 if (checkall)
1568 ret = vim_dialog_save_all_changes(buf);
1569 else
1570 ret = vim_dialog_save_changes(buf);
1572 else
1574 #endif
1575 dialog_msg(buff, _("Save changes to \"%s\"?"),
1576 (buf->b_fname != NULL) ?
1577 buf->b_fname : (char_u *)_("Untitled"));
1578 if (checkall)
1579 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1580 else
1581 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1582 #ifdef FEAT_GUI_MACVIM
1584 #endif
1586 if (ret == VIM_YES)
1588 #ifdef FEAT_BROWSE
1589 /* May get file name, when there is none */
1590 browse_save_fname(buf);
1591 #endif
1592 if (buf->b_fname != NULL) /* didn't hit Cancel */
1593 (void)buf_write_all(buf, FALSE);
1595 else if (ret == VIM_NO)
1597 unchanged(buf, TRUE);
1599 else if (ret == VIM_ALL)
1602 * Write all modified files that can be written.
1603 * Skip readonly buffers, these need to be confirmed
1604 * individually.
1606 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1608 if (bufIsChanged(buf2)
1609 && (buf2->b_ffname != NULL
1610 #ifdef FEAT_BROWSE
1611 || cmdmod.browse
1612 #endif
1614 && !buf2->b_p_ro)
1616 #ifdef FEAT_BROWSE
1617 /* May get file name, when there is none */
1618 browse_save_fname(buf2);
1619 #endif
1620 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1621 (void)buf_write_all(buf2, FALSE);
1622 #ifdef FEAT_AUTOCMD
1623 /* an autocommand may have deleted the buffer */
1624 if (!buf_valid(buf2))
1625 buf2 = firstbuf;
1626 #endif
1630 else if (ret == VIM_DISCARDALL)
1633 * mark all buffers as unchanged
1635 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1636 unchanged(buf2, TRUE);
1639 #endif
1642 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1643 * hidden, autowriting it or unloading it.
1646 can_abandon(buf, forceit)
1647 buf_T *buf;
1648 int forceit;
1650 return ( P_HID(buf)
1651 || !bufIsChanged(buf)
1652 || buf->b_nwindows > 1
1653 || autowrite(buf, forceit) == OK
1654 || forceit);
1658 * Return TRUE if any buffer was changed and cannot be abandoned.
1659 * That changed buffer becomes the current buffer.
1662 check_changed_any(hidden)
1663 int hidden; /* Only check hidden buffers */
1665 buf_T *buf;
1666 int save;
1667 #ifdef FEAT_WINDOWS
1668 win_T *wp;
1669 #endif
1671 for (;;)
1673 /* check curbuf first: if it was changed we can't abandon it */
1674 if (!hidden && curbufIsChanged())
1675 buf = curbuf;
1676 else
1678 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1679 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1680 break;
1682 if (buf == NULL) /* No buffers changed */
1683 return FALSE;
1685 /* Try auto-writing the buffer. If this fails but the buffer no
1686 * longer exists it's not changed, that's OK. */
1687 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1688 break; /* didn't save - still changes */
1691 exiting = FALSE;
1692 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1694 * When ":confirm" used, don't give an error message.
1696 if (!(p_confirm || cmdmod.confirm))
1697 #endif
1699 /* There must be a wait_return for this message, do_buffer()
1700 * may cause a redraw. But wait_return() is a no-op when vgetc()
1701 * is busy (Quit used from window menu), then make sure we don't
1702 * cause a scroll up. */
1703 if (vgetc_busy > 0)
1705 msg_row = cmdline_row;
1706 msg_col = 0;
1707 msg_didout = FALSE;
1709 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1710 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1711 buf->b_fname))
1713 save = no_wait_return;
1714 no_wait_return = FALSE;
1715 wait_return(FALSE);
1716 no_wait_return = save;
1720 #ifdef FEAT_WINDOWS
1721 /* Try to find a window that contains the buffer. */
1722 if (buf != curbuf)
1723 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1724 if (wp->w_buffer == buf)
1726 win_goto(wp);
1727 # ifdef FEAT_AUTOCMD
1728 /* Paranoia: did autocms wipe out the buffer with changes? */
1729 if (!buf_valid(buf))
1730 return TRUE;
1731 # endif
1732 break;
1734 #endif
1736 /* Open the changed buffer in the current window. */
1737 if (buf != curbuf)
1738 set_curbuf(buf, DOBUF_GOTO);
1740 return TRUE;
1744 * return FAIL if there is no file name, OK if there is one
1745 * give error message for FAIL
1748 check_fname()
1750 if (curbuf->b_ffname == NULL)
1752 EMSG(_(e_noname));
1753 return FAIL;
1755 return OK;
1759 * flush the contents of a buffer, unless it has no file name
1761 * return FAIL for failure, OK otherwise
1764 buf_write_all(buf, forceit)
1765 buf_T *buf;
1766 int forceit;
1768 int retval;
1769 #ifdef FEAT_AUTOCMD
1770 buf_T *old_curbuf = curbuf;
1771 #endif
1773 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1774 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1775 FALSE, forceit, TRUE, FALSE));
1776 #ifdef FEAT_AUTOCMD
1777 if (curbuf != old_curbuf)
1779 msg_source(hl_attr(HLF_W));
1780 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
1782 #endif
1783 return retval;
1787 * Code to handle the argument list.
1790 static char_u *do_one_arg __ARGS((char_u *str));
1791 static int do_arglist __ARGS((char_u *str, int what, int after));
1792 static void alist_check_arg_idx __ARGS((void));
1793 static int editing_arg_idx __ARGS((win_T *win));
1794 #ifdef FEAT_LISTCMDS
1795 static int alist_add_list __ARGS((int count, char_u **files, int after));
1796 #endif
1797 #define AL_SET 1
1798 #define AL_ADD 2
1799 #define AL_DEL 3
1802 * Isolate one argument, taking backticks.
1803 * Changes the argument in-place, puts a NUL after it. Backticks remain.
1804 * Return a pointer to the start of the next argument.
1806 static char_u *
1807 do_one_arg(str)
1808 char_u *str;
1810 char_u *p;
1811 int inbacktick;
1813 inbacktick = FALSE;
1814 for (p = str; *str; ++str)
1816 /* When the backslash is used for escaping the special meaning of a
1817 * character we need to keep it until wildcard expansion. */
1818 if (rem_backslash(str))
1820 *p++ = *str++;
1821 *p++ = *str;
1823 else
1825 /* An item ends at a space not in backticks */
1826 if (!inbacktick && vim_isspace(*str))
1827 break;
1828 if (*str == '`')
1829 inbacktick ^= TRUE;
1830 *p++ = *str;
1833 str = skipwhite(str);
1834 *p = NUL;
1836 return str;
1840 * Separate the arguments in "str" and return a list of pointers in the
1841 * growarray "gap".
1844 get_arglist(gap, str)
1845 garray_T *gap;
1846 char_u *str;
1848 ga_init2(gap, (int)sizeof(char_u *), 20);
1849 while (*str != NUL)
1851 if (ga_grow(gap, 1) == FAIL)
1853 ga_clear(gap);
1854 return FAIL;
1856 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1858 /* Isolate one argument, change it in-place, put a NUL after it. */
1859 str = do_one_arg(str);
1861 return OK;
1864 #if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
1866 * Parse a list of arguments (file names), expand them and return in
1867 * "fnames[fcountp]".
1868 * Return FAIL or OK.
1871 get_arglist_exp(str, fcountp, fnamesp)
1872 char_u *str;
1873 int *fcountp;
1874 char_u ***fnamesp;
1876 garray_T ga;
1877 int i;
1879 if (get_arglist(&ga, str) == FAIL)
1880 return FAIL;
1881 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1882 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1883 ga_clear(&ga);
1884 return i;
1886 #endif
1888 #if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1890 * Redefine the argument list.
1892 void
1893 set_arglist(str)
1894 char_u *str;
1896 do_arglist(str, AL_SET, 0);
1898 #endif
1901 * "what" == AL_SET: Redefine the argument list to 'str'.
1902 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1903 * "what" == AL_DEL: remove files in 'str' from the argument list.
1905 * Return FAIL for failure, OK otherwise.
1907 static int
1908 do_arglist(str, what, after)
1909 char_u *str;
1910 int what UNUSED;
1911 int after UNUSED; /* 0 means before first one */
1913 garray_T new_ga;
1914 int exp_count;
1915 char_u **exp_files;
1916 int i;
1917 #ifdef FEAT_LISTCMDS
1918 char_u *p;
1919 int match;
1920 #endif
1923 * Collect all file name arguments in "new_ga".
1925 if (get_arglist(&new_ga, str) == FAIL)
1926 return FAIL;
1928 #ifdef FEAT_LISTCMDS
1929 if (what == AL_DEL)
1931 regmatch_T regmatch;
1932 int didone;
1935 * Delete the items: use each item as a regexp and find a match in the
1936 * argument list.
1938 #ifdef CASE_INSENSITIVE_FILENAME
1939 regmatch.rm_ic = TRUE; /* Always ignore case */
1940 #else
1941 regmatch.rm_ic = FALSE; /* Never ignore case */
1942 #endif
1943 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1945 p = ((char_u **)new_ga.ga_data)[i];
1946 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1947 if (p == NULL)
1948 break;
1949 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1950 if (regmatch.regprog == NULL)
1952 vim_free(p);
1953 break;
1956 didone = FALSE;
1957 for (match = 0; match < ARGCOUNT; ++match)
1958 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1959 (colnr_T)0))
1961 didone = TRUE;
1962 vim_free(ARGLIST[match].ae_fname);
1963 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1964 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1965 --ALIST(curwin)->al_ga.ga_len;
1966 if (curwin->w_arg_idx > match)
1967 --curwin->w_arg_idx;
1968 --match;
1971 vim_free(regmatch.regprog);
1972 vim_free(p);
1973 if (!didone)
1974 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1976 ga_clear(&new_ga);
1978 else
1979 #endif
1981 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1982 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1983 ga_clear(&new_ga);
1984 if (i == FAIL)
1985 return FAIL;
1986 if (exp_count == 0)
1988 EMSG(_(e_nomatch));
1989 return FAIL;
1992 #ifdef FEAT_LISTCMDS
1993 if (what == AL_ADD)
1995 (void)alist_add_list(exp_count, exp_files, after);
1996 vim_free(exp_files);
1998 else /* what == AL_SET */
1999 #endif
2000 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
2003 alist_check_arg_idx();
2005 return OK;
2009 * Check the validity of the arg_idx for each other window.
2011 static void
2012 alist_check_arg_idx()
2014 #ifdef FEAT_WINDOWS
2015 win_T *win;
2016 tabpage_T *tp;
2018 FOR_ALL_TAB_WINDOWS(tp, win)
2019 if (win->w_alist == curwin->w_alist)
2020 check_arg_idx(win);
2021 #else
2022 check_arg_idx(curwin);
2023 #endif
2027 * Return TRUE if window "win" is editing then file at the current argument
2028 * index.
2030 static int
2031 editing_arg_idx(win)
2032 win_T *win;
2034 return !(win->w_arg_idx >= WARGCOUNT(win)
2035 || (win->w_buffer->b_fnum
2036 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2037 && (win->w_buffer->b_ffname == NULL
2038 || !(fullpathcmp(
2039 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2040 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2044 * Check if window "win" is editing the w_arg_idx file in its argument list.
2046 void
2047 check_arg_idx(win)
2048 win_T *win;
2050 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
2052 /* We are not editing the current entry in the argument list.
2053 * Set "arg_had_last" if we are editing the last one. */
2054 win->w_arg_idx_invalid = TRUE;
2055 if (win->w_arg_idx != WARGCOUNT(win) - 1
2056 && arg_had_last == FALSE
2057 #ifdef FEAT_WINDOWS
2058 && ALIST(win) == &global_alist
2059 #endif
2060 && GARGCOUNT > 0
2061 && win->w_arg_idx < GARGCOUNT
2062 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2063 || (win->w_buffer->b_ffname != NULL
2064 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2065 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2066 arg_had_last = TRUE;
2068 else
2070 /* We are editing the current entry in the argument list.
2071 * Set "arg_had_last" if it's also the last one */
2072 win->w_arg_idx_invalid = FALSE;
2073 if (win->w_arg_idx == WARGCOUNT(win) - 1
2074 #ifdef FEAT_WINDOWS
2075 && win->w_alist == &global_alist
2076 #endif
2078 arg_had_last = TRUE;
2083 * ":args", ":argslocal" and ":argsglobal".
2085 void
2086 ex_args(eap)
2087 exarg_T *eap;
2089 int i;
2091 if (eap->cmdidx != CMD_args)
2093 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2094 alist_unlink(ALIST(curwin));
2095 if (eap->cmdidx == CMD_argglobal)
2096 ALIST(curwin) = &global_alist;
2097 else /* eap->cmdidx == CMD_arglocal */
2098 alist_new();
2099 #else
2100 ex_ni(eap);
2101 return;
2102 #endif
2105 if (!ends_excmd(*eap->arg))
2108 * ":args file ..": define new argument list, handle like ":next"
2109 * Also for ":argslocal file .." and ":argsglobal file ..".
2111 ex_next(eap);
2113 else
2114 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2115 if (eap->cmdidx == CMD_args)
2116 #endif
2119 * ":args": list arguments.
2121 if (ARGCOUNT > 0)
2123 /* Overwrite the command, for a short list there is no scrolling
2124 * required and no wait_return(). */
2125 gotocmdline(TRUE);
2126 for (i = 0; i < ARGCOUNT; ++i)
2128 if (i == curwin->w_arg_idx)
2129 msg_putchar('[');
2130 msg_outtrans(alist_name(&ARGLIST[i]));
2131 if (i == curwin->w_arg_idx)
2132 msg_putchar(']');
2133 msg_putchar(' ');
2137 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2138 else if (eap->cmdidx == CMD_arglocal)
2140 garray_T *gap = &curwin->w_alist->al_ga;
2143 * ":argslocal": make a local copy of the global argument list.
2145 if (ga_grow(gap, GARGCOUNT) == OK)
2146 for (i = 0; i < GARGCOUNT; ++i)
2147 if (GARGLIST[i].ae_fname != NULL)
2149 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2150 vim_strsave(GARGLIST[i].ae_fname);
2151 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2152 GARGLIST[i].ae_fnum;
2153 ++gap->ga_len;
2156 #endif
2160 * ":previous", ":sprevious", ":Next" and ":sNext".
2162 void
2163 ex_previous(eap)
2164 exarg_T *eap;
2166 /* If past the last one already, go to the last one. */
2167 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2168 do_argfile(eap, ARGCOUNT - 1);
2169 else
2170 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2174 * ":rewind", ":first", ":sfirst" and ":srewind".
2176 void
2177 ex_rewind(eap)
2178 exarg_T *eap;
2180 do_argfile(eap, 0);
2184 * ":last" and ":slast".
2186 void
2187 ex_last(eap)
2188 exarg_T *eap;
2190 do_argfile(eap, ARGCOUNT - 1);
2194 * ":argument" and ":sargument".
2196 void
2197 ex_argument(eap)
2198 exarg_T *eap;
2200 int i;
2202 if (eap->addr_count > 0)
2203 i = eap->line2 - 1;
2204 else
2205 i = curwin->w_arg_idx;
2206 do_argfile(eap, i);
2210 * Edit file "argn" of the argument lists.
2212 void
2213 do_argfile(eap, argn)
2214 exarg_T *eap;
2215 int argn;
2217 int other;
2218 char_u *p;
2219 int old_arg_idx = curwin->w_arg_idx;
2221 if (argn < 0 || argn >= ARGCOUNT)
2223 if (ARGCOUNT <= 1)
2224 EMSG(_("E163: There is only one file to edit"));
2225 else if (argn < 0)
2226 EMSG(_("E164: Cannot go before first file"));
2227 else
2228 EMSG(_("E165: Cannot go beyond last file"));
2230 else
2232 setpcmark();
2233 #ifdef FEAT_GUI
2234 need_mouse_correct = TRUE;
2235 #endif
2237 #ifdef FEAT_WINDOWS
2238 /* split window or create new tab page first */
2239 if (*eap->cmd == 's' || cmdmod.tab != 0)
2241 if (win_split(0, 0) == FAIL)
2242 return;
2243 # ifdef FEAT_SCROLLBIND
2244 curwin->w_p_scb = FALSE;
2245 # endif
2247 else
2248 #endif
2251 * if 'hidden' set, only check for changed file when re-editing
2252 * the same buffer
2254 other = TRUE;
2255 if (P_HID(curbuf))
2257 p = fix_fname(alist_name(&ARGLIST[argn]));
2258 other = otherfile(p);
2259 vim_free(p);
2261 if ((!P_HID(curbuf) || !other)
2262 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2263 return;
2266 curwin->w_arg_idx = argn;
2267 if (argn == ARGCOUNT - 1
2268 #ifdef FEAT_WINDOWS
2269 && curwin->w_alist == &global_alist
2270 #endif
2272 arg_had_last = TRUE;
2274 /* Edit the file; always use the last known line number.
2275 * When it fails (e.g. Abort for already edited file) restore the
2276 * argument index. */
2277 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
2278 eap, ECMD_LAST,
2279 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2280 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
2281 curwin->w_arg_idx = old_arg_idx;
2282 /* like Vi: set the mark where the cursor is in the file. */
2283 else if (eap->cmdidx != CMD_argdo)
2284 setmark('\'');
2289 * ":next", and commands that behave like it.
2291 void
2292 ex_next(eap)
2293 exarg_T *eap;
2295 int i;
2298 * check for changed buffer now, if this fails the argument list is not
2299 * redefined.
2301 if ( P_HID(curbuf)
2302 || eap->cmdidx == CMD_snext
2303 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2305 if (*eap->arg != NUL) /* redefine file list */
2307 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2308 return;
2309 i = 0;
2311 else
2312 i = curwin->w_arg_idx + (int)eap->line2;
2313 do_argfile(eap, i);
2317 #ifdef FEAT_LISTCMDS
2319 * ":argedit"
2321 void
2322 ex_argedit(eap)
2323 exarg_T *eap;
2325 int fnum;
2326 int i;
2327 char_u *s;
2329 /* Add the argument to the buffer list and get the buffer number. */
2330 fnum = buflist_add(eap->arg, BLN_LISTED);
2332 /* Check if this argument is already in the argument list. */
2333 for (i = 0; i < ARGCOUNT; ++i)
2334 if (ARGLIST[i].ae_fnum == fnum)
2335 break;
2336 if (i == ARGCOUNT)
2338 /* Can't find it, add it to the argument list. */
2339 s = vim_strsave(eap->arg);
2340 if (s == NULL)
2341 return;
2342 i = alist_add_list(1, &s,
2343 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2344 if (i < 0)
2345 return;
2346 curwin->w_arg_idx = i;
2349 alist_check_arg_idx();
2351 /* Edit the argument. */
2352 do_argfile(eap, i);
2356 * ":argadd"
2358 void
2359 ex_argadd(eap)
2360 exarg_T *eap;
2362 do_arglist(eap->arg, AL_ADD,
2363 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2364 #ifdef FEAT_TITLE
2365 maketitle();
2366 #endif
2370 * ":argdelete"
2372 void
2373 ex_argdelete(eap)
2374 exarg_T *eap;
2376 int i;
2377 int n;
2379 if (eap->addr_count > 0)
2381 /* ":1,4argdel": Delete all arguments in the range. */
2382 if (eap->line2 > ARGCOUNT)
2383 eap->line2 = ARGCOUNT;
2384 n = eap->line2 - eap->line1 + 1;
2385 if (*eap->arg != NUL || n <= 0)
2386 EMSG(_(e_invarg));
2387 else
2389 for (i = eap->line1; i <= eap->line2; ++i)
2390 vim_free(ARGLIST[i - 1].ae_fname);
2391 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2392 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2393 ALIST(curwin)->al_ga.ga_len -= n;
2394 if (curwin->w_arg_idx >= eap->line2)
2395 curwin->w_arg_idx -= n;
2396 else if (curwin->w_arg_idx > eap->line1)
2397 curwin->w_arg_idx = eap->line1;
2400 else if (*eap->arg == NUL)
2401 EMSG(_(e_argreq));
2402 else
2403 do_arglist(eap->arg, AL_DEL, 0);
2404 #ifdef FEAT_TITLE
2405 maketitle();
2406 #endif
2410 * ":argdo", ":windo", ":bufdo", ":tabdo"
2412 void
2413 ex_listdo(eap)
2414 exarg_T *eap;
2416 int i;
2417 #ifdef FEAT_WINDOWS
2418 win_T *wp;
2419 tabpage_T *tp;
2420 #endif
2421 buf_T *buf;
2422 int next_fnum = 0;
2423 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2424 char_u *save_ei = NULL;
2425 #endif
2426 char_u *p_shm_save;
2428 #ifndef FEAT_WINDOWS
2429 if (eap->cmdidx == CMD_windo)
2431 ex_ni(eap);
2432 return;
2434 #endif
2436 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2437 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
2438 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2439 * great speed improvement. */
2440 save_ei = au_event_disable(",Syntax");
2441 #endif
2443 if (eap->cmdidx == CMD_windo
2444 || eap->cmdidx == CMD_tabdo
2445 || P_HID(curbuf)
2446 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2448 /* start at the first argument/window/buffer */
2449 i = 0;
2450 #ifdef FEAT_WINDOWS
2451 wp = firstwin;
2452 tp = first_tabpage;
2453 #endif
2454 /* set pcmark now */
2455 if (eap->cmdidx == CMD_bufdo)
2456 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2457 else
2458 setpcmark();
2459 listcmd_busy = TRUE; /* avoids setting pcmark below */
2461 while (!got_int)
2463 if (eap->cmdidx == CMD_argdo)
2465 /* go to argument "i" */
2466 if (i == ARGCOUNT)
2467 break;
2468 /* Don't call do_argfile() when already there, it will try
2469 * reloading the file. */
2470 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
2472 /* Clear 'shm' to avoid that the file message overwrites
2473 * any output from the command. */
2474 p_shm_save = vim_strsave(p_shm);
2475 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
2476 do_argfile(eap, i);
2477 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2478 vim_free(p_shm_save);
2480 if (curwin->w_arg_idx != i)
2481 break;
2482 ++i;
2484 #ifdef FEAT_WINDOWS
2485 else if (eap->cmdidx == CMD_windo)
2487 /* go to window "wp" */
2488 if (!win_valid(wp))
2489 break;
2490 win_goto(wp);
2491 if (curwin != wp)
2492 break; /* something must be wrong */
2493 wp = curwin->w_next;
2495 else if (eap->cmdidx == CMD_tabdo)
2497 /* go to window "tp" */
2498 if (!valid_tabpage(tp))
2499 break;
2500 goto_tabpage_tp(tp);
2501 tp = tp->tp_next;
2503 #endif
2504 else if (eap->cmdidx == CMD_bufdo)
2506 /* Remember the number of the next listed buffer, in case
2507 * ":bwipe" is used or autocommands do something strange. */
2508 next_fnum = -1;
2509 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2510 if (buf->b_p_bl)
2512 next_fnum = buf->b_fnum;
2513 break;
2517 /* execute the command */
2518 do_cmdline(eap->arg, eap->getline, eap->cookie,
2519 DOCMD_VERBOSE + DOCMD_NOWAIT);
2521 if (eap->cmdidx == CMD_bufdo)
2523 /* Done? */
2524 if (next_fnum < 0)
2525 break;
2526 /* Check if the buffer still exists. */
2527 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2528 if (buf->b_fnum == next_fnum)
2529 break;
2530 if (buf == NULL)
2531 break;
2533 /* Go to the next buffer. Clear 'shm' to avoid that the file
2534 * message overwrites any output from the command. */
2535 p_shm_save = vim_strsave(p_shm);
2536 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
2537 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
2538 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2539 vim_free(p_shm_save);
2541 /* If autocommands took us elsewhere, quit here */
2542 if (curbuf->b_fnum != next_fnum)
2543 break;
2546 if (eap->cmdidx == CMD_windo)
2548 validate_cursor(); /* cursor may have moved */
2549 #ifdef FEAT_SCROLLBIND
2550 /* required when 'scrollbind' has been set */
2551 if (curwin->w_p_scb)
2552 do_check_scrollbind(TRUE);
2553 #endif
2556 listcmd_busy = FALSE;
2559 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2560 if (save_ei != NULL)
2562 au_event_restore(save_ei);
2563 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2564 curbuf->b_fname, TRUE, curbuf);
2566 #endif
2570 * Add files[count] to the arglist of the current window after arg "after".
2571 * The file names in files[count] must have been allocated and are taken over.
2572 * Files[] itself is not taken over.
2573 * Returns index of first added argument. Returns -1 when failed (out of mem).
2575 static int
2576 alist_add_list(count, files, after)
2577 int count;
2578 char_u **files;
2579 int after; /* where to add: 0 = before first one */
2581 int i;
2583 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2585 if (after < 0)
2586 after = 0;
2587 if (after > ARGCOUNT)
2588 after = ARGCOUNT;
2589 if (after < ARGCOUNT)
2590 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2591 (ARGCOUNT - after) * sizeof(aentry_T));
2592 for (i = 0; i < count; ++i)
2594 ARGLIST[after + i].ae_fname = files[i];
2595 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2597 ALIST(curwin)->al_ga.ga_len += count;
2598 if (curwin->w_arg_idx >= after)
2599 ++curwin->w_arg_idx;
2600 return after;
2603 for (i = 0; i < count; ++i)
2604 vim_free(files[i]);
2605 return -1;
2608 #endif /* FEAT_LISTCMDS */
2610 #ifdef FEAT_EVAL
2612 * ":compiler[!] {name}"
2614 void
2615 ex_compiler(eap)
2616 exarg_T *eap;
2618 char_u *buf;
2619 char_u *old_cur_comp = NULL;
2620 char_u *p;
2622 if (*eap->arg == NUL)
2624 /* List all compiler scripts. */
2625 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2626 /* ) keep the indenter happy... */
2628 else
2630 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2631 if (buf != NULL)
2633 if (eap->forceit)
2635 /* ":compiler! {name}" sets global options */
2636 do_cmdline_cmd((char_u *)
2637 "command -nargs=* CompilerSet set <args>");
2639 else
2641 /* ":compiler! {name}" sets local options.
2642 * To remain backwards compatible "current_compiler" is always
2643 * used. A user's compiler plugin may set it, the distributed
2644 * plugin will then skip the settings. Afterwards set
2645 * "b:current_compiler" and restore "current_compiler".
2646 * Explicitly prepend "g:" to make it work in a function. */
2647 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
2648 if (old_cur_comp != NULL)
2649 old_cur_comp = vim_strsave(old_cur_comp);
2650 do_cmdline_cmd((char_u *)
2651 "command -nargs=* CompilerSet setlocal <args>");
2653 do_unlet((char_u *)"g:current_compiler", TRUE);
2654 do_unlet((char_u *)"b:current_compiler", TRUE);
2656 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
2657 if (source_runtime(buf, TRUE) == FAIL)
2658 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2659 vim_free(buf);
2661 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2663 /* Set "b:current_compiler" from "current_compiler". */
2664 p = get_var_value((char_u *)"g:current_compiler");
2665 if (p != NULL)
2666 set_internal_string_var((char_u *)"b:current_compiler", p);
2668 /* Restore "current_compiler" for ":compiler {name}". */
2669 if (!eap->forceit)
2671 if (old_cur_comp != NULL)
2673 set_internal_string_var((char_u *)"g:current_compiler",
2674 old_cur_comp);
2675 vim_free(old_cur_comp);
2677 else
2678 do_unlet((char_u *)"g:current_compiler", TRUE);
2683 #endif
2686 * ":runtime {name}"
2688 void
2689 ex_runtime(eap)
2690 exarg_T *eap;
2692 source_runtime(eap->arg, eap->forceit);
2695 static void source_callback __ARGS((char_u *fname, void *cookie));
2697 static void
2698 source_callback(fname, cookie)
2699 char_u *fname;
2700 void *cookie UNUSED;
2702 (void)do_source(fname, FALSE, DOSO_NONE);
2706 * Source the file "name" from all directories in 'runtimepath'.
2707 * "name" can contain wildcards.
2708 * When "all" is TRUE, source all files, otherwise only the first one.
2709 * return FAIL when no file could be sourced, OK otherwise.
2712 source_runtime(name, all)
2713 char_u *name;
2714 int all;
2716 return do_in_runtimepath(name, all, source_callback, NULL);
2720 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2721 * it: callback(fname, "cookie")
2722 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2723 * used.
2724 * Returns OK when at least one match found, FAIL otherwise.
2727 do_in_runtimepath(name, all, callback, cookie)
2728 char_u *name;
2729 int all;
2730 void (*callback)__ARGS((char_u *fname, void *ck));
2731 void *cookie;
2733 char_u *rtp;
2734 char_u *np;
2735 char_u *buf;
2736 char_u *rtp_copy;
2737 char_u *tail;
2738 int num_files;
2739 char_u **files;
2740 int i;
2741 int did_one = FALSE;
2742 #ifdef AMIGA
2743 struct Process *proc = (struct Process *)FindTask(0L);
2744 APTR save_winptr = proc->pr_WindowPtr;
2746 /* Avoid a requester here for a volume that doesn't exist. */
2747 proc->pr_WindowPtr = (APTR)-1L;
2748 #endif
2750 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2751 * value. */
2752 rtp_copy = vim_strsave(p_rtp);
2753 buf = alloc(MAXPATHL);
2754 if (buf != NULL && rtp_copy != NULL)
2756 if (p_verbose > 1)
2758 verbose_enter();
2759 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
2760 (char *)name, (char *)p_rtp);
2761 verbose_leave();
2764 /* Loop over all entries in 'runtimepath'. */
2765 rtp = rtp_copy;
2766 while (*rtp != NUL && (all || !did_one))
2768 /* Copy the path from 'runtimepath' to buf[]. */
2769 copy_option_part(&rtp, buf, MAXPATHL, ",");
2770 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2772 add_pathsep(buf);
2773 tail = buf + STRLEN(buf);
2775 /* Loop over all patterns in "name" */
2776 np = name;
2777 while (*np != NUL && (all || !did_one))
2779 /* Append the pattern from "name" to buf[]. */
2780 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2781 "\t ");
2783 if (p_verbose > 2)
2785 verbose_enter();
2786 smsg((char_u *)_("Searching for \"%s\""), buf);
2787 verbose_leave();
2790 /* Expand wildcards, invoke the callback for each match. */
2791 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2792 EW_FILE) == OK)
2794 for (i = 0; i < num_files; ++i)
2796 (*callback)(files[i], cookie);
2797 did_one = TRUE;
2798 if (!all)
2799 break;
2801 FreeWild(num_files, files);
2807 vim_free(buf);
2808 vim_free(rtp_copy);
2809 if (p_verbose > 0 && !did_one)
2811 verbose_enter();
2812 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
2813 verbose_leave();
2816 #ifdef AMIGA
2817 proc->pr_WindowPtr = save_winptr;
2818 #endif
2820 return did_one ? OK : FAIL;
2823 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2825 * ":options"
2827 void
2828 ex_options(eap)
2829 exarg_T *eap UNUSED;
2831 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2833 #endif
2836 * ":source {fname}"
2838 void
2839 ex_source(eap)
2840 exarg_T *eap;
2842 #ifdef FEAT_BROWSE
2843 if (cmdmod.browse)
2845 char_u *fname = NULL;
2847 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
2848 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2849 if (fname != NULL)
2851 cmd_source(fname, eap);
2852 vim_free(fname);
2855 else
2856 #endif
2857 cmd_source(eap->arg, eap);
2860 static void
2861 cmd_source(fname, eap)
2862 char_u *fname;
2863 exarg_T *eap;
2865 if (*fname == NUL)
2866 EMSG(_(e_argreq));
2868 else if (eap != NULL && eap->forceit)
2869 /* ":source!": read Normal mdoe commands
2870 * Need to execute the commands directly. This is required at least
2871 * for:
2872 * - ":g" command busy
2873 * - after ":argdo", ":windo" or ":bufdo"
2874 * - another command follows
2875 * - inside a loop
2877 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2878 #ifdef FEAT_EVAL
2879 || eap->cstack->cs_idx >= 0
2880 #endif
2883 /* ":source" read ex commands */
2884 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
2885 EMSG2(_(e_notopen), fname);
2889 * ":source" and associated commands.
2892 * Structure used to store info for each sourced file.
2893 * It is shared between do_source() and getsourceline().
2894 * This is required, because it needs to be handed to do_cmdline() and
2895 * sourcing can be done recursively.
2897 struct source_cookie
2899 FILE *fp; /* opened file for sourcing */
2900 char_u *nextline; /* if not NULL: line that was read ahead */
2901 int finished; /* ":finish" used */
2902 #if defined (USE_CRNL) || defined (USE_CR)
2903 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2904 int error; /* TRUE if LF found after CR-LF */
2905 #endif
2906 #ifdef FEAT_EVAL
2907 linenr_T breakpoint; /* next line with breakpoint or zero */
2908 char_u *fname; /* name of sourced file */
2909 int dbg_tick; /* debug_tick when breakpoint was set */
2910 int level; /* top nesting level of sourced file */
2911 #endif
2912 #ifdef FEAT_MBYTE
2913 vimconv_T conv; /* type of conversion */
2914 #endif
2917 #ifdef FEAT_EVAL
2919 * Return the address holding the next breakpoint line for a source cookie.
2921 linenr_T *
2922 source_breakpoint(cookie)
2923 void *cookie;
2925 return &((struct source_cookie *)cookie)->breakpoint;
2929 * Return the address holding the debug tick for a source cookie.
2931 int *
2932 source_dbg_tick(cookie)
2933 void *cookie;
2935 return &((struct source_cookie *)cookie)->dbg_tick;
2939 * Return the nesting level for a source cookie.
2942 source_level(cookie)
2943 void *cookie;
2945 return ((struct source_cookie *)cookie)->level;
2947 #endif
2949 static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2951 #if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2952 # define USE_FOPEN_NOINH
2953 static FILE *fopen_noinh_readbin __ARGS((char *filename));
2956 * Special function to open a file without handle inheritance.
2957 * When possible the handle is closed on exec().
2959 static FILE *
2960 fopen_noinh_readbin(filename)
2961 char *filename;
2963 # ifdef WIN32
2964 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2965 # else
2966 int fd_tmp = mch_open(filename, O_RDONLY, 0);
2967 # endif
2969 if (fd_tmp == -1)
2970 return NULL;
2972 # ifdef HAVE_FD_CLOEXEC
2974 int fdflags = fcntl(fd_tmp, F_GETFD);
2975 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
2976 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
2978 # endif
2980 return fdopen(fd_tmp, READBIN);
2982 #endif
2986 * do_source: Read the file "fname" and execute its lines as EX commands.
2988 * This function may be called recursively!
2990 * return FAIL if file could not be opened, OK otherwise
2993 do_source(fname, check_other, is_vimrc)
2994 char_u *fname;
2995 int check_other; /* check for .vimrc and _vimrc */
2996 int is_vimrc; /* DOSO_ value */
2998 struct source_cookie cookie;
2999 char_u *save_sourcing_name;
3000 linenr_T save_sourcing_lnum;
3001 char_u *p;
3002 char_u *fname_exp;
3003 char_u *firstline = NULL;
3004 int retval = FAIL;
3005 #ifdef FEAT_EVAL
3006 scid_T save_current_SID;
3007 static scid_T last_current_SID = 0;
3008 void *save_funccalp;
3009 int save_debug_break_level = debug_break_level;
3010 scriptitem_T *si = NULL;
3011 # ifdef UNIX
3012 struct stat st;
3013 int stat_ok;
3014 # endif
3015 #endif
3016 #ifdef STARTUPTIME
3017 struct timeval tv_rel;
3018 struct timeval tv_start;
3019 #endif
3020 #ifdef FEAT_PROFILE
3021 proftime_T wait_start;
3022 #endif
3024 #ifdef RISCOS
3025 p = mch_munge_fname(fname);
3026 #else
3027 p = expand_env_save(fname);
3028 #endif
3029 if (p == NULL)
3030 return retval;
3031 fname_exp = fix_fname(p);
3032 vim_free(p);
3033 if (fname_exp == NULL)
3034 return retval;
3035 if (mch_isdir(fname_exp))
3037 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
3038 goto theend;
3041 #ifdef FEAT_AUTOCMD
3042 /* Apply SourceCmd autocommands, they should get the file and source it. */
3043 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3044 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3045 FALSE, curbuf))
3047 # ifdef FEAT_EVAL
3048 retval = aborting() ? FAIL : OK;
3049 # else
3050 retval = OK;
3051 # endif
3052 goto theend;
3055 /* Apply SourcePre autocommands, they may get the file. */
3056 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3057 #endif
3059 #ifdef USE_FOPEN_NOINH
3060 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3061 #else
3062 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3063 #endif
3064 if (cookie.fp == NULL && check_other)
3067 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3068 * and ".exrc" by "_exrc" or vice versa.
3070 p = gettail(fname_exp);
3071 if ((*p == '.' || *p == '_')
3072 && (STRICMP(p + 1, "vimrc") == 0
3073 || STRICMP(p + 1, "gvimrc") == 0
3074 || STRICMP(p + 1, "exrc") == 0))
3076 if (*p == '_')
3077 *p = '.';
3078 else
3079 *p = '_';
3080 #ifdef USE_FOPEN_NOINH
3081 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3082 #else
3083 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3084 #endif
3088 if (cookie.fp == NULL)
3090 if (p_verbose > 0)
3092 verbose_enter();
3093 if (sourcing_name == NULL)
3094 smsg((char_u *)_("could not source \"%s\""), fname);
3095 else
3096 smsg((char_u *)_("line %ld: could not source \"%s\""),
3097 sourcing_lnum, fname);
3098 verbose_leave();
3100 goto theend;
3104 * The file exists.
3105 * - In verbose mode, give a message.
3106 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3108 if (p_verbose > 1)
3110 verbose_enter();
3111 if (sourcing_name == NULL)
3112 smsg((char_u *)_("sourcing \"%s\""), fname);
3113 else
3114 smsg((char_u *)_("line %ld: sourcing \"%s\""),
3115 sourcing_lnum, fname);
3116 verbose_leave();
3118 if (is_vimrc == DOSO_VIMRC)
3119 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3120 else if (is_vimrc == DOSO_GVIMRC)
3121 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
3123 #ifdef USE_CRNL
3124 /* If no automatic file format: Set default to CR-NL. */
3125 if (*p_ffs == NUL)
3126 cookie.fileformat = EOL_DOS;
3127 else
3128 cookie.fileformat = EOL_UNKNOWN;
3129 cookie.error = FALSE;
3130 #endif
3132 #ifdef USE_CR
3133 /* If no automatic file format: Set default to CR. */
3134 if (*p_ffs == NUL)
3135 cookie.fileformat = EOL_MAC;
3136 else
3137 cookie.fileformat = EOL_UNKNOWN;
3138 cookie.error = FALSE;
3139 #endif
3141 cookie.nextline = NULL;
3142 cookie.finished = FALSE;
3144 #ifdef FEAT_EVAL
3146 * Check if this script has a breakpoint.
3148 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3149 cookie.fname = fname_exp;
3150 cookie.dbg_tick = debug_tick;
3152 cookie.level = ex_nesting_level;
3153 #endif
3156 * Keep the sourcing name/lnum, for recursive calls.
3158 save_sourcing_name = sourcing_name;
3159 sourcing_name = fname_exp;
3160 save_sourcing_lnum = sourcing_lnum;
3161 sourcing_lnum = 0;
3163 #ifdef FEAT_MBYTE
3164 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3166 /* Read the first line so we can check for a UTF-8 BOM. */
3167 firstline = getsourceline(0, (void *)&cookie, 0);
3168 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3169 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3171 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3172 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3173 p = string_convert(&cookie.conv, firstline + 3, NULL);
3174 if (p == NULL)
3175 p = vim_strsave(firstline + 3);
3176 if (p != NULL)
3178 vim_free(firstline);
3179 firstline = p;
3182 #endif
3184 #ifdef STARTUPTIME
3185 if (time_fd != NULL)
3186 time_push(&tv_rel, &tv_start);
3187 #endif
3189 #ifdef FEAT_EVAL
3190 # ifdef FEAT_PROFILE
3191 if (do_profiling == PROF_YES)
3192 prof_child_enter(&wait_start); /* entering a child now */
3193 # endif
3195 /* Don't use local function variables, if called from a function.
3196 * Also starts profiling timer for nested script. */
3197 save_funccalp = save_funccal();
3200 * Check if this script was sourced before to finds its SID.
3201 * If it's new, generate a new SID.
3203 save_current_SID = current_SID;
3204 # ifdef UNIX
3205 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3206 # endif
3207 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3209 si = &SCRIPT_ITEM(current_SID);
3210 if (si->sn_name != NULL
3211 && (
3212 # ifdef UNIX
3213 /* Compare dev/ino when possible, it catches symbolic
3214 * links. Also compare file names, the inode may change
3215 * when the file was edited. */
3216 ((stat_ok && si->sn_dev_valid)
3217 && (si->sn_dev == st.st_dev
3218 && si->sn_ino == st.st_ino)) ||
3219 # endif
3220 fnamecmp(si->sn_name, fname_exp) == 0))
3221 break;
3223 if (current_SID == 0)
3225 current_SID = ++last_current_SID;
3226 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3227 == FAIL)
3228 goto almosttheend;
3229 while (script_items.ga_len < current_SID)
3231 ++script_items.ga_len;
3232 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3233 # ifdef FEAT_PROFILE
3234 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
3235 # endif
3237 si = &SCRIPT_ITEM(current_SID);
3238 si->sn_name = fname_exp;
3239 fname_exp = NULL;
3240 # ifdef UNIX
3241 if (stat_ok)
3243 si->sn_dev_valid = TRUE;
3244 si->sn_dev = st.st_dev;
3245 si->sn_ino = st.st_ino;
3247 else
3248 si->sn_dev_valid = FALSE;
3249 # endif
3251 /* Allocate the local script variables to use for this script. */
3252 new_script_vars(current_SID);
3255 # ifdef FEAT_PROFILE
3256 if (do_profiling == PROF_YES)
3258 int forceit;
3260 /* Check if we do profiling for this script. */
3261 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3263 script_do_profile(si);
3264 si->sn_pr_force = forceit;
3266 if (si->sn_prof_on)
3268 ++si->sn_pr_count;
3269 profile_start(&si->sn_pr_start);
3270 profile_zero(&si->sn_pr_children);
3273 # endif
3274 #endif
3277 * Call do_cmdline, which will call getsourceline() to get the lines.
3279 do_cmdline(firstline, getsourceline, (void *)&cookie,
3280 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
3281 retval = OK;
3283 #ifdef FEAT_PROFILE
3284 if (do_profiling == PROF_YES)
3286 /* Get "si" again, "script_items" may have been reallocated. */
3287 si = &SCRIPT_ITEM(current_SID);
3288 if (si->sn_prof_on)
3290 profile_end(&si->sn_pr_start);
3291 profile_sub_wait(&wait_start, &si->sn_pr_start);
3292 profile_add(&si->sn_pr_total, &si->sn_pr_start);
3293 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3294 &si->sn_pr_children);
3297 #endif
3299 if (got_int)
3300 EMSG(_(e_interr));
3301 sourcing_name = save_sourcing_name;
3302 sourcing_lnum = save_sourcing_lnum;
3303 if (p_verbose > 1)
3305 verbose_enter();
3306 smsg((char_u *)_("finished sourcing %s"), fname);
3307 if (sourcing_name != NULL)
3308 smsg((char_u *)_("continuing in %s"), sourcing_name);
3309 verbose_leave();
3311 #ifdef STARTUPTIME
3312 if (time_fd != NULL)
3314 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3315 time_msg((char *)IObuff, &tv_start);
3316 time_pop(&tv_rel);
3318 #endif
3320 #ifdef FEAT_EVAL
3322 * After a "finish" in debug mode, need to break at first command of next
3323 * sourced file.
3325 if (save_debug_break_level > ex_nesting_level
3326 && debug_break_level == ex_nesting_level)
3327 ++debug_break_level;
3328 #endif
3330 #ifdef FEAT_EVAL
3331 almosttheend:
3332 current_SID = save_current_SID;
3333 restore_funccal(save_funccalp);
3334 # ifdef FEAT_PROFILE
3335 if (do_profiling == PROF_YES)
3336 prof_child_exit(&wait_start); /* leaving a child now */
3337 # endif
3338 #endif
3339 fclose(cookie.fp);
3340 vim_free(cookie.nextline);
3341 vim_free(firstline);
3342 #ifdef FEAT_MBYTE
3343 convert_setup(&cookie.conv, NULL, NULL);
3344 #endif
3346 theend:
3347 vim_free(fname_exp);
3348 return retval;
3351 #if defined(FEAT_EVAL) || defined(PROTO)
3354 * ":scriptnames"
3356 void
3357 ex_scriptnames(eap)
3358 exarg_T *eap UNUSED;
3360 int i;
3362 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3363 if (SCRIPT_ITEM(i).sn_name != NULL)
3364 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
3367 # if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3369 * Fix slashes in the list of script names for 'shellslash'.
3371 void
3372 scriptnames_slash_adjust()
3374 int i;
3376 for (i = 1; i <= script_items.ga_len; ++i)
3377 if (SCRIPT_ITEM(i).sn_name != NULL)
3378 slash_adjust(SCRIPT_ITEM(i).sn_name);
3380 # endif
3383 * Get a pointer to a script name. Used for ":verbose set".
3385 char_u *
3386 get_scriptname(id)
3387 scid_T id;
3389 if (id == SID_MODELINE)
3390 return (char_u *)_("modeline");
3391 if (id == SID_CMDARG)
3392 return (char_u *)_("--cmd argument");
3393 if (id == SID_CARG)
3394 return (char_u *)_("-c argument");
3395 if (id == SID_ENV)
3396 return (char_u *)_("environment variable");
3397 if (id == SID_ERROR)
3398 return (char_u *)_("error handler");
3399 return SCRIPT_ITEM(id).sn_name;
3402 # if defined(EXITFREE) || defined(PROTO)
3403 void
3404 free_scriptnames()
3406 int i;
3408 for (i = script_items.ga_len; i > 0; --i)
3409 vim_free(SCRIPT_ITEM(i).sn_name);
3410 ga_clear(&script_items);
3412 # endif
3414 #endif
3416 #if defined(USE_CR) || defined(PROTO)
3418 # if defined(__MSL__) && (__MSL__ >= 22)
3420 * Newer version of the Metrowerks library handle DOS and UNIX files
3421 * without help.
3422 * Test with earlier versions, MSL 2.2 is the library supplied with
3423 * Codewarrior Pro 2.
3425 char *
3426 fgets_cr(s, n, stream)
3427 char *s;
3428 int n;
3429 FILE *stream;
3431 return fgets(s, n, stream);
3433 # else
3435 * Version of fgets() which also works for lines ending in a <CR> only
3436 * (Macintosh format).
3437 * For older versions of the Metrowerks library.
3438 * At least CodeWarrior 9 needed this code.
3440 char *
3441 fgets_cr(s, n, stream)
3442 char *s;
3443 int n;
3444 FILE *stream;
3446 int c = 0;
3447 int char_read = 0;
3449 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3451 c = fgetc(stream);
3452 s[char_read++] = c;
3453 /* If the file is in DOS format, we need to skip a NL after a CR. I
3454 * thought it was the other way around, but this appears to work... */
3455 if (c == '\n')
3457 c = fgetc(stream);
3458 if (c != '\r')
3459 ungetc(c, stream);
3463 s[char_read] = 0;
3464 if (char_read == 0)
3465 return NULL;
3467 if (feof(stream) && char_read == 1)
3468 return NULL;
3470 return s;
3472 # endif
3473 #endif
3476 * Get one full line from a sourced file.
3477 * Called by do_cmdline() when it's called from do_source().
3479 * Return a pointer to the line in allocated memory.
3480 * Return NULL for end-of-file or some error.
3482 char_u *
3483 getsourceline(c, cookie, indent)
3484 int c UNUSED;
3485 void *cookie;
3486 int indent UNUSED;
3488 struct source_cookie *sp = (struct source_cookie *)cookie;
3489 char_u *line;
3490 char_u *p, *s;
3492 #ifdef FEAT_EVAL
3493 /* If breakpoints have been added/deleted need to check for it. */
3494 if (sp->dbg_tick < debug_tick)
3496 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3497 sp->dbg_tick = debug_tick;
3499 # ifdef FEAT_PROFILE
3500 if (do_profiling == PROF_YES)
3501 script_line_end();
3502 # endif
3503 #endif
3505 * Get current line. If there is a read-ahead line, use it, otherwise get
3506 * one now.
3508 if (sp->finished)
3509 line = NULL;
3510 else if (sp->nextline == NULL)
3511 line = get_one_sourceline(sp);
3512 else
3514 line = sp->nextline;
3515 sp->nextline = NULL;
3516 ++sourcing_lnum;
3518 #ifdef FEAT_PROFILE
3519 if (line != NULL && do_profiling == PROF_YES)
3520 script_line_start();
3521 #endif
3523 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3524 * contain the 'C' flag. */
3525 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3527 /* compensate for the one line read-ahead */
3528 --sourcing_lnum;
3529 for (;;)
3531 sp->nextline = get_one_sourceline(sp);
3532 if (sp->nextline == NULL)
3533 break;
3534 p = skipwhite(sp->nextline);
3535 if (*p != '\\')
3536 break;
3537 s = alloc((unsigned)(STRLEN(line) + STRLEN(p)));
3538 if (s == NULL) /* out of memory */
3539 break;
3540 STRCPY(s, line);
3541 STRCAT(s, p + 1);
3542 vim_free(line);
3543 line = s;
3544 vim_free(sp->nextline);
3548 #ifdef FEAT_MBYTE
3549 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3551 /* Convert the encoding of the script line. */
3552 s = string_convert(&sp->conv, line, NULL);
3553 if (s != NULL)
3555 vim_free(line);
3556 line = s;
3559 #endif
3561 #ifdef FEAT_EVAL
3562 /* Did we encounter a breakpoint? */
3563 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3565 dbg_breakpoint(sp->fname, sourcing_lnum);
3566 /* Find next breakpoint. */
3567 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3568 sp->dbg_tick = debug_tick;
3570 #endif
3572 return line;
3575 static char_u *
3576 get_one_sourceline(sp)
3577 struct source_cookie *sp;
3579 garray_T ga;
3580 int len;
3581 int c;
3582 char_u *buf;
3583 #ifdef USE_CRNL
3584 int has_cr; /* CR-LF found */
3585 #endif
3586 #ifdef USE_CR
3587 char_u *scan;
3588 #endif
3589 int have_read = FALSE;
3591 /* use a growarray to store the sourced line */
3592 ga_init2(&ga, 1, 250);
3595 * Loop until there is a finished line (or end-of-file).
3597 sourcing_lnum++;
3598 for (;;)
3600 /* make room to read at least 120 (more) characters */
3601 if (ga_grow(&ga, 120) == FAIL)
3602 break;
3603 buf = (char_u *)ga.ga_data;
3605 #ifdef USE_CR
3606 if (sp->fileformat == EOL_MAC)
3608 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3609 sp->fp) == NULL)
3610 break;
3612 else
3613 #endif
3614 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3615 sp->fp) == NULL)
3616 break;
3617 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
3618 #ifdef USE_CRNL
3619 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3620 * CTRL-Z by its own, or after a NL. */
3621 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3622 && sp->fileformat == EOL_DOS
3623 && buf[len - 1] == Ctrl_Z)
3625 buf[len - 1] = NUL;
3626 break;
3628 #endif
3630 #ifdef USE_CR
3631 /* If the read doesn't stop on a new line, and there's
3632 * some CR then we assume a Mac format */
3633 if (sp->fileformat == EOL_UNKNOWN)
3635 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3636 sp->fileformat = EOL_MAC;
3637 else
3638 sp->fileformat = EOL_UNIX;
3641 if (sp->fileformat == EOL_MAC)
3643 scan = vim_strchr(buf, '\r');
3645 if (scan != NULL)
3647 *scan = '\n';
3648 if (*(scan + 1) != 0)
3650 *(scan + 1) = 0;
3651 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3654 len = STRLEN(buf);
3656 #endif
3658 have_read = TRUE;
3659 ga.ga_len = len;
3661 /* If the line was longer than the buffer, read more. */
3662 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
3663 continue;
3665 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3667 #ifdef USE_CRNL
3668 has_cr = (len >= 2 && buf[len - 2] == '\r');
3669 if (sp->fileformat == EOL_UNKNOWN)
3671 if (has_cr)
3672 sp->fileformat = EOL_DOS;
3673 else
3674 sp->fileformat = EOL_UNIX;
3677 if (sp->fileformat == EOL_DOS)
3679 if (has_cr) /* replace trailing CR */
3681 buf[len - 2] = '\n';
3682 --len;
3683 --ga.ga_len;
3685 else /* lines like ":map xx yy^M" will have failed */
3687 if (!sp->error)
3689 msg_source(hl_attr(HLF_W));
3690 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
3692 sp->error = TRUE;
3693 sp->fileformat = EOL_UNIX;
3696 #endif
3697 /* The '\n' is escaped if there is an odd number of ^V's just
3698 * before it, first set "c" just before the 'V's and then check
3699 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3700 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3702 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3704 sourcing_lnum++;
3705 continue;
3708 buf[len - 1] = NUL; /* remove the NL */
3712 * Check for ^C here now and then, so recursive :so can be broken.
3714 line_breakcheck();
3715 break;
3718 if (have_read)
3719 return (char_u *)ga.ga_data;
3721 vim_free(ga.ga_data);
3722 return NULL;
3725 #if defined(FEAT_PROFILE) || defined(PROTO)
3727 * Called when starting to read a script line.
3728 * "sourcing_lnum" must be correct!
3729 * When skipping lines it may not actually be executed, but we won't find out
3730 * until later and we need to store the time now.
3732 void
3733 script_line_start()
3735 scriptitem_T *si;
3736 sn_prl_T *pp;
3738 if (current_SID <= 0 || current_SID > script_items.ga_len)
3739 return;
3740 si = &SCRIPT_ITEM(current_SID);
3741 if (si->sn_prof_on && sourcing_lnum >= 1)
3743 /* Grow the array before starting the timer, so that the time spent
3744 * here isn't counted. */
3745 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3746 si->sn_prl_idx = sourcing_lnum - 1;
3747 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3748 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3750 /* Zero counters for a line that was not used before. */
3751 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3752 pp->snp_count = 0;
3753 profile_zero(&pp->sn_prl_total);
3754 profile_zero(&pp->sn_prl_self);
3755 ++si->sn_prl_ga.ga_len;
3757 si->sn_prl_execed = FALSE;
3758 profile_start(&si->sn_prl_start);
3759 profile_zero(&si->sn_prl_children);
3760 profile_get_wait(&si->sn_prl_wait);
3765 * Called when actually executing a function line.
3767 void
3768 script_line_exec()
3770 scriptitem_T *si;
3772 if (current_SID <= 0 || current_SID > script_items.ga_len)
3773 return;
3774 si = &SCRIPT_ITEM(current_SID);
3775 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3776 si->sn_prl_execed = TRUE;
3780 * Called when done with a function line.
3782 void
3783 script_line_end()
3785 scriptitem_T *si;
3786 sn_prl_T *pp;
3788 if (current_SID <= 0 || current_SID > script_items.ga_len)
3789 return;
3790 si = &SCRIPT_ITEM(current_SID);
3791 if (si->sn_prof_on && si->sn_prl_idx >= 0
3792 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3794 if (si->sn_prl_execed)
3796 pp = &PRL_ITEM(si, si->sn_prl_idx);
3797 ++pp->snp_count;
3798 profile_end(&si->sn_prl_start);
3799 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
3800 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
3801 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3802 &si->sn_prl_children);
3804 si->sn_prl_idx = -1;
3807 #endif
3810 * ":scriptencoding": Set encoding conversion for a sourced script.
3811 * Without the multi-byte feature it's simply ignored.
3813 void
3814 ex_scriptencoding(eap)
3815 exarg_T *eap UNUSED;
3817 #ifdef FEAT_MBYTE
3818 struct source_cookie *sp;
3819 char_u *name;
3821 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3823 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3824 return;
3827 if (*eap->arg != NUL)
3829 name = enc_canonize(eap->arg);
3830 if (name == NULL) /* out of memory */
3831 return;
3833 else
3834 name = eap->arg;
3836 /* Setup for conversion from the specified encoding to 'encoding'. */
3837 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3838 convert_setup(&sp->conv, name, p_enc);
3840 if (name != eap->arg)
3841 vim_free(name);
3842 #endif
3845 #if defined(FEAT_EVAL) || defined(PROTO)
3847 * ":finish": Mark a sourced file as finished.
3849 void
3850 ex_finish(eap)
3851 exarg_T *eap;
3853 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3854 do_finish(eap, FALSE);
3855 else
3856 EMSG(_("E168: :finish used outside of a sourced file"));
3860 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3861 * Also called for a pending finish at the ":endtry" or after returning from
3862 * an extra do_cmdline(). "reanimate" is used in the latter case.
3864 void
3865 do_finish(eap, reanimate)
3866 exarg_T *eap;
3867 int reanimate;
3869 int idx;
3871 if (reanimate)
3872 ((struct source_cookie *)getline_cookie(eap->getline,
3873 eap->cookie))->finished = FALSE;
3876 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3877 * not in its finally clause (which then is to be executed next) is found.
3878 * In this case, make the ":finish" pending for execution at the ":endtry".
3879 * Otherwise, finish normally.
3881 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3882 if (idx >= 0)
3884 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3885 report_make_pending(CSTP_FINISH, NULL);
3887 else
3888 ((struct source_cookie *)getline_cookie(eap->getline,
3889 eap->cookie))->finished = TRUE;
3894 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3895 * message for missing ":endif".
3896 * Return FALSE when not sourcing a file.
3899 source_finished(fgetline, cookie)
3900 char_u *(*fgetline) __ARGS((int, void *, int));
3901 void *cookie;
3903 return (getline_equal(fgetline, cookie, getsourceline)
3904 && ((struct source_cookie *)getline_cookie(
3905 fgetline, cookie))->finished);
3907 #endif
3909 #if defined(FEAT_LISTCMDS) || defined(PROTO)
3911 * ":checktime [buffer]"
3913 void
3914 ex_checktime(eap)
3915 exarg_T *eap;
3917 buf_T *buf;
3918 int save_no_check_timestamps = no_check_timestamps;
3920 no_check_timestamps = 0;
3921 if (eap->addr_count == 0) /* default is all buffers */
3922 check_timestamps(FALSE);
3923 else
3925 buf = buflist_findnr((int)eap->line2);
3926 if (buf != NULL) /* cannot happen? */
3927 (void)buf_check_timestamp(buf, FALSE);
3929 no_check_timestamps = save_no_check_timestamps;
3931 #endif
3933 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3934 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3935 static char *get_locale_val __ARGS((int what));
3937 static char *
3938 get_locale_val(what)
3939 int what;
3941 char *loc;
3943 /* Obtain the locale value from the libraries. For DJGPP this is
3944 * redefined and it doesn't use the arguments. */
3945 loc = setlocale(what, NULL);
3947 # ifdef WIN32
3948 if (loc != NULL)
3950 char_u *p;
3952 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3953 * one of the values (e.g., LC_CTYPE) differs. */
3954 p = vim_strchr(loc, '=');
3955 if (p != NULL)
3957 loc = ++p;
3958 while (*p != NUL) /* remove trailing newline */
3960 if (*p < ' ' || *p == ';')
3962 *p = NUL;
3963 break;
3965 ++p;
3969 # endif
3971 return loc;
3973 #endif
3976 #ifdef WIN32
3978 * On MS-Windows locale names are strings like "German_Germany.1252", but
3979 * gettext expects "de". Try to translate one into another here for a few
3980 * supported languages.
3982 static char_u *
3983 gettext_lang(char_u *name)
3985 int i;
3986 static char *(mtable[]) = {
3987 "afrikaans", "af",
3988 "czech", "cs",
3989 "dutch", "nl",
3990 "german", "de",
3991 "english_united kingdom", "en_GB",
3992 "spanish", "es",
3993 "french", "fr",
3994 "italian", "it",
3995 "japanese", "ja",
3996 "korean", "ko",
3997 "norwegian", "no",
3998 "polish", "pl",
3999 "russian", "ru",
4000 "slovak", "sk",
4001 "swedish", "sv",
4002 "ukrainian", "uk",
4003 "chinese_china", "zh_CN",
4004 "chinese_taiwan", "zh_TW",
4005 NULL};
4007 for (i = 0; mtable[i] != NULL; i += 2)
4008 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4009 return mtable[i + 1];
4010 return name;
4012 #endif
4014 #if defined(FEAT_MULTI_LANG) || defined(PROTO)
4016 * Obtain the current messages language. Used to set the default for
4017 * 'helplang'. May return NULL or an empty string.
4019 char_u *
4020 get_mess_lang()
4022 char_u *p;
4024 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
4025 # if defined(LC_MESSAGES)
4026 p = (char_u *)get_locale_val(LC_MESSAGES);
4027 # else
4028 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
4029 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4030 * and LC_MONETARY may be set differently for a Japanese working in the
4031 * US. */
4032 p = (char_u *)get_locale_val(LC_COLLATE);
4033 # endif
4034 # else
4035 p = mch_getenv((char_u *)"LC_ALL");
4036 if (p == NULL || *p == NUL)
4038 p = mch_getenv((char_u *)"LC_MESSAGES");
4039 if (p == NULL || *p == NUL)
4040 p = mch_getenv((char_u *)"LANG");
4042 # endif
4043 # ifdef WIN32
4044 p = gettext_lang(p);
4045 # endif
4046 return p;
4048 #endif
4050 /* Complicated #if; matches with where get_mess_env() is used below. */
4051 #if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4052 && defined(LC_MESSAGES))) \
4053 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4054 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4055 && !defined(LC_MESSAGES))
4056 static char_u *get_mess_env __ARGS((void));
4059 * Get the language used for messages from the environment.
4061 static char_u *
4062 get_mess_env()
4064 char_u *p;
4066 p = mch_getenv((char_u *)"LC_ALL");
4067 if (p == NULL || *p == NUL)
4069 p = mch_getenv((char_u *)"LC_MESSAGES");
4070 if (p == NULL || *p == NUL)
4072 p = mch_getenv((char_u *)"LANG");
4073 if (p != NULL && VIM_ISDIGIT(*p))
4074 p = NULL; /* ignore something like "1043" */
4075 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4076 if (p == NULL || *p == NUL)
4077 p = (char_u *)get_locale_val(LC_CTYPE);
4078 # endif
4081 return p;
4083 #endif
4085 #if defined(FEAT_EVAL) || defined(PROTO)
4088 * Set the "v:lang" variable according to the current locale setting.
4089 * Also do "v:lc_time"and "v:ctype".
4091 void
4092 set_lang_var()
4094 char_u *loc;
4096 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4097 loc = (char_u *)get_locale_val(LC_CTYPE);
4098 # else
4099 /* setlocale() not supported: use the default value */
4100 loc = (char_u *)"C";
4101 # endif
4102 set_vim_var_string(VV_CTYPE, loc, -1);
4104 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4105 * back to LC_CTYPE if it's empty. */
4106 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
4107 loc = (char_u *)get_locale_val(LC_MESSAGES);
4108 # else
4109 loc = get_mess_env();
4110 # endif
4111 set_vim_var_string(VV_LANG, loc, -1);
4113 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4114 loc = (char_u *)get_locale_val(LC_TIME);
4115 # endif
4116 set_vim_var_string(VV_LC_TIME, loc, -1);
4118 #endif
4120 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4121 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4123 * ":language": Set the language (locale).
4125 void
4126 ex_language(eap)
4127 exarg_T *eap;
4129 char *loc;
4130 char_u *p;
4131 char_u *name;
4132 int what = LC_ALL;
4133 char *whatstr = "";
4134 #ifdef LC_MESSAGES
4135 # define VIM_LC_MESSAGES LC_MESSAGES
4136 #else
4137 # define VIM_LC_MESSAGES 6789
4138 #endif
4140 name = eap->arg;
4142 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4143 * Allow abbreviation, but require at least 3 characters to avoid
4144 * confusion with a two letter language name "me" or "ct". */
4145 p = skiptowhite(eap->arg);
4146 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4148 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4150 what = VIM_LC_MESSAGES;
4151 name = skipwhite(p);
4152 whatstr = "messages ";
4154 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4156 what = LC_CTYPE;
4157 name = skipwhite(p);
4158 whatstr = "ctype ";
4160 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4162 what = LC_TIME;
4163 name = skipwhite(p);
4164 whatstr = "time ";
4168 if (*name == NUL)
4170 #ifndef LC_MESSAGES
4171 if (what == VIM_LC_MESSAGES)
4172 p = get_mess_env();
4173 else
4174 #endif
4175 p = (char_u *)setlocale(what, NULL);
4176 if (p == NULL || *p == NUL)
4177 p = (char_u *)"Unknown";
4178 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4180 else
4182 #ifndef LC_MESSAGES
4183 if (what == VIM_LC_MESSAGES)
4184 loc = "";
4185 else
4186 #endif
4188 loc = setlocale(what, (char *)name);
4189 #if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4190 /* Make sure strtod() uses a decimal point, not a comma. */
4191 setlocale(LC_NUMERIC, "C");
4192 #endif
4194 if (loc == NULL)
4195 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4196 else
4198 #ifdef HAVE_NL_MSG_CAT_CNTR
4199 /* Need to do this for GNU gettext, otherwise cached translations
4200 * will be used again. */
4201 extern int _nl_msg_cat_cntr;
4203 ++_nl_msg_cat_cntr;
4204 #endif
4205 /* Reset $LC_ALL, otherwise it would overrule everything. */
4206 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4208 if (what != LC_TIME)
4210 /* Tell gettext() what to translate to. It apparently doesn't
4211 * use the currently effective locale. Also do this when
4212 * FEAT_GETTEXT isn't defined, so that shell commands use this
4213 * value. */
4214 if (what == LC_ALL)
4216 vim_setenv((char_u *)"LANG", name);
4217 # ifdef WIN32
4218 /* Apparently MS-Windows printf() may cause a crash when
4219 * we give it 8-bit text while it's expecting text in the
4220 * current locale. This call avoids that. */
4221 setlocale(LC_CTYPE, "C");
4222 # endif
4224 if (what != LC_CTYPE)
4226 char_u *mname;
4227 #ifdef WIN32
4228 mname = gettext_lang(name);
4229 #else
4230 mname = name;
4231 #endif
4232 vim_setenv((char_u *)"LC_MESSAGES", mname);
4233 #ifdef FEAT_MULTI_LANG
4234 set_helplang_default(mname);
4235 #endif
4238 /* Set $LC_CTYPE, because it overrules $LANG, and
4239 * gtk_set_locale() calls setlocale() again. gnome_init()
4240 * sets $LC_CTYPE to "en_US" (that's a bug!). */
4241 if (what != VIM_LC_MESSAGES)
4242 vim_setenv((char_u *)"LC_CTYPE", name);
4243 # ifdef FEAT_GUI_GTK
4244 /* Let GTK know what locale we're using. Not sure this is
4245 * really needed... */
4246 if (gui.in_use)
4247 (void)gtk_set_locale();
4248 # endif
4251 # ifdef FEAT_EVAL
4252 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4253 set_lang_var();
4254 # endif
4259 # if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4261 * Function given to ExpandGeneric() to obtain the possible arguments of the
4262 * ":language" command.
4264 char_u *
4265 get_lang_arg(xp, idx)
4266 expand_T *xp UNUSED;
4267 int idx;
4269 if (idx == 0)
4270 return (char_u *)"messages";
4271 if (idx == 1)
4272 return (char_u *)"ctype";
4273 if (idx == 2)
4274 return (char_u *)"time";
4275 return NULL;
4277 # endif
4279 #endif