Dialog sheet animation can no longer cause a crash
[MacVim.git] / src / ex_cmds2.c
blobefb85194d45712100e0406205b4c8cbcfa5d34f6
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);
1119 * Dump the profiling info.
1121 void
1122 profile_dump()
1124 FILE *fd;
1126 if (profile_fname != NULL)
1128 fd = mch_fopen((char *)profile_fname, "w");
1129 if (fd == NULL)
1130 EMSG2(_(e_notopen), profile_fname);
1131 else
1133 script_dump_profile(fd);
1134 func_dump_profile(fd);
1135 fclose(fd);
1141 * Start profiling script "fp".
1143 static void
1144 script_do_profile(si)
1145 scriptitem_T *si;
1147 si->sn_pr_count = 0;
1148 profile_zero(&si->sn_pr_total);
1149 profile_zero(&si->sn_pr_self);
1151 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1152 si->sn_prl_idx = -1;
1153 si->sn_prof_on = TRUE;
1154 si->sn_pr_nest = 0;
1158 * save time when starting to invoke another script or function.
1160 void
1161 script_prof_save(tm)
1162 proftime_T *tm; /* place to store wait time */
1164 scriptitem_T *si;
1166 if (current_SID > 0 && current_SID <= script_items.ga_len)
1168 si = &SCRIPT_ITEM(current_SID);
1169 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1170 profile_start(&si->sn_pr_child);
1172 profile_get_wait(tm);
1176 * Count time spent in children after invoking another script or function.
1178 void
1179 script_prof_restore(tm)
1180 proftime_T *tm;
1182 scriptitem_T *si;
1184 if (current_SID > 0 && current_SID <= script_items.ga_len)
1186 si = &SCRIPT_ITEM(current_SID);
1187 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1189 profile_end(&si->sn_pr_child);
1190 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1191 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1192 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1197 static proftime_T inchar_time;
1200 * Called when starting to wait for the user to type a character.
1202 void
1203 prof_inchar_enter()
1205 profile_start(&inchar_time);
1209 * Called when finished waiting for the user to type a character.
1211 void
1212 prof_inchar_exit()
1214 profile_end(&inchar_time);
1215 profile_add(&prof_wait_time, &inchar_time);
1219 * Dump the profiling results for all scripts in file "fd".
1221 static void
1222 script_dump_profile(fd)
1223 FILE *fd;
1225 int id;
1226 scriptitem_T *si;
1227 int i;
1228 FILE *sfd;
1229 sn_prl_T *pp;
1231 for (id = 1; id <= script_items.ga_len; ++id)
1233 si = &SCRIPT_ITEM(id);
1234 if (si->sn_prof_on)
1236 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1237 if (si->sn_pr_count == 1)
1238 fprintf(fd, "Sourced 1 time\n");
1239 else
1240 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1241 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1242 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1243 fprintf(fd, "\n");
1244 fprintf(fd, "count total (s) self (s)\n");
1246 sfd = mch_fopen((char *)si->sn_name, "r");
1247 if (sfd == NULL)
1248 fprintf(fd, "Cannot open file!\n");
1249 else
1251 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1253 if (vim_fgets(IObuff, IOSIZE, sfd))
1254 break;
1255 pp = &PRL_ITEM(si, i);
1256 if (pp->snp_count > 0)
1258 fprintf(fd, "%5d ", pp->snp_count);
1259 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1260 fprintf(fd, " ");
1261 else
1262 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1263 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1265 else
1266 fprintf(fd, " ");
1267 fprintf(fd, "%s", IObuff);
1269 fclose(sfd);
1271 fprintf(fd, "\n");
1277 * Return TRUE when a function defined in the current script should be
1278 * profiled.
1281 prof_def_func()
1283 if (current_SID > 0)
1284 return SCRIPT_ITEM(current_SID).sn_pr_force;
1285 return FALSE;
1288 # endif
1289 #endif
1292 * If 'autowrite' option set, try to write the file.
1293 * Careful: autocommands may make "buf" invalid!
1295 * return FAIL for failure, OK otherwise
1298 autowrite(buf, forceit)
1299 buf_T *buf;
1300 int forceit;
1302 int r;
1304 if (!(p_aw || p_awa) || !p_write
1305 #ifdef FEAT_QUICKFIX
1306 /* never autowrite a "nofile" or "nowrite" buffer */
1307 || bt_dontwrite(buf)
1308 #endif
1309 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
1310 return FAIL;
1311 r = buf_write_all(buf, forceit);
1313 /* Writing may succeed but the buffer still changed, e.g., when there is a
1314 * conversion error. We do want to return FAIL then. */
1315 if (buf_valid(buf) && bufIsChanged(buf))
1316 r = FAIL;
1317 return r;
1321 * flush all buffers, except the ones that are readonly
1323 void
1324 autowrite_all()
1326 buf_T *buf;
1328 if (!(p_aw || p_awa) || !p_write)
1329 return;
1330 for (buf = firstbuf; buf; buf = buf->b_next)
1331 if (bufIsChanged(buf) && !buf->b_p_ro)
1333 (void)buf_write_all(buf, FALSE);
1334 #ifdef FEAT_AUTOCMD
1335 /* an autocommand may have deleted the buffer */
1336 if (!buf_valid(buf))
1337 buf = firstbuf;
1338 #endif
1343 * return TRUE if buffer was changed and cannot be abandoned.
1346 check_changed(buf, checkaw, mult_win, forceit, allbuf)
1347 buf_T *buf;
1348 int checkaw; /* do autowrite if buffer was changed */
1349 int mult_win; /* check also when several wins for the buf */
1350 int forceit;
1351 int allbuf UNUSED; /* may write all buffers */
1353 if ( !forceit
1354 && bufIsChanged(buf)
1355 && (mult_win || buf->b_nwindows <= 1)
1356 && (!checkaw || autowrite(buf, forceit) == FAIL))
1358 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1359 if ((p_confirm || cmdmod.confirm) && p_write)
1361 buf_T *buf2;
1362 int count = 0;
1364 if (allbuf)
1365 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1366 if (bufIsChanged(buf2)
1367 && (buf2->b_ffname != NULL
1368 # ifdef FEAT_BROWSE
1369 || cmdmod.browse
1370 # endif
1372 ++count;
1373 # ifdef FEAT_AUTOCMD
1374 if (!buf_valid(buf))
1375 /* Autocommand deleted buffer, oops! It's not changed now. */
1376 return FALSE;
1377 # endif
1378 dialog_changed(buf, count > 1);
1379 # ifdef FEAT_AUTOCMD
1380 if (!buf_valid(buf))
1381 /* Autocommand deleted buffer, oops! It's not changed now. */
1382 return FALSE;
1383 # endif
1384 return bufIsChanged(buf);
1386 #endif
1387 EMSG(_(e_nowrtmsg));
1388 return TRUE;
1390 return FALSE;
1393 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1395 #if defined(FEAT_BROWSE) || defined(PROTO)
1397 * When wanting to write a file without a file name, ask the user for a name.
1399 void
1400 browse_save_fname(buf)
1401 buf_T *buf;
1403 if (buf->b_fname == NULL)
1405 char_u *fname;
1407 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1408 NULL, NULL, NULL, NULL, buf);
1409 if (fname != NULL)
1411 if (setfname(buf, fname, NULL, TRUE) == OK)
1412 buf->b_flags |= BF_NOTEDITED;
1413 vim_free(fname);
1417 #endif
1419 #ifdef FEAT_GUI_MACVIM
1421 * "Save changes" dialog that conforms to the Apple HIG.
1424 vim_dialog_save_changes(buf)
1425 buf_T *buf;
1427 char_u buff[IOSIZE];
1429 dialog_msg(buff, _("Do you want to save the changes you made in the "
1430 "document \"%s\"?"), buf->b_fname);
1431 switch (do_dialog(VIM_QUESTION, buff,
1432 (char_u*) _("Your changes will be lost if you don't save "
1433 "them."),
1434 (buf->b_fname != NULL)
1435 ? (char_u *)_("&Save\n&Cancel\n&Don't Save")
1436 : (char_u *)_("&Save...\n&Cancel\n&Don't Save"),
1437 1, NULL))
1439 case 1: return VIM_YES;
1440 case 3: return VIM_NO;
1443 return VIM_CANCEL;
1447 * "Save all changes" dialog that tries to emulate the above "Save changes"
1448 * dialog for the case of several modified buffers.
1451 vim_dialog_save_all_changes(buf)
1452 buf_T *buf;
1454 char_u buff[IOSIZE];
1456 dialog_msg(buff, _("There are several documents with unsaved changes. "
1457 "Do you want to save the changes you made in the "
1458 "document \"%s\"?"), buf->b_fname);
1459 switch (do_dialog(VIM_QUESTION, buff,
1460 (char_u*) _("Your changes will be lost if you don't save "
1461 "them."),
1462 (char_u *)_("&Save\n&Don't Save\nS&ave All\nD&iscard All\n"
1463 "&Cancel"),
1464 1, NULL))
1466 case 1: return VIM_YES;
1467 case 2: return VIM_NO;
1468 case 3: return VIM_ALL;
1469 case 4: return VIM_DISCARDALL;
1472 return VIM_CANCEL;
1474 #endif
1477 * Ask the user what to do when abondoning a changed buffer.
1478 * Must check 'write' option first!
1480 void
1481 dialog_changed(buf, checkall)
1482 buf_T *buf;
1483 int checkall; /* may abandon all changed buffers */
1485 char_u buff[IOSIZE];
1486 int ret;
1487 buf_T *buf2;
1489 #ifdef FEAT_GUI_MACVIM
1490 /* Save dialogs on Mac OS X are standardized so in case the GUI is enabled
1491 * and "c" isn't in 'guioptions' we use a OS X specific dialog. */
1492 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
1494 if (checkall)
1495 ret = vim_dialog_save_all_changes(buf);
1496 else
1497 ret = vim_dialog_save_changes(buf);
1499 else
1501 #endif
1502 dialog_msg(buff, _("Save changes to \"%s\"?"),
1503 (buf->b_fname != NULL) ?
1504 buf->b_fname : (char_u *)_("Untitled"));
1505 if (checkall)
1506 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1507 else
1508 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1509 #ifdef FEAT_GUI_MACVIM
1511 #endif
1513 if (ret == VIM_YES)
1515 #ifdef FEAT_BROWSE
1516 /* May get file name, when there is none */
1517 browse_save_fname(buf);
1518 #endif
1519 if (buf->b_fname != NULL) /* didn't hit Cancel */
1520 (void)buf_write_all(buf, FALSE);
1522 else if (ret == VIM_NO)
1524 unchanged(buf, TRUE);
1526 else if (ret == VIM_ALL)
1529 * Write all modified files that can be written.
1530 * Skip readonly buffers, these need to be confirmed
1531 * individually.
1533 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1535 if (bufIsChanged(buf2)
1536 && (buf2->b_ffname != NULL
1537 #ifdef FEAT_BROWSE
1538 || cmdmod.browse
1539 #endif
1541 && !buf2->b_p_ro)
1543 #ifdef FEAT_BROWSE
1544 /* May get file name, when there is none */
1545 browse_save_fname(buf2);
1546 #endif
1547 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1548 (void)buf_write_all(buf2, FALSE);
1549 #ifdef FEAT_AUTOCMD
1550 /* an autocommand may have deleted the buffer */
1551 if (!buf_valid(buf2))
1552 buf2 = firstbuf;
1553 #endif
1557 else if (ret == VIM_DISCARDALL)
1560 * mark all buffers as unchanged
1562 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1563 unchanged(buf2, TRUE);
1566 #endif
1569 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1570 * hidden, autowriting it or unloading it.
1573 can_abandon(buf, forceit)
1574 buf_T *buf;
1575 int forceit;
1577 return ( P_HID(buf)
1578 || !bufIsChanged(buf)
1579 || buf->b_nwindows > 1
1580 || autowrite(buf, forceit) == OK
1581 || forceit);
1585 * Return TRUE if any buffer was changed and cannot be abandoned.
1586 * That changed buffer becomes the current buffer.
1589 check_changed_any(hidden)
1590 int hidden; /* Only check hidden buffers */
1592 buf_T *buf;
1593 int save;
1594 #ifdef FEAT_WINDOWS
1595 win_T *wp;
1596 #endif
1598 for (;;)
1600 /* check curbuf first: if it was changed we can't abandon it */
1601 if (!hidden && curbufIsChanged())
1602 buf = curbuf;
1603 else
1605 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1606 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1607 break;
1609 if (buf == NULL) /* No buffers changed */
1610 return FALSE;
1612 /* Try auto-writing the buffer. If this fails but the buffer no
1613 * longer exists it's not changed, that's OK. */
1614 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1615 break; /* didn't save - still changes */
1618 exiting = FALSE;
1619 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1621 * When ":confirm" used, don't give an error message.
1623 if (!(p_confirm || cmdmod.confirm))
1624 #endif
1626 /* There must be a wait_return for this message, do_buffer()
1627 * may cause a redraw. But wait_return() is a no-op when vgetc()
1628 * is busy (Quit used from window menu), then make sure we don't
1629 * cause a scroll up. */
1630 if (vgetc_busy > 0)
1632 msg_row = cmdline_row;
1633 msg_col = 0;
1634 msg_didout = FALSE;
1636 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1637 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1638 buf->b_fname))
1640 save = no_wait_return;
1641 no_wait_return = FALSE;
1642 wait_return(FALSE);
1643 no_wait_return = save;
1647 #ifdef FEAT_WINDOWS
1648 /* Try to find a window that contains the buffer. */
1649 if (buf != curbuf)
1650 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1651 if (wp->w_buffer == buf)
1653 win_goto(wp);
1654 # ifdef FEAT_AUTOCMD
1655 /* Paranoia: did autocms wipe out the buffer with changes? */
1656 if (!buf_valid(buf))
1657 return TRUE;
1658 # endif
1659 break;
1661 #endif
1663 /* Open the changed buffer in the current window. */
1664 if (buf != curbuf)
1665 set_curbuf(buf, DOBUF_GOTO);
1667 return TRUE;
1671 * return FAIL if there is no file name, OK if there is one
1672 * give error message for FAIL
1675 check_fname()
1677 if (curbuf->b_ffname == NULL)
1679 EMSG(_(e_noname));
1680 return FAIL;
1682 return OK;
1686 * flush the contents of a buffer, unless it has no file name
1688 * return FAIL for failure, OK otherwise
1691 buf_write_all(buf, forceit)
1692 buf_T *buf;
1693 int forceit;
1695 int retval;
1696 #ifdef FEAT_AUTOCMD
1697 buf_T *old_curbuf = curbuf;
1698 #endif
1700 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1701 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1702 FALSE, forceit, TRUE, FALSE));
1703 #ifdef FEAT_AUTOCMD
1704 if (curbuf != old_curbuf)
1706 msg_source(hl_attr(HLF_W));
1707 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
1709 #endif
1710 return retval;
1714 * Code to handle the argument list.
1717 static char_u *do_one_arg __ARGS((char_u *str));
1718 static int do_arglist __ARGS((char_u *str, int what, int after));
1719 static void alist_check_arg_idx __ARGS((void));
1720 static int editing_arg_idx __ARGS((win_T *win));
1721 #ifdef FEAT_LISTCMDS
1722 static int alist_add_list __ARGS((int count, char_u **files, int after));
1723 #endif
1724 #define AL_SET 1
1725 #define AL_ADD 2
1726 #define AL_DEL 3
1729 * Isolate one argument, taking backticks.
1730 * Changes the argument in-place, puts a NUL after it. Backticks remain.
1731 * Return a pointer to the start of the next argument.
1733 static char_u *
1734 do_one_arg(str)
1735 char_u *str;
1737 char_u *p;
1738 int inbacktick;
1740 inbacktick = FALSE;
1741 for (p = str; *str; ++str)
1743 /* When the backslash is used for escaping the special meaning of a
1744 * character we need to keep it until wildcard expansion. */
1745 if (rem_backslash(str))
1747 *p++ = *str++;
1748 *p++ = *str;
1750 else
1752 /* An item ends at a space not in backticks */
1753 if (!inbacktick && vim_isspace(*str))
1754 break;
1755 if (*str == '`')
1756 inbacktick ^= TRUE;
1757 *p++ = *str;
1760 str = skipwhite(str);
1761 *p = NUL;
1763 return str;
1767 * Separate the arguments in "str" and return a list of pointers in the
1768 * growarray "gap".
1771 get_arglist(gap, str)
1772 garray_T *gap;
1773 char_u *str;
1775 ga_init2(gap, (int)sizeof(char_u *), 20);
1776 while (*str != NUL)
1778 if (ga_grow(gap, 1) == FAIL)
1780 ga_clear(gap);
1781 return FAIL;
1783 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1785 /* Isolate one argument, change it in-place, put a NUL after it. */
1786 str = do_one_arg(str);
1788 return OK;
1791 #if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
1793 * Parse a list of arguments (file names), expand them and return in
1794 * "fnames[fcountp]".
1795 * Return FAIL or OK.
1798 get_arglist_exp(str, fcountp, fnamesp)
1799 char_u *str;
1800 int *fcountp;
1801 char_u ***fnamesp;
1803 garray_T ga;
1804 int i;
1806 if (get_arglist(&ga, str) == FAIL)
1807 return FAIL;
1808 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1809 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1810 ga_clear(&ga);
1811 return i;
1813 #endif
1815 #if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1817 * Redefine the argument list.
1819 void
1820 set_arglist(str)
1821 char_u *str;
1823 do_arglist(str, AL_SET, 0);
1825 #endif
1828 * "what" == AL_SET: Redefine the argument list to 'str'.
1829 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1830 * "what" == AL_DEL: remove files in 'str' from the argument list.
1832 * Return FAIL for failure, OK otherwise.
1834 static int
1835 do_arglist(str, what, after)
1836 char_u *str;
1837 int what UNUSED;
1838 int after UNUSED; /* 0 means before first one */
1840 garray_T new_ga;
1841 int exp_count;
1842 char_u **exp_files;
1843 int i;
1844 #ifdef FEAT_LISTCMDS
1845 char_u *p;
1846 int match;
1847 #endif
1850 * Collect all file name arguments in "new_ga".
1852 if (get_arglist(&new_ga, str) == FAIL)
1853 return FAIL;
1855 #ifdef FEAT_LISTCMDS
1856 if (what == AL_DEL)
1858 regmatch_T regmatch;
1859 int didone;
1862 * Delete the items: use each item as a regexp and find a match in the
1863 * argument list.
1865 #ifdef CASE_INSENSITIVE_FILENAME
1866 regmatch.rm_ic = TRUE; /* Always ignore case */
1867 #else
1868 regmatch.rm_ic = FALSE; /* Never ignore case */
1869 #endif
1870 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1872 p = ((char_u **)new_ga.ga_data)[i];
1873 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1874 if (p == NULL)
1875 break;
1876 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1877 if (regmatch.regprog == NULL)
1879 vim_free(p);
1880 break;
1883 didone = FALSE;
1884 for (match = 0; match < ARGCOUNT; ++match)
1885 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1886 (colnr_T)0))
1888 didone = TRUE;
1889 vim_free(ARGLIST[match].ae_fname);
1890 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1891 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1892 --ALIST(curwin)->al_ga.ga_len;
1893 if (curwin->w_arg_idx > match)
1894 --curwin->w_arg_idx;
1895 --match;
1898 vim_free(regmatch.regprog);
1899 vim_free(p);
1900 if (!didone)
1901 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1903 ga_clear(&new_ga);
1905 else
1906 #endif
1908 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1909 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1910 ga_clear(&new_ga);
1911 if (i == FAIL)
1912 return FAIL;
1913 if (exp_count == 0)
1915 EMSG(_(e_nomatch));
1916 return FAIL;
1919 #ifdef FEAT_LISTCMDS
1920 if (what == AL_ADD)
1922 (void)alist_add_list(exp_count, exp_files, after);
1923 vim_free(exp_files);
1925 else /* what == AL_SET */
1926 #endif
1927 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
1930 alist_check_arg_idx();
1932 return OK;
1936 * Check the validity of the arg_idx for each other window.
1938 static void
1939 alist_check_arg_idx()
1941 #ifdef FEAT_WINDOWS
1942 win_T *win;
1943 tabpage_T *tp;
1945 FOR_ALL_TAB_WINDOWS(tp, win)
1946 if (win->w_alist == curwin->w_alist)
1947 check_arg_idx(win);
1948 #else
1949 check_arg_idx(curwin);
1950 #endif
1954 * Return TRUE if window "win" is editing then file at the current argument
1955 * index.
1957 static int
1958 editing_arg_idx(win)
1959 win_T *win;
1961 return !(win->w_arg_idx >= WARGCOUNT(win)
1962 || (win->w_buffer->b_fnum
1963 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1964 && (win->w_buffer->b_ffname == NULL
1965 || !(fullpathcmp(
1966 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1967 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1971 * Check if window "win" is editing the w_arg_idx file in its argument list.
1973 void
1974 check_arg_idx(win)
1975 win_T *win;
1977 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
1979 /* We are not editing the current entry in the argument list.
1980 * Set "arg_had_last" if we are editing the last one. */
1981 win->w_arg_idx_invalid = TRUE;
1982 if (win->w_arg_idx != WARGCOUNT(win) - 1
1983 && arg_had_last == FALSE
1984 #ifdef FEAT_WINDOWS
1985 && ALIST(win) == &global_alist
1986 #endif
1987 && GARGCOUNT > 0
1988 && win->w_arg_idx < GARGCOUNT
1989 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1990 || (win->w_buffer->b_ffname != NULL
1991 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1992 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1993 arg_had_last = TRUE;
1995 else
1997 /* We are editing the current entry in the argument list.
1998 * Set "arg_had_last" if it's also the last one */
1999 win->w_arg_idx_invalid = FALSE;
2000 if (win->w_arg_idx == WARGCOUNT(win) - 1
2001 #ifdef FEAT_WINDOWS
2002 && win->w_alist == &global_alist
2003 #endif
2005 arg_had_last = TRUE;
2010 * ":args", ":argslocal" and ":argsglobal".
2012 void
2013 ex_args(eap)
2014 exarg_T *eap;
2016 int i;
2018 if (eap->cmdidx != CMD_args)
2020 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2021 alist_unlink(ALIST(curwin));
2022 if (eap->cmdidx == CMD_argglobal)
2023 ALIST(curwin) = &global_alist;
2024 else /* eap->cmdidx == CMD_arglocal */
2025 alist_new();
2026 #else
2027 ex_ni(eap);
2028 return;
2029 #endif
2032 if (!ends_excmd(*eap->arg))
2035 * ":args file ..": define new argument list, handle like ":next"
2036 * Also for ":argslocal file .." and ":argsglobal file ..".
2038 ex_next(eap);
2040 else
2041 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2042 if (eap->cmdidx == CMD_args)
2043 #endif
2046 * ":args": list arguments.
2048 if (ARGCOUNT > 0)
2050 /* Overwrite the command, for a short list there is no scrolling
2051 * required and no wait_return(). */
2052 gotocmdline(TRUE);
2053 for (i = 0; i < ARGCOUNT; ++i)
2055 if (i == curwin->w_arg_idx)
2056 msg_putchar('[');
2057 msg_outtrans(alist_name(&ARGLIST[i]));
2058 if (i == curwin->w_arg_idx)
2059 msg_putchar(']');
2060 msg_putchar(' ');
2064 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2065 else if (eap->cmdidx == CMD_arglocal)
2067 garray_T *gap = &curwin->w_alist->al_ga;
2070 * ":argslocal": make a local copy of the global argument list.
2072 if (ga_grow(gap, GARGCOUNT) == OK)
2073 for (i = 0; i < GARGCOUNT; ++i)
2074 if (GARGLIST[i].ae_fname != NULL)
2076 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2077 vim_strsave(GARGLIST[i].ae_fname);
2078 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2079 GARGLIST[i].ae_fnum;
2080 ++gap->ga_len;
2083 #endif
2087 * ":previous", ":sprevious", ":Next" and ":sNext".
2089 void
2090 ex_previous(eap)
2091 exarg_T *eap;
2093 /* If past the last one already, go to the last one. */
2094 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2095 do_argfile(eap, ARGCOUNT - 1);
2096 else
2097 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2101 * ":rewind", ":first", ":sfirst" and ":srewind".
2103 void
2104 ex_rewind(eap)
2105 exarg_T *eap;
2107 do_argfile(eap, 0);
2111 * ":last" and ":slast".
2113 void
2114 ex_last(eap)
2115 exarg_T *eap;
2117 do_argfile(eap, ARGCOUNT - 1);
2121 * ":argument" and ":sargument".
2123 void
2124 ex_argument(eap)
2125 exarg_T *eap;
2127 int i;
2129 if (eap->addr_count > 0)
2130 i = eap->line2 - 1;
2131 else
2132 i = curwin->w_arg_idx;
2133 do_argfile(eap, i);
2137 * Edit file "argn" of the argument lists.
2139 void
2140 do_argfile(eap, argn)
2141 exarg_T *eap;
2142 int argn;
2144 int other;
2145 char_u *p;
2146 int old_arg_idx = curwin->w_arg_idx;
2148 if (argn < 0 || argn >= ARGCOUNT)
2150 if (ARGCOUNT <= 1)
2151 EMSG(_("E163: There is only one file to edit"));
2152 else if (argn < 0)
2153 EMSG(_("E164: Cannot go before first file"));
2154 else
2155 EMSG(_("E165: Cannot go beyond last file"));
2157 else
2159 setpcmark();
2160 #ifdef FEAT_GUI
2161 need_mouse_correct = TRUE;
2162 #endif
2164 #ifdef FEAT_WINDOWS
2165 /* split window or create new tab page first */
2166 if (*eap->cmd == 's' || cmdmod.tab != 0)
2168 if (win_split(0, 0) == FAIL)
2169 return;
2170 # ifdef FEAT_SCROLLBIND
2171 curwin->w_p_scb = FALSE;
2172 # endif
2174 else
2175 #endif
2178 * if 'hidden' set, only check for changed file when re-editing
2179 * the same buffer
2181 other = TRUE;
2182 if (P_HID(curbuf))
2184 p = fix_fname(alist_name(&ARGLIST[argn]));
2185 other = otherfile(p);
2186 vim_free(p);
2188 if ((!P_HID(curbuf) || !other)
2189 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2190 return;
2193 curwin->w_arg_idx = argn;
2194 if (argn == ARGCOUNT - 1
2195 #ifdef FEAT_WINDOWS
2196 && curwin->w_alist == &global_alist
2197 #endif
2199 arg_had_last = TRUE;
2201 /* Edit the file; always use the last known line number.
2202 * When it fails (e.g. Abort for already edited file) restore the
2203 * argument index. */
2204 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
2205 eap, ECMD_LAST,
2206 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2207 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
2208 curwin->w_arg_idx = old_arg_idx;
2209 /* like Vi: set the mark where the cursor is in the file. */
2210 else if (eap->cmdidx != CMD_argdo)
2211 setmark('\'');
2216 * ":next", and commands that behave like it.
2218 void
2219 ex_next(eap)
2220 exarg_T *eap;
2222 int i;
2225 * check for changed buffer now, if this fails the argument list is not
2226 * redefined.
2228 if ( P_HID(curbuf)
2229 || eap->cmdidx == CMD_snext
2230 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2232 if (*eap->arg != NUL) /* redefine file list */
2234 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2235 return;
2236 i = 0;
2238 else
2239 i = curwin->w_arg_idx + (int)eap->line2;
2240 do_argfile(eap, i);
2244 #ifdef FEAT_LISTCMDS
2246 * ":argedit"
2248 void
2249 ex_argedit(eap)
2250 exarg_T *eap;
2252 int fnum;
2253 int i;
2254 char_u *s;
2256 /* Add the argument to the buffer list and get the buffer number. */
2257 fnum = buflist_add(eap->arg, BLN_LISTED);
2259 /* Check if this argument is already in the argument list. */
2260 for (i = 0; i < ARGCOUNT; ++i)
2261 if (ARGLIST[i].ae_fnum == fnum)
2262 break;
2263 if (i == ARGCOUNT)
2265 /* Can't find it, add it to the argument list. */
2266 s = vim_strsave(eap->arg);
2267 if (s == NULL)
2268 return;
2269 i = alist_add_list(1, &s,
2270 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2271 if (i < 0)
2272 return;
2273 curwin->w_arg_idx = i;
2276 alist_check_arg_idx();
2278 /* Edit the argument. */
2279 do_argfile(eap, i);
2283 * ":argadd"
2285 void
2286 ex_argadd(eap)
2287 exarg_T *eap;
2289 do_arglist(eap->arg, AL_ADD,
2290 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2291 #ifdef FEAT_TITLE
2292 maketitle();
2293 #endif
2297 * ":argdelete"
2299 void
2300 ex_argdelete(eap)
2301 exarg_T *eap;
2303 int i;
2304 int n;
2306 if (eap->addr_count > 0)
2308 /* ":1,4argdel": Delete all arguments in the range. */
2309 if (eap->line2 > ARGCOUNT)
2310 eap->line2 = ARGCOUNT;
2311 n = eap->line2 - eap->line1 + 1;
2312 if (*eap->arg != NUL || n <= 0)
2313 EMSG(_(e_invarg));
2314 else
2316 for (i = eap->line1; i <= eap->line2; ++i)
2317 vim_free(ARGLIST[i - 1].ae_fname);
2318 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2319 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2320 ALIST(curwin)->al_ga.ga_len -= n;
2321 if (curwin->w_arg_idx >= eap->line2)
2322 curwin->w_arg_idx -= n;
2323 else if (curwin->w_arg_idx > eap->line1)
2324 curwin->w_arg_idx = eap->line1;
2327 else if (*eap->arg == NUL)
2328 EMSG(_(e_argreq));
2329 else
2330 do_arglist(eap->arg, AL_DEL, 0);
2331 #ifdef FEAT_TITLE
2332 maketitle();
2333 #endif
2337 * ":argdo", ":windo", ":bufdo", ":tabdo"
2339 void
2340 ex_listdo(eap)
2341 exarg_T *eap;
2343 int i;
2344 #ifdef FEAT_WINDOWS
2345 win_T *wp;
2346 tabpage_T *tp;
2347 #endif
2348 buf_T *buf;
2349 int next_fnum = 0;
2350 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2351 char_u *save_ei = NULL;
2352 #endif
2353 char_u *p_shm_save;
2355 #ifndef FEAT_WINDOWS
2356 if (eap->cmdidx == CMD_windo)
2358 ex_ni(eap);
2359 return;
2361 #endif
2363 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2364 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
2365 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2366 * great speed improvement. */
2367 save_ei = au_event_disable(",Syntax");
2368 #endif
2370 if (eap->cmdidx == CMD_windo
2371 || eap->cmdidx == CMD_tabdo
2372 || P_HID(curbuf)
2373 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2375 /* start at the first argument/window/buffer */
2376 i = 0;
2377 #ifdef FEAT_WINDOWS
2378 wp = firstwin;
2379 tp = first_tabpage;
2380 #endif
2381 /* set pcmark now */
2382 if (eap->cmdidx == CMD_bufdo)
2383 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2384 else
2385 setpcmark();
2386 listcmd_busy = TRUE; /* avoids setting pcmark below */
2388 while (!got_int)
2390 if (eap->cmdidx == CMD_argdo)
2392 /* go to argument "i" */
2393 if (i == ARGCOUNT)
2394 break;
2395 /* Don't call do_argfile() when already there, it will try
2396 * reloading the file. */
2397 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
2399 /* Clear 'shm' to avoid that the file message overwrites
2400 * any output from the command. */
2401 p_shm_save = vim_strsave(p_shm);
2402 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
2403 do_argfile(eap, i);
2404 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2405 vim_free(p_shm_save);
2407 if (curwin->w_arg_idx != i)
2408 break;
2409 ++i;
2411 #ifdef FEAT_WINDOWS
2412 else if (eap->cmdidx == CMD_windo)
2414 /* go to window "wp" */
2415 if (!win_valid(wp))
2416 break;
2417 win_goto(wp);
2418 if (curwin != wp)
2419 break; /* something must be wrong */
2420 wp = curwin->w_next;
2422 else if (eap->cmdidx == CMD_tabdo)
2424 /* go to window "tp" */
2425 if (!valid_tabpage(tp))
2426 break;
2427 goto_tabpage_tp(tp);
2428 tp = tp->tp_next;
2430 #endif
2431 else if (eap->cmdidx == CMD_bufdo)
2433 /* Remember the number of the next listed buffer, in case
2434 * ":bwipe" is used or autocommands do something strange. */
2435 next_fnum = -1;
2436 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2437 if (buf->b_p_bl)
2439 next_fnum = buf->b_fnum;
2440 break;
2444 /* execute the command */
2445 do_cmdline(eap->arg, eap->getline, eap->cookie,
2446 DOCMD_VERBOSE + DOCMD_NOWAIT);
2448 if (eap->cmdidx == CMD_bufdo)
2450 /* Done? */
2451 if (next_fnum < 0)
2452 break;
2453 /* Check if the buffer still exists. */
2454 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2455 if (buf->b_fnum == next_fnum)
2456 break;
2457 if (buf == NULL)
2458 break;
2460 /* Go to the next buffer. Clear 'shm' to avoid that the file
2461 * message overwrites any output from the command. */
2462 p_shm_save = vim_strsave(p_shm);
2463 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
2464 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
2465 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2466 vim_free(p_shm_save);
2468 /* If autocommands took us elsewhere, quit here */
2469 if (curbuf->b_fnum != next_fnum)
2470 break;
2473 if (eap->cmdidx == CMD_windo)
2475 validate_cursor(); /* cursor may have moved */
2476 #ifdef FEAT_SCROLLBIND
2477 /* required when 'scrollbind' has been set */
2478 if (curwin->w_p_scb)
2479 do_check_scrollbind(TRUE);
2480 #endif
2483 listcmd_busy = FALSE;
2486 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2487 if (save_ei != NULL)
2489 au_event_restore(save_ei);
2490 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2491 curbuf->b_fname, TRUE, curbuf);
2493 #endif
2497 * Add files[count] to the arglist of the current window after arg "after".
2498 * The file names in files[count] must have been allocated and are taken over.
2499 * Files[] itself is not taken over.
2500 * Returns index of first added argument. Returns -1 when failed (out of mem).
2502 static int
2503 alist_add_list(count, files, after)
2504 int count;
2505 char_u **files;
2506 int after; /* where to add: 0 = before first one */
2508 int i;
2510 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2512 if (after < 0)
2513 after = 0;
2514 if (after > ARGCOUNT)
2515 after = ARGCOUNT;
2516 if (after < ARGCOUNT)
2517 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2518 (ARGCOUNT - after) * sizeof(aentry_T));
2519 for (i = 0; i < count; ++i)
2521 ARGLIST[after + i].ae_fname = files[i];
2522 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2524 ALIST(curwin)->al_ga.ga_len += count;
2525 if (curwin->w_arg_idx >= after)
2526 ++curwin->w_arg_idx;
2527 return after;
2530 for (i = 0; i < count; ++i)
2531 vim_free(files[i]);
2532 return -1;
2535 #endif /* FEAT_LISTCMDS */
2537 #ifdef FEAT_EVAL
2539 * ":compiler[!] {name}"
2541 void
2542 ex_compiler(eap)
2543 exarg_T *eap;
2545 char_u *buf;
2546 char_u *old_cur_comp = NULL;
2547 char_u *p;
2549 if (*eap->arg == NUL)
2551 /* List all compiler scripts. */
2552 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2553 /* ) keep the indenter happy... */
2555 else
2557 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2558 if (buf != NULL)
2560 if (eap->forceit)
2562 /* ":compiler! {name}" sets global options */
2563 do_cmdline_cmd((char_u *)
2564 "command -nargs=* CompilerSet set <args>");
2566 else
2568 /* ":compiler! {name}" sets local options.
2569 * To remain backwards compatible "current_compiler" is always
2570 * used. A user's compiler plugin may set it, the distributed
2571 * plugin will then skip the settings. Afterwards set
2572 * "b:current_compiler" and restore "current_compiler". */
2573 old_cur_comp = get_var_value((char_u *)"current_compiler");
2574 if (old_cur_comp != NULL)
2575 old_cur_comp = vim_strsave(old_cur_comp);
2576 do_cmdline_cmd((char_u *)
2577 "command -nargs=* CompilerSet setlocal <args>");
2579 do_unlet((char_u *)"current_compiler", TRUE);
2580 do_unlet((char_u *)"b:current_compiler", TRUE);
2582 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
2583 if (source_runtime(buf, TRUE) == FAIL)
2584 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2585 vim_free(buf);
2587 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2589 /* Set "b:current_compiler" from "current_compiler". */
2590 p = get_var_value((char_u *)"current_compiler");
2591 if (p != NULL)
2592 set_internal_string_var((char_u *)"b:current_compiler", p);
2594 /* Restore "current_compiler" for ":compiler {name}". */
2595 if (!eap->forceit)
2597 if (old_cur_comp != NULL)
2599 set_internal_string_var((char_u *)"current_compiler",
2600 old_cur_comp);
2601 vim_free(old_cur_comp);
2603 else
2604 do_unlet((char_u *)"current_compiler", TRUE);
2609 #endif
2612 * ":runtime {name}"
2614 void
2615 ex_runtime(eap)
2616 exarg_T *eap;
2618 source_runtime(eap->arg, eap->forceit);
2621 static void source_callback __ARGS((char_u *fname, void *cookie));
2623 static void
2624 source_callback(fname, cookie)
2625 char_u *fname;
2626 void *cookie UNUSED;
2628 (void)do_source(fname, FALSE, DOSO_NONE);
2632 * Source the file "name" from all directories in 'runtimepath'.
2633 * "name" can contain wildcards.
2634 * When "all" is TRUE, source all files, otherwise only the first one.
2635 * return FAIL when no file could be sourced, OK otherwise.
2638 source_runtime(name, all)
2639 char_u *name;
2640 int all;
2642 return do_in_runtimepath(name, all, source_callback, NULL);
2646 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2647 * it: callback(fname, "cookie")
2648 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2649 * used.
2650 * Returns OK when at least one match found, FAIL otherwise.
2653 do_in_runtimepath(name, all, callback, cookie)
2654 char_u *name;
2655 int all;
2656 void (*callback)__ARGS((char_u *fname, void *ck));
2657 void *cookie;
2659 char_u *rtp;
2660 char_u *np;
2661 char_u *buf;
2662 char_u *rtp_copy;
2663 char_u *tail;
2664 int num_files;
2665 char_u **files;
2666 int i;
2667 int did_one = FALSE;
2668 #ifdef AMIGA
2669 struct Process *proc = (struct Process *)FindTask(0L);
2670 APTR save_winptr = proc->pr_WindowPtr;
2672 /* Avoid a requester here for a volume that doesn't exist. */
2673 proc->pr_WindowPtr = (APTR)-1L;
2674 #endif
2676 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2677 * value. */
2678 rtp_copy = vim_strsave(p_rtp);
2679 buf = alloc(MAXPATHL);
2680 if (buf != NULL && rtp_copy != NULL)
2682 if (p_verbose > 1)
2684 verbose_enter();
2685 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
2686 (char *)name, (char *)p_rtp);
2687 verbose_leave();
2690 /* Loop over all entries in 'runtimepath'. */
2691 rtp = rtp_copy;
2692 while (*rtp != NUL && (all || !did_one))
2694 /* Copy the path from 'runtimepath' to buf[]. */
2695 copy_option_part(&rtp, buf, MAXPATHL, ",");
2696 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2698 add_pathsep(buf);
2699 tail = buf + STRLEN(buf);
2701 /* Loop over all patterns in "name" */
2702 np = name;
2703 while (*np != NUL && (all || !did_one))
2705 /* Append the pattern from "name" to buf[]. */
2706 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2707 "\t ");
2709 if (p_verbose > 2)
2711 verbose_enter();
2712 smsg((char_u *)_("Searching for \"%s\""), buf);
2713 verbose_leave();
2716 /* Expand wildcards, invoke the callback for each match. */
2717 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2718 EW_FILE) == OK)
2720 for (i = 0; i < num_files; ++i)
2722 (*callback)(files[i], cookie);
2723 did_one = TRUE;
2724 if (!all)
2725 break;
2727 FreeWild(num_files, files);
2733 vim_free(buf);
2734 vim_free(rtp_copy);
2735 if (p_verbose > 0 && !did_one)
2737 verbose_enter();
2738 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
2739 verbose_leave();
2742 #ifdef AMIGA
2743 proc->pr_WindowPtr = save_winptr;
2744 #endif
2746 return did_one ? OK : FAIL;
2749 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2751 * ":options"
2753 void
2754 ex_options(eap)
2755 exarg_T *eap UNUSED;
2757 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2759 #endif
2762 * ":source {fname}"
2764 void
2765 ex_source(eap)
2766 exarg_T *eap;
2768 #ifdef FEAT_BROWSE
2769 if (cmdmod.browse)
2771 char_u *fname = NULL;
2773 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
2774 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2775 if (fname != NULL)
2777 cmd_source(fname, eap);
2778 vim_free(fname);
2781 else
2782 #endif
2783 cmd_source(eap->arg, eap);
2786 static void
2787 cmd_source(fname, eap)
2788 char_u *fname;
2789 exarg_T *eap;
2791 if (*fname == NUL)
2792 EMSG(_(e_argreq));
2794 else if (eap != NULL && eap->forceit)
2795 /* ":source!": read Normal mdoe commands
2796 * Need to execute the commands directly. This is required at least
2797 * for:
2798 * - ":g" command busy
2799 * - after ":argdo", ":windo" or ":bufdo"
2800 * - another command follows
2801 * - inside a loop
2803 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2804 #ifdef FEAT_EVAL
2805 || eap->cstack->cs_idx >= 0
2806 #endif
2809 /* ":source" read ex commands */
2810 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
2811 EMSG2(_(e_notopen), fname);
2815 * ":source" and associated commands.
2818 * Structure used to store info for each sourced file.
2819 * It is shared between do_source() and getsourceline().
2820 * This is required, because it needs to be handed to do_cmdline() and
2821 * sourcing can be done recursively.
2823 struct source_cookie
2825 FILE *fp; /* opened file for sourcing */
2826 char_u *nextline; /* if not NULL: line that was read ahead */
2827 int finished; /* ":finish" used */
2828 #if defined (USE_CRNL) || defined (USE_CR)
2829 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2830 int error; /* TRUE if LF found after CR-LF */
2831 #endif
2832 #ifdef FEAT_EVAL
2833 linenr_T breakpoint; /* next line with breakpoint or zero */
2834 char_u *fname; /* name of sourced file */
2835 int dbg_tick; /* debug_tick when breakpoint was set */
2836 int level; /* top nesting level of sourced file */
2837 #endif
2838 #ifdef FEAT_MBYTE
2839 vimconv_T conv; /* type of conversion */
2840 #endif
2843 #ifdef FEAT_EVAL
2845 * Return the address holding the next breakpoint line for a source cookie.
2847 linenr_T *
2848 source_breakpoint(cookie)
2849 void *cookie;
2851 return &((struct source_cookie *)cookie)->breakpoint;
2855 * Return the address holding the debug tick for a source cookie.
2857 int *
2858 source_dbg_tick(cookie)
2859 void *cookie;
2861 return &((struct source_cookie *)cookie)->dbg_tick;
2865 * Return the nesting level for a source cookie.
2868 source_level(cookie)
2869 void *cookie;
2871 return ((struct source_cookie *)cookie)->level;
2873 #endif
2875 static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2877 #if defined(WIN32) && defined(FEAT_CSCOPE)
2878 static FILE *fopen_noinh_readbin __ARGS((char *filename));
2881 * Special function to open a file without handle inheritance.
2883 static FILE *
2884 fopen_noinh_readbin(filename)
2885 char *filename;
2887 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2889 if (fd_tmp == -1)
2890 return NULL;
2891 return fdopen(fd_tmp, READBIN);
2893 #endif
2897 * do_source: Read the file "fname" and execute its lines as EX commands.
2899 * This function may be called recursively!
2901 * return FAIL if file could not be opened, OK otherwise
2904 do_source(fname, check_other, is_vimrc)
2905 char_u *fname;
2906 int check_other; /* check for .vimrc and _vimrc */
2907 int is_vimrc; /* DOSO_ value */
2909 struct source_cookie cookie;
2910 char_u *save_sourcing_name;
2911 linenr_T save_sourcing_lnum;
2912 char_u *p;
2913 char_u *fname_exp;
2914 char_u *firstline = NULL;
2915 int retval = FAIL;
2916 #ifdef FEAT_EVAL
2917 scid_T save_current_SID;
2918 static scid_T last_current_SID = 0;
2919 void *save_funccalp;
2920 int save_debug_break_level = debug_break_level;
2921 scriptitem_T *si = NULL;
2922 # ifdef UNIX
2923 struct stat st;
2924 int stat_ok;
2925 # endif
2926 #endif
2927 #ifdef STARTUPTIME
2928 struct timeval tv_rel;
2929 struct timeval tv_start;
2930 #endif
2931 #ifdef FEAT_PROFILE
2932 proftime_T wait_start;
2933 #endif
2935 #ifdef RISCOS
2936 p = mch_munge_fname(fname);
2937 #else
2938 p = expand_env_save(fname);
2939 #endif
2940 if (p == NULL)
2941 return retval;
2942 fname_exp = fix_fname(p);
2943 vim_free(p);
2944 if (fname_exp == NULL)
2945 return retval;
2946 if (mch_isdir(fname_exp))
2948 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
2949 goto theend;
2952 #ifdef FEAT_AUTOCMD
2953 /* Apply SourceCmd autocommands, they should get the file and source it. */
2954 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2955 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2956 FALSE, curbuf))
2958 # ifdef FEAT_EVAL
2959 retval = aborting() ? FAIL : OK;
2960 # else
2961 retval = OK;
2962 # endif
2963 goto theend;
2966 /* Apply SourcePre autocommands, they may get the file. */
2967 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2968 #endif
2970 #if defined(WIN32) && defined(FEAT_CSCOPE)
2971 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2972 #else
2973 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2974 #endif
2975 if (cookie.fp == NULL && check_other)
2978 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2979 * and ".exrc" by "_exrc" or vice versa.
2981 p = gettail(fname_exp);
2982 if ((*p == '.' || *p == '_')
2983 && (STRICMP(p + 1, "vimrc") == 0
2984 || STRICMP(p + 1, "gvimrc") == 0
2985 || STRICMP(p + 1, "exrc") == 0))
2987 if (*p == '_')
2988 *p = '.';
2989 else
2990 *p = '_';
2991 #if defined(WIN32) && defined(FEAT_CSCOPE)
2992 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2993 #else
2994 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2995 #endif
2999 if (cookie.fp == NULL)
3001 if (p_verbose > 0)
3003 verbose_enter();
3004 if (sourcing_name == NULL)
3005 smsg((char_u *)_("could not source \"%s\""), fname);
3006 else
3007 smsg((char_u *)_("line %ld: could not source \"%s\""),
3008 sourcing_lnum, fname);
3009 verbose_leave();
3011 goto theend;
3015 * The file exists.
3016 * - In verbose mode, give a message.
3017 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3019 if (p_verbose > 1)
3021 verbose_enter();
3022 if (sourcing_name == NULL)
3023 smsg((char_u *)_("sourcing \"%s\""), fname);
3024 else
3025 smsg((char_u *)_("line %ld: sourcing \"%s\""),
3026 sourcing_lnum, fname);
3027 verbose_leave();
3029 if (is_vimrc == DOSO_VIMRC)
3030 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3031 else if (is_vimrc == DOSO_GVIMRC)
3032 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
3034 #ifdef USE_CRNL
3035 /* If no automatic file format: Set default to CR-NL. */
3036 if (*p_ffs == NUL)
3037 cookie.fileformat = EOL_DOS;
3038 else
3039 cookie.fileformat = EOL_UNKNOWN;
3040 cookie.error = FALSE;
3041 #endif
3043 #ifdef USE_CR
3044 /* If no automatic file format: Set default to CR. */
3045 if (*p_ffs == NUL)
3046 cookie.fileformat = EOL_MAC;
3047 else
3048 cookie.fileformat = EOL_UNKNOWN;
3049 cookie.error = FALSE;
3050 #endif
3052 cookie.nextline = NULL;
3053 cookie.finished = FALSE;
3055 #ifdef FEAT_EVAL
3057 * Check if this script has a breakpoint.
3059 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3060 cookie.fname = fname_exp;
3061 cookie.dbg_tick = debug_tick;
3063 cookie.level = ex_nesting_level;
3064 #endif
3067 * Keep the sourcing name/lnum, for recursive calls.
3069 save_sourcing_name = sourcing_name;
3070 sourcing_name = fname_exp;
3071 save_sourcing_lnum = sourcing_lnum;
3072 sourcing_lnum = 0;
3074 #ifdef FEAT_MBYTE
3075 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3077 /* Read the first line so we can check for a UTF-8 BOM. */
3078 firstline = getsourceline(0, (void *)&cookie, 0);
3079 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3080 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3082 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3083 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3084 p = string_convert(&cookie.conv, firstline + 3, NULL);
3085 if (p == NULL)
3086 p = vim_strsave(firstline + 3);
3087 if (p != NULL)
3089 vim_free(firstline);
3090 firstline = p;
3093 #endif
3095 #ifdef STARTUPTIME
3096 time_push(&tv_rel, &tv_start);
3097 #endif
3099 #ifdef FEAT_EVAL
3100 # ifdef FEAT_PROFILE
3101 if (do_profiling == PROF_YES)
3102 prof_child_enter(&wait_start); /* entering a child now */
3103 # endif
3105 /* Don't use local function variables, if called from a function.
3106 * Also starts profiling timer for nested script. */
3107 save_funccalp = save_funccal();
3110 * Check if this script was sourced before to finds its SID.
3111 * If it's new, generate a new SID.
3113 save_current_SID = current_SID;
3114 # ifdef UNIX
3115 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3116 # endif
3117 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3119 si = &SCRIPT_ITEM(current_SID);
3120 if (si->sn_name != NULL
3121 && (
3122 # ifdef UNIX
3123 /* Compare dev/ino when possible, it catches symbolic
3124 * links. Also compare file names, the inode may change
3125 * when the file was edited. */
3126 ((stat_ok && si->sn_dev_valid)
3127 && (si->sn_dev == st.st_dev
3128 && si->sn_ino == st.st_ino)) ||
3129 # endif
3130 fnamecmp(si->sn_name, fname_exp) == 0))
3131 break;
3133 if (current_SID == 0)
3135 current_SID = ++last_current_SID;
3136 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3137 == FAIL)
3138 goto almosttheend;
3139 while (script_items.ga_len < current_SID)
3141 ++script_items.ga_len;
3142 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3143 # ifdef FEAT_PROFILE
3144 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
3145 # endif
3147 si = &SCRIPT_ITEM(current_SID);
3148 si->sn_name = fname_exp;
3149 fname_exp = NULL;
3150 # ifdef UNIX
3151 if (stat_ok)
3153 si->sn_dev_valid = TRUE;
3154 si->sn_dev = st.st_dev;
3155 si->sn_ino = st.st_ino;
3157 else
3158 si->sn_dev_valid = FALSE;
3159 # endif
3161 /* Allocate the local script variables to use for this script. */
3162 new_script_vars(current_SID);
3165 # ifdef FEAT_PROFILE
3166 if (do_profiling == PROF_YES)
3168 int forceit;
3170 /* Check if we do profiling for this script. */
3171 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3173 script_do_profile(si);
3174 si->sn_pr_force = forceit;
3176 if (si->sn_prof_on)
3178 ++si->sn_pr_count;
3179 profile_start(&si->sn_pr_start);
3180 profile_zero(&si->sn_pr_children);
3183 # endif
3184 #endif
3187 * Call do_cmdline, which will call getsourceline() to get the lines.
3189 do_cmdline(firstline, getsourceline, (void *)&cookie,
3190 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
3191 retval = OK;
3193 #ifdef FEAT_PROFILE
3194 if (do_profiling == PROF_YES)
3196 /* Get "si" again, "script_items" may have been reallocated. */
3197 si = &SCRIPT_ITEM(current_SID);
3198 if (si->sn_prof_on)
3200 profile_end(&si->sn_pr_start);
3201 profile_sub_wait(&wait_start, &si->sn_pr_start);
3202 profile_add(&si->sn_pr_total, &si->sn_pr_start);
3203 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3204 &si->sn_pr_children);
3207 #endif
3209 if (got_int)
3210 EMSG(_(e_interr));
3211 sourcing_name = save_sourcing_name;
3212 sourcing_lnum = save_sourcing_lnum;
3213 if (p_verbose > 1)
3215 verbose_enter();
3216 smsg((char_u *)_("finished sourcing %s"), fname);
3217 if (sourcing_name != NULL)
3218 smsg((char_u *)_("continuing in %s"), sourcing_name);
3219 verbose_leave();
3221 #ifdef STARTUPTIME
3222 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3223 time_msg((char *)IObuff, &tv_start);
3224 time_pop(&tv_rel);
3225 #endif
3227 #ifdef FEAT_EVAL
3229 * After a "finish" in debug mode, need to break at first command of next
3230 * sourced file.
3232 if (save_debug_break_level > ex_nesting_level
3233 && debug_break_level == ex_nesting_level)
3234 ++debug_break_level;
3235 #endif
3237 #ifdef FEAT_EVAL
3238 almosttheend:
3239 current_SID = save_current_SID;
3240 restore_funccal(save_funccalp);
3241 # ifdef FEAT_PROFILE
3242 if (do_profiling == PROF_YES)
3243 prof_child_exit(&wait_start); /* leaving a child now */
3244 # endif
3245 #endif
3246 fclose(cookie.fp);
3247 vim_free(cookie.nextline);
3248 vim_free(firstline);
3249 #ifdef FEAT_MBYTE
3250 convert_setup(&cookie.conv, NULL, NULL);
3251 #endif
3253 theend:
3254 vim_free(fname_exp);
3255 return retval;
3258 #if defined(FEAT_EVAL) || defined(PROTO)
3261 * ":scriptnames"
3263 void
3264 ex_scriptnames(eap)
3265 exarg_T *eap UNUSED;
3267 int i;
3269 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3270 if (SCRIPT_ITEM(i).sn_name != NULL)
3271 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
3274 # if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3276 * Fix slashes in the list of script names for 'shellslash'.
3278 void
3279 scriptnames_slash_adjust()
3281 int i;
3283 for (i = 1; i <= script_items.ga_len; ++i)
3284 if (SCRIPT_ITEM(i).sn_name != NULL)
3285 slash_adjust(SCRIPT_ITEM(i).sn_name);
3287 # endif
3290 * Get a pointer to a script name. Used for ":verbose set".
3292 char_u *
3293 get_scriptname(id)
3294 scid_T id;
3296 if (id == SID_MODELINE)
3297 return (char_u *)_("modeline");
3298 if (id == SID_CMDARG)
3299 return (char_u *)_("--cmd argument");
3300 if (id == SID_CARG)
3301 return (char_u *)_("-c argument");
3302 if (id == SID_ENV)
3303 return (char_u *)_("environment variable");
3304 if (id == SID_ERROR)
3305 return (char_u *)_("error handler");
3306 return SCRIPT_ITEM(id).sn_name;
3309 # if defined(EXITFREE) || defined(PROTO)
3310 void
3311 free_scriptnames()
3313 int i;
3315 for (i = script_items.ga_len; i > 0; --i)
3316 vim_free(SCRIPT_ITEM(i).sn_name);
3317 ga_clear(&script_items);
3319 # endif
3321 #endif
3323 #if defined(USE_CR) || defined(PROTO)
3325 # if defined(__MSL__) && (__MSL__ >= 22)
3327 * Newer version of the Metrowerks library handle DOS and UNIX files
3328 * without help.
3329 * Test with earlier versions, MSL 2.2 is the library supplied with
3330 * Codewarrior Pro 2.
3332 char *
3333 fgets_cr(s, n, stream)
3334 char *s;
3335 int n;
3336 FILE *stream;
3338 return fgets(s, n, stream);
3340 # else
3342 * Version of fgets() which also works for lines ending in a <CR> only
3343 * (Macintosh format).
3344 * For older versions of the Metrowerks library.
3345 * At least CodeWarrior 9 needed this code.
3347 char *
3348 fgets_cr(s, n, stream)
3349 char *s;
3350 int n;
3351 FILE *stream;
3353 int c = 0;
3354 int char_read = 0;
3356 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3358 c = fgetc(stream);
3359 s[char_read++] = c;
3360 /* If the file is in DOS format, we need to skip a NL after a CR. I
3361 * thought it was the other way around, but this appears to work... */
3362 if (c == '\n')
3364 c = fgetc(stream);
3365 if (c != '\r')
3366 ungetc(c, stream);
3370 s[char_read] = 0;
3371 if (char_read == 0)
3372 return NULL;
3374 if (feof(stream) && char_read == 1)
3375 return NULL;
3377 return s;
3379 # endif
3380 #endif
3383 * Get one full line from a sourced file.
3384 * Called by do_cmdline() when it's called from do_source().
3386 * Return a pointer to the line in allocated memory.
3387 * Return NULL for end-of-file or some error.
3389 char_u *
3390 getsourceline(c, cookie, indent)
3391 int c UNUSED;
3392 void *cookie;
3393 int indent UNUSED;
3395 struct source_cookie *sp = (struct source_cookie *)cookie;
3396 char_u *line;
3397 char_u *p, *s;
3399 #ifdef FEAT_EVAL
3400 /* If breakpoints have been added/deleted need to check for it. */
3401 if (sp->dbg_tick < debug_tick)
3403 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3404 sp->dbg_tick = debug_tick;
3406 # ifdef FEAT_PROFILE
3407 if (do_profiling == PROF_YES)
3408 script_line_end();
3409 # endif
3410 #endif
3412 * Get current line. If there is a read-ahead line, use it, otherwise get
3413 * one now.
3415 if (sp->finished)
3416 line = NULL;
3417 else if (sp->nextline == NULL)
3418 line = get_one_sourceline(sp);
3419 else
3421 line = sp->nextline;
3422 sp->nextline = NULL;
3423 ++sourcing_lnum;
3425 #ifdef FEAT_PROFILE
3426 if (line != NULL && do_profiling == PROF_YES)
3427 script_line_start();
3428 #endif
3430 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3431 * contain the 'C' flag. */
3432 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3434 /* compensate for the one line read-ahead */
3435 --sourcing_lnum;
3436 for (;;)
3438 sp->nextline = get_one_sourceline(sp);
3439 if (sp->nextline == NULL)
3440 break;
3441 p = skipwhite(sp->nextline);
3442 if (*p != '\\')
3443 break;
3444 s = alloc((unsigned)(STRLEN(line) + STRLEN(p)));
3445 if (s == NULL) /* out of memory */
3446 break;
3447 STRCPY(s, line);
3448 STRCAT(s, p + 1);
3449 vim_free(line);
3450 line = s;
3451 vim_free(sp->nextline);
3455 #ifdef FEAT_MBYTE
3456 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3458 /* Convert the encoding of the script line. */
3459 s = string_convert(&sp->conv, line, NULL);
3460 if (s != NULL)
3462 vim_free(line);
3463 line = s;
3466 #endif
3468 #ifdef FEAT_EVAL
3469 /* Did we encounter a breakpoint? */
3470 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3472 dbg_breakpoint(sp->fname, sourcing_lnum);
3473 /* Find next breakpoint. */
3474 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3475 sp->dbg_tick = debug_tick;
3477 #endif
3479 return line;
3482 static char_u *
3483 get_one_sourceline(sp)
3484 struct source_cookie *sp;
3486 garray_T ga;
3487 int len;
3488 int c;
3489 char_u *buf;
3490 #ifdef USE_CRNL
3491 int has_cr; /* CR-LF found */
3492 #endif
3493 #ifdef USE_CR
3494 char_u *scan;
3495 #endif
3496 int have_read = FALSE;
3498 /* use a growarray to store the sourced line */
3499 ga_init2(&ga, 1, 250);
3502 * Loop until there is a finished line (or end-of-file).
3504 sourcing_lnum++;
3505 for (;;)
3507 /* make room to read at least 120 (more) characters */
3508 if (ga_grow(&ga, 120) == FAIL)
3509 break;
3510 buf = (char_u *)ga.ga_data;
3512 #ifdef USE_CR
3513 if (sp->fileformat == EOL_MAC)
3515 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3516 sp->fp) == NULL)
3517 break;
3519 else
3520 #endif
3521 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3522 sp->fp) == NULL)
3523 break;
3524 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
3525 #ifdef USE_CRNL
3526 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3527 * CTRL-Z by its own, or after a NL. */
3528 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3529 && sp->fileformat == EOL_DOS
3530 && buf[len - 1] == Ctrl_Z)
3532 buf[len - 1] = NUL;
3533 break;
3535 #endif
3537 #ifdef USE_CR
3538 /* If the read doesn't stop on a new line, and there's
3539 * some CR then we assume a Mac format */
3540 if (sp->fileformat == EOL_UNKNOWN)
3542 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3543 sp->fileformat = EOL_MAC;
3544 else
3545 sp->fileformat = EOL_UNIX;
3548 if (sp->fileformat == EOL_MAC)
3550 scan = vim_strchr(buf, '\r');
3552 if (scan != NULL)
3554 *scan = '\n';
3555 if (*(scan + 1) != 0)
3557 *(scan + 1) = 0;
3558 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3561 len = STRLEN(buf);
3563 #endif
3565 have_read = TRUE;
3566 ga.ga_len = len;
3568 /* If the line was longer than the buffer, read more. */
3569 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
3570 continue;
3572 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3574 #ifdef USE_CRNL
3575 has_cr = (len >= 2 && buf[len - 2] == '\r');
3576 if (sp->fileformat == EOL_UNKNOWN)
3578 if (has_cr)
3579 sp->fileformat = EOL_DOS;
3580 else
3581 sp->fileformat = EOL_UNIX;
3584 if (sp->fileformat == EOL_DOS)
3586 if (has_cr) /* replace trailing CR */
3588 buf[len - 2] = '\n';
3589 --len;
3590 --ga.ga_len;
3592 else /* lines like ":map xx yy^M" will have failed */
3594 if (!sp->error)
3596 msg_source(hl_attr(HLF_W));
3597 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
3599 sp->error = TRUE;
3600 sp->fileformat = EOL_UNIX;
3603 #endif
3604 /* The '\n' is escaped if there is an odd number of ^V's just
3605 * before it, first set "c" just before the 'V's and then check
3606 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3607 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3609 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3611 sourcing_lnum++;
3612 continue;
3615 buf[len - 1] = NUL; /* remove the NL */
3619 * Check for ^C here now and then, so recursive :so can be broken.
3621 line_breakcheck();
3622 break;
3625 if (have_read)
3626 return (char_u *)ga.ga_data;
3628 vim_free(ga.ga_data);
3629 return NULL;
3632 #if defined(FEAT_PROFILE) || defined(PROTO)
3634 * Called when starting to read a script line.
3635 * "sourcing_lnum" must be correct!
3636 * When skipping lines it may not actually be executed, but we won't find out
3637 * until later and we need to store the time now.
3639 void
3640 script_line_start()
3642 scriptitem_T *si;
3643 sn_prl_T *pp;
3645 if (current_SID <= 0 || current_SID > script_items.ga_len)
3646 return;
3647 si = &SCRIPT_ITEM(current_SID);
3648 if (si->sn_prof_on && sourcing_lnum >= 1)
3650 /* Grow the array before starting the timer, so that the time spent
3651 * here isn't counted. */
3652 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3653 si->sn_prl_idx = sourcing_lnum - 1;
3654 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3655 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3657 /* Zero counters for a line that was not used before. */
3658 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3659 pp->snp_count = 0;
3660 profile_zero(&pp->sn_prl_total);
3661 profile_zero(&pp->sn_prl_self);
3662 ++si->sn_prl_ga.ga_len;
3664 si->sn_prl_execed = FALSE;
3665 profile_start(&si->sn_prl_start);
3666 profile_zero(&si->sn_prl_children);
3667 profile_get_wait(&si->sn_prl_wait);
3672 * Called when actually executing a function line.
3674 void
3675 script_line_exec()
3677 scriptitem_T *si;
3679 if (current_SID <= 0 || current_SID > script_items.ga_len)
3680 return;
3681 si = &SCRIPT_ITEM(current_SID);
3682 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3683 si->sn_prl_execed = TRUE;
3687 * Called when done with a function line.
3689 void
3690 script_line_end()
3692 scriptitem_T *si;
3693 sn_prl_T *pp;
3695 if (current_SID <= 0 || current_SID > script_items.ga_len)
3696 return;
3697 si = &SCRIPT_ITEM(current_SID);
3698 if (si->sn_prof_on && si->sn_prl_idx >= 0
3699 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3701 if (si->sn_prl_execed)
3703 pp = &PRL_ITEM(si, si->sn_prl_idx);
3704 ++pp->snp_count;
3705 profile_end(&si->sn_prl_start);
3706 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
3707 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
3708 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3709 &si->sn_prl_children);
3711 si->sn_prl_idx = -1;
3714 #endif
3717 * ":scriptencoding": Set encoding conversion for a sourced script.
3718 * Without the multi-byte feature it's simply ignored.
3720 void
3721 ex_scriptencoding(eap)
3722 exarg_T *eap UNUSED;
3724 #ifdef FEAT_MBYTE
3725 struct source_cookie *sp;
3726 char_u *name;
3728 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3730 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3731 return;
3734 if (*eap->arg != NUL)
3736 name = enc_canonize(eap->arg);
3737 if (name == NULL) /* out of memory */
3738 return;
3740 else
3741 name = eap->arg;
3743 /* Setup for conversion from the specified encoding to 'encoding'. */
3744 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3745 convert_setup(&sp->conv, name, p_enc);
3747 if (name != eap->arg)
3748 vim_free(name);
3749 #endif
3752 #if defined(FEAT_EVAL) || defined(PROTO)
3754 * ":finish": Mark a sourced file as finished.
3756 void
3757 ex_finish(eap)
3758 exarg_T *eap;
3760 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3761 do_finish(eap, FALSE);
3762 else
3763 EMSG(_("E168: :finish used outside of a sourced file"));
3767 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3768 * Also called for a pending finish at the ":endtry" or after returning from
3769 * an extra do_cmdline(). "reanimate" is used in the latter case.
3771 void
3772 do_finish(eap, reanimate)
3773 exarg_T *eap;
3774 int reanimate;
3776 int idx;
3778 if (reanimate)
3779 ((struct source_cookie *)getline_cookie(eap->getline,
3780 eap->cookie))->finished = FALSE;
3783 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3784 * not in its finally clause (which then is to be executed next) is found.
3785 * In this case, make the ":finish" pending for execution at the ":endtry".
3786 * Otherwise, finish normally.
3788 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3789 if (idx >= 0)
3791 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3792 report_make_pending(CSTP_FINISH, NULL);
3794 else
3795 ((struct source_cookie *)getline_cookie(eap->getline,
3796 eap->cookie))->finished = TRUE;
3801 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3802 * message for missing ":endif".
3803 * Return FALSE when not sourcing a file.
3806 source_finished(fgetline, cookie)
3807 char_u *(*fgetline) __ARGS((int, void *, int));
3808 void *cookie;
3810 return (getline_equal(fgetline, cookie, getsourceline)
3811 && ((struct source_cookie *)getline_cookie(
3812 fgetline, cookie))->finished);
3814 #endif
3816 #if defined(FEAT_LISTCMDS) || defined(PROTO)
3818 * ":checktime [buffer]"
3820 void
3821 ex_checktime(eap)
3822 exarg_T *eap;
3824 buf_T *buf;
3825 int save_no_check_timestamps = no_check_timestamps;
3827 no_check_timestamps = 0;
3828 if (eap->addr_count == 0) /* default is all buffers */
3829 check_timestamps(FALSE);
3830 else
3832 buf = buflist_findnr((int)eap->line2);
3833 if (buf != NULL) /* cannot happen? */
3834 (void)buf_check_timestamp(buf, FALSE);
3836 no_check_timestamps = save_no_check_timestamps;
3838 #endif
3840 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3841 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3842 static char *get_locale_val __ARGS((int what));
3844 static char *
3845 get_locale_val(what)
3846 int what;
3848 char *loc;
3850 /* Obtain the locale value from the libraries. For DJGPP this is
3851 * redefined and it doesn't use the arguments. */
3852 loc = setlocale(what, NULL);
3854 # ifdef WIN32
3855 if (loc != NULL)
3857 char_u *p;
3859 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3860 * one of the values (e.g., LC_CTYPE) differs. */
3861 p = vim_strchr(loc, '=');
3862 if (p != NULL)
3864 loc = ++p;
3865 while (*p != NUL) /* remove trailing newline */
3867 if (*p < ' ' || *p == ';')
3869 *p = NUL;
3870 break;
3872 ++p;
3876 # endif
3878 return loc;
3880 #endif
3883 #ifdef WIN32
3885 * On MS-Windows locale names are strings like "German_Germany.1252", but
3886 * gettext expects "de". Try to translate one into another here for a few
3887 * supported languages.
3889 static char_u *
3890 gettext_lang(char_u *name)
3892 int i;
3893 static char *(mtable[]) = {
3894 "afrikaans", "af",
3895 "czech", "cs",
3896 "dutch", "nl",
3897 "german", "de",
3898 "english_united kingdom", "en_GB",
3899 "spanish", "es",
3900 "french", "fr",
3901 "italian", "it",
3902 "japanese", "ja",
3903 "korean", "ko",
3904 "norwegian", "no",
3905 "polish", "pl",
3906 "russian", "ru",
3907 "slovak", "sk",
3908 "swedish", "sv",
3909 "ukrainian", "uk",
3910 "chinese_china", "zh_CN",
3911 "chinese_taiwan", "zh_TW",
3912 NULL};
3914 for (i = 0; mtable[i] != NULL; i += 2)
3915 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3916 return mtable[i + 1];
3917 return name;
3919 #endif
3921 #if defined(FEAT_MULTI_LANG) || defined(PROTO)
3923 * Obtain the current messages language. Used to set the default for
3924 * 'helplang'. May return NULL or an empty string.
3926 char_u *
3927 get_mess_lang()
3929 char_u *p;
3931 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3932 # if defined(LC_MESSAGES)
3933 p = (char_u *)get_locale_val(LC_MESSAGES);
3934 # else
3935 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
3936 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3937 * and LC_MONETARY may be set differently for a Japanese working in the
3938 * US. */
3939 p = (char_u *)get_locale_val(LC_COLLATE);
3940 # endif
3941 # else
3942 p = mch_getenv((char_u *)"LC_ALL");
3943 if (p == NULL || *p == NUL)
3945 p = mch_getenv((char_u *)"LC_MESSAGES");
3946 if (p == NULL || *p == NUL)
3947 p = mch_getenv((char_u *)"LANG");
3949 # endif
3950 # ifdef WIN32
3951 p = gettext_lang(p);
3952 # endif
3953 return p;
3955 #endif
3957 /* Complicated #if; matches with where get_mess_env() is used below. */
3958 #if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3959 && defined(LC_MESSAGES))) \
3960 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3961 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3962 && !defined(LC_MESSAGES))
3963 static char_u *get_mess_env __ARGS((void));
3966 * Get the language used for messages from the environment.
3968 static char_u *
3969 get_mess_env()
3971 char_u *p;
3973 p = mch_getenv((char_u *)"LC_ALL");
3974 if (p == NULL || *p == NUL)
3976 p = mch_getenv((char_u *)"LC_MESSAGES");
3977 if (p == NULL || *p == NUL)
3979 p = mch_getenv((char_u *)"LANG");
3980 if (p != NULL && VIM_ISDIGIT(*p))
3981 p = NULL; /* ignore something like "1043" */
3982 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3983 if (p == NULL || *p == NUL)
3984 p = (char_u *)get_locale_val(LC_CTYPE);
3985 # endif
3988 return p;
3990 #endif
3992 #if defined(FEAT_EVAL) || defined(PROTO)
3995 * Set the "v:lang" variable according to the current locale setting.
3996 * Also do "v:lc_time"and "v:ctype".
3998 void
3999 set_lang_var()
4001 char_u *loc;
4003 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4004 loc = (char_u *)get_locale_val(LC_CTYPE);
4005 # else
4006 /* setlocale() not supported: use the default value */
4007 loc = (char_u *)"C";
4008 # endif
4009 set_vim_var_string(VV_CTYPE, loc, -1);
4011 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4012 * back to LC_CTYPE if it's empty. */
4013 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
4014 loc = (char_u *)get_locale_val(LC_MESSAGES);
4015 # else
4016 loc = get_mess_env();
4017 # endif
4018 set_vim_var_string(VV_LANG, loc, -1);
4020 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4021 loc = (char_u *)get_locale_val(LC_TIME);
4022 # endif
4023 set_vim_var_string(VV_LC_TIME, loc, -1);
4025 #endif
4027 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4028 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4030 * ":language": Set the language (locale).
4032 void
4033 ex_language(eap)
4034 exarg_T *eap;
4036 char *loc;
4037 char_u *p;
4038 char_u *name;
4039 int what = LC_ALL;
4040 char *whatstr = "";
4041 #ifdef LC_MESSAGES
4042 # define VIM_LC_MESSAGES LC_MESSAGES
4043 #else
4044 # define VIM_LC_MESSAGES 6789
4045 #endif
4047 name = eap->arg;
4049 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4050 * Allow abbreviation, but require at least 3 characters to avoid
4051 * confusion with a two letter language name "me" or "ct". */
4052 p = skiptowhite(eap->arg);
4053 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4055 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4057 what = VIM_LC_MESSAGES;
4058 name = skipwhite(p);
4059 whatstr = "messages ";
4061 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4063 what = LC_CTYPE;
4064 name = skipwhite(p);
4065 whatstr = "ctype ";
4067 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4069 what = LC_TIME;
4070 name = skipwhite(p);
4071 whatstr = "time ";
4075 if (*name == NUL)
4077 #ifndef LC_MESSAGES
4078 if (what == VIM_LC_MESSAGES)
4079 p = get_mess_env();
4080 else
4081 #endif
4082 p = (char_u *)setlocale(what, NULL);
4083 if (p == NULL || *p == NUL)
4084 p = (char_u *)"Unknown";
4085 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4087 else
4089 #ifndef LC_MESSAGES
4090 if (what == VIM_LC_MESSAGES)
4091 loc = "";
4092 else
4093 #endif
4095 loc = setlocale(what, (char *)name);
4096 #if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4097 /* Make sure strtod() uses a decimal point, not a comma. */
4098 setlocale(LC_NUMERIC, "C");
4099 #endif
4101 if (loc == NULL)
4102 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4103 else
4105 #ifdef HAVE_NL_MSG_CAT_CNTR
4106 /* Need to do this for GNU gettext, otherwise cached translations
4107 * will be used again. */
4108 extern int _nl_msg_cat_cntr;
4110 ++_nl_msg_cat_cntr;
4111 #endif
4112 /* Reset $LC_ALL, otherwise it would overrule everything. */
4113 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4115 if (what != LC_TIME)
4117 /* Tell gettext() what to translate to. It apparently doesn't
4118 * use the currently effective locale. Also do this when
4119 * FEAT_GETTEXT isn't defined, so that shell commands use this
4120 * value. */
4121 if (what == LC_ALL)
4123 vim_setenv((char_u *)"LANG", name);
4124 # ifdef WIN32
4125 /* Apparently MS-Windows printf() may cause a crash when
4126 * we give it 8-bit text while it's expecting text in the
4127 * current locale. This call avoids that. */
4128 setlocale(LC_CTYPE, "C");
4129 # endif
4131 if (what != LC_CTYPE)
4133 char_u *mname;
4134 #ifdef WIN32
4135 mname = gettext_lang(name);
4136 #else
4137 mname = name;
4138 #endif
4139 vim_setenv((char_u *)"LC_MESSAGES", mname);
4140 #ifdef FEAT_MULTI_LANG
4141 set_helplang_default(mname);
4142 #endif
4145 /* Set $LC_CTYPE, because it overrules $LANG, and
4146 * gtk_set_locale() calls setlocale() again. gnome_init()
4147 * sets $LC_CTYPE to "en_US" (that's a bug!). */
4148 if (what != VIM_LC_MESSAGES)
4149 vim_setenv((char_u *)"LC_CTYPE", name);
4150 # ifdef FEAT_GUI_GTK
4151 /* Let GTK know what locale we're using. Not sure this is
4152 * really needed... */
4153 if (gui.in_use)
4154 (void)gtk_set_locale();
4155 # endif
4158 # ifdef FEAT_EVAL
4159 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4160 set_lang_var();
4161 # endif
4166 # if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4168 * Function given to ExpandGeneric() to obtain the possible arguments of the
4169 * ":language" command.
4171 char_u *
4172 get_lang_arg(xp, idx)
4173 expand_T *xp UNUSED;
4174 int idx;
4176 if (idx == 0)
4177 return (char_u *)"messages";
4178 if (idx == 1)
4179 return (char_u *)"ctype";
4180 if (idx == 2)
4181 return (char_u *)"time";
4182 return NULL;
4184 # endif
4186 #endif