Merged from the latest developing branch.
[MacVim.git] / src / ex_cmds2.c
blob0fcb6c7a71a64ffe3ab7fbc9534f223b7c055cad
1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
11 * ex_cmds2.c: some more functions for command line commands
14 #if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
15 # include "vimio.h" /* for mch_open(), must be before vim.h */
16 #endif
18 #include "vim.h"
19 #include "version.h"
21 static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
23 #ifdef FEAT_EVAL
24 /* Growarray to store info about already sourced scripts.
25 * For Unix also store the dev/ino, so that we don't have to stat() each
26 * script when going through the list. */
27 typedef struct scriptitem_S
29 char_u *sn_name;
30 # ifdef UNIX
31 int sn_dev_valid;
32 dev_t sn_dev;
33 ino_t sn_ino;
34 # endif
35 # ifdef FEAT_PROFILE
36 int sn_prof_on; /* TRUE when script is/was profiled */
37 int sn_pr_force; /* forceit: profile functions in this script */
38 proftime_T sn_pr_child; /* time set when going into first child */
39 int sn_pr_nest; /* nesting for sn_pr_child */
40 /* profiling the script as a whole */
41 int sn_pr_count; /* nr of times sourced */
42 proftime_T sn_pr_total; /* time spent in script + children */
43 proftime_T sn_pr_self; /* time spent in script itself */
44 proftime_T sn_pr_start; /* time at script start */
45 proftime_T sn_pr_children; /* time in children after script start */
46 /* profiling the script per line */
47 garray_T sn_prl_ga; /* things stored for every line */
48 proftime_T sn_prl_start; /* start time for current line */
49 proftime_T sn_prl_children; /* time spent in children for this line */
50 proftime_T sn_prl_wait; /* wait start time for current line */
51 int sn_prl_idx; /* index of line being timed; -1 if none */
52 int sn_prl_execed; /* line being timed was executed */
53 # endif
54 } scriptitem_T;
56 static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
57 #define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
59 # ifdef FEAT_PROFILE
60 /* Struct used in sn_prl_ga for every line of a script. */
61 typedef struct sn_prl_S
63 int snp_count; /* nr of times line was executed */
64 proftime_T sn_prl_total; /* time spent in a line + children */
65 proftime_T sn_prl_self; /* time spent in a line itself */
66 } sn_prl_T;
68 # define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
69 # endif
70 #endif
72 #if defined(FEAT_EVAL) || defined(PROTO)
73 static int debug_greedy = FALSE; /* batch mode debugging: don't save
74 and restore typeahead. */
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
80 void
81 do_debug(cmd)
82 char_u *cmd;
84 int save_msg_scroll = msg_scroll;
85 int save_State = State;
86 int save_did_emsg = did_emsg;
87 int save_cmd_silent = cmd_silent;
88 int save_msg_silent = msg_silent;
89 int save_emsg_silent = emsg_silent;
90 int save_redir_off = redir_off;
91 tasave_T typeaheadbuf;
92 int typeahead_saved = FALSE;
93 int save_ignore_script = 0;
94 # ifdef FEAT_EX_EXTRA
95 int save_ex_normal_busy;
96 # endif
97 int n;
98 char_u *cmdline = NULL;
99 char_u *p;
100 char *tail = NULL;
101 static int last_cmd = 0;
102 #define CMD_CONT 1
103 #define CMD_NEXT 2
104 #define CMD_STEP 3
105 #define CMD_FINISH 4
106 #define CMD_QUIT 5
107 #define CMD_INTERRUPT 6
109 #ifdef ALWAYS_USE_GUI
110 /* Can't do this when there is no terminal for input/output. */
111 if (!gui.in_use)
113 /* Break as soon as possible. */
114 debug_break_level = 9999;
115 return;
117 #endif
119 /* Make sure we are in raw mode and start termcap mode. Might have side
120 * effects... */
121 settmode(TMODE_RAW);
122 starttermcap();
124 ++RedrawingDisabled; /* don't redisplay the window */
125 ++no_wait_return; /* don't wait for return */
126 did_emsg = FALSE; /* don't use error from debugged stuff */
127 cmd_silent = FALSE; /* display commands */
128 msg_silent = FALSE; /* display messages */
129 emsg_silent = FALSE; /* display error messages */
130 redir_off = TRUE; /* don't redirect debug commands */
132 State = NORMAL;
133 #ifdef FEAT_SNIFF
134 want_sniff_request = 0; /* No K_SNIFF wanted */
135 #endif
137 if (!debug_did_msg)
138 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
139 if (sourcing_name != NULL)
140 msg(sourcing_name);
141 if (sourcing_lnum != 0)
142 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
143 else
144 smsg((char_u *)_("cmd: %s"), cmd);
147 * Repeat getting a command and executing it.
149 for (;;)
151 msg_scroll = TRUE;
152 need_wait_return = FALSE;
153 #ifdef FEAT_SNIFF
154 ProcessSniffRequests();
155 #endif
156 /* Save the current typeahead buffer and replace it with an empty one.
157 * This makes sure we get input from the user here and don't interfere
158 * with the commands being executed. Reset "ex_normal_busy" to avoid
159 * the side effects of using ":normal". Save the stuff buffer and make
160 * it empty. Set ignore_script to avoid reading from script input. */
161 # ifdef FEAT_EX_EXTRA
162 save_ex_normal_busy = ex_normal_busy;
163 ex_normal_busy = 0;
164 # endif
165 if (!debug_greedy)
167 save_typeahead(&typeaheadbuf);
168 typeahead_saved = TRUE;
169 save_ignore_script = ignore_script;
170 ignore_script = TRUE;
173 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
175 if (typeahead_saved)
177 restore_typeahead(&typeaheadbuf);
178 ignore_script = save_ignore_script;
180 # ifdef FEAT_EX_EXTRA
181 ex_normal_busy = save_ex_normal_busy;
182 # endif
184 cmdline_row = msg_row;
185 if (cmdline != NULL)
187 /* If this is a debug command, set "last_cmd".
188 * If not, reset "last_cmd".
189 * For a blank line use previous command. */
190 p = skipwhite(cmdline);
191 if (*p != NUL)
193 switch (*p)
195 case 'c': last_cmd = CMD_CONT;
196 tail = "ont";
197 break;
198 case 'n': last_cmd = CMD_NEXT;
199 tail = "ext";
200 break;
201 case 's': last_cmd = CMD_STEP;
202 tail = "tep";
203 break;
204 case 'f': last_cmd = CMD_FINISH;
205 tail = "inish";
206 break;
207 case 'q': last_cmd = CMD_QUIT;
208 tail = "uit";
209 break;
210 case 'i': last_cmd = CMD_INTERRUPT;
211 tail = "nterrupt";
212 break;
213 default: last_cmd = 0;
215 if (last_cmd != 0)
217 /* Check that the tail matches. */
218 ++p;
219 while (*p != NUL && *p == *tail)
221 ++p;
222 ++tail;
224 if (ASCII_ISALPHA(*p))
225 last_cmd = 0;
229 if (last_cmd != 0)
231 /* Execute debug command: decided where to break next and
232 * return. */
233 switch (last_cmd)
235 case CMD_CONT:
236 debug_break_level = -1;
237 break;
238 case CMD_NEXT:
239 debug_break_level = ex_nesting_level;
240 break;
241 case CMD_STEP:
242 debug_break_level = 9999;
243 break;
244 case CMD_FINISH:
245 debug_break_level = ex_nesting_level - 1;
246 break;
247 case CMD_QUIT:
248 got_int = TRUE;
249 debug_break_level = -1;
250 break;
251 case CMD_INTERRUPT:
252 got_int = TRUE;
253 debug_break_level = 9999;
254 /* Do not repeat ">interrupt" cmd, continue stepping. */
255 last_cmd = CMD_STEP;
256 break;
258 break;
261 /* don't debug this command */
262 n = debug_break_level;
263 debug_break_level = -1;
264 (void)do_cmdline(cmdline, getexline, NULL,
265 DOCMD_VERBOSE|DOCMD_EXCRESET);
266 debug_break_level = n;
268 vim_free(cmdline);
270 lines_left = Rows - 1;
272 vim_free(cmdline);
274 --RedrawingDisabled;
275 --no_wait_return;
276 redraw_all_later(NOT_VALID);
277 need_wait_return = FALSE;
278 msg_scroll = save_msg_scroll;
279 lines_left = Rows - 1;
280 State = save_State;
281 did_emsg = save_did_emsg;
282 cmd_silent = save_cmd_silent;
283 msg_silent = save_msg_silent;
284 emsg_silent = save_emsg_silent;
285 redir_off = save_redir_off;
287 /* Only print the message again when typing a command before coming back
288 * here. */
289 debug_did_msg = TRUE;
293 * ":debug".
295 void
296 ex_debug(eap)
297 exarg_T *eap;
299 int debug_break_level_save = debug_break_level;
301 debug_break_level = 9999;
302 do_cmdline_cmd(eap->arg);
303 debug_break_level = debug_break_level_save;
306 static char_u *debug_breakpoint_name = NULL;
307 static linenr_T debug_breakpoint_lnum;
310 * When debugging or a breakpoint is set on a skipped command, no debug prompt
311 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
312 * debug_skipped_name is then set to the source name in the breakpoint case. If
313 * a skipped command decides itself that a debug prompt should be displayed, it
314 * can do so by calling dbg_check_skipped().
316 static int debug_skipped;
317 static char_u *debug_skipped_name;
320 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
321 * at or below the break level. But only when the line is actually
322 * executed. Return TRUE and set breakpoint_name for skipped commands that
323 * decide to execute something themselves.
324 * Called from do_one_cmd() before executing a command.
326 void
327 dbg_check_breakpoint(eap)
328 exarg_T *eap;
330 char_u *p;
332 debug_skipped = FALSE;
333 if (debug_breakpoint_name != NULL)
335 if (!eap->skip)
337 /* replace K_SNR with "<SNR>" */
338 if (debug_breakpoint_name[0] == K_SPECIAL
339 && debug_breakpoint_name[1] == KS_EXTRA
340 && debug_breakpoint_name[2] == (int)KE_SNR)
341 p = (char_u *)"<SNR>";
342 else
343 p = (char_u *)"";
344 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
346 debug_breakpoint_name + (*p == NUL ? 0 : 3),
347 (long)debug_breakpoint_lnum);
348 debug_breakpoint_name = NULL;
349 do_debug(eap->cmd);
351 else
353 debug_skipped = TRUE;
354 debug_skipped_name = debug_breakpoint_name;
355 debug_breakpoint_name = NULL;
358 else if (ex_nesting_level <= debug_break_level)
360 if (!eap->skip)
361 do_debug(eap->cmd);
362 else
364 debug_skipped = TRUE;
365 debug_skipped_name = NULL;
371 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
372 * set. Return TRUE when the debug mode is entered this time.
375 dbg_check_skipped(eap)
376 exarg_T *eap;
378 int prev_got_int;
380 if (debug_skipped)
383 * Save the value of got_int and reset it. We don't want a previous
384 * interruption cause flushing the input buffer.
386 prev_got_int = got_int;
387 got_int = FALSE;
388 debug_breakpoint_name = debug_skipped_name;
389 /* eap->skip is TRUE */
390 eap->skip = FALSE;
391 (void)dbg_check_breakpoint(eap);
392 eap->skip = TRUE;
393 got_int |= prev_got_int;
394 return TRUE;
396 return FALSE;
400 * The list of breakpoints: dbg_breakp.
401 * This is a grow-array of structs.
403 struct debuggy
405 int dbg_nr; /* breakpoint number */
406 int dbg_type; /* DBG_FUNC or DBG_FILE */
407 char_u *dbg_name; /* function or file name */
408 regprog_T *dbg_prog; /* regexp program */
409 linenr_T dbg_lnum; /* line number in function or file */
410 int dbg_forceit; /* ! used */
413 static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
414 #define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
415 #define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
416 static int last_breakp = 0; /* nr of last defined breakpoint */
418 #ifdef FEAT_PROFILE
419 /* Profiling uses file and func names similar to breakpoints. */
420 static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
421 #endif
422 #define DBG_FUNC 1
423 #define DBG_FILE 2
425 static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
426 static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, garray_T *gap, int *fp));
429 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
430 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
431 * is allocated.
432 * Returns FAIL for failure.
434 static int
435 dbg_parsearg(arg, gap)
436 char_u *arg;
437 garray_T *gap; /* either &dbg_breakp or &prof_ga */
439 char_u *p = arg;
440 char_u *q;
441 struct debuggy *bp;
442 int here = FALSE;
444 if (ga_grow(gap, 1) == FAIL)
445 return FAIL;
446 bp = &DEBUGGY(gap, gap->ga_len);
448 /* Find "func" or "file". */
449 if (STRNCMP(p, "func", 4) == 0)
450 bp->dbg_type = DBG_FUNC;
451 else if (STRNCMP(p, "file", 4) == 0)
452 bp->dbg_type = DBG_FILE;
453 else if (
454 #ifdef FEAT_PROFILE
455 gap != &prof_ga &&
456 #endif
457 STRNCMP(p, "here", 4) == 0)
459 if (curbuf->b_ffname == NULL)
461 EMSG(_(e_noname));
462 return FAIL;
464 bp->dbg_type = DBG_FILE;
465 here = TRUE;
467 else
469 EMSG2(_(e_invarg2), p);
470 return FAIL;
472 p = skipwhite(p + 4);
474 /* Find optional line number. */
475 if (here)
476 bp->dbg_lnum = curwin->w_cursor.lnum;
477 else if (
478 #ifdef FEAT_PROFILE
479 gap != &prof_ga &&
480 #endif
481 VIM_ISDIGIT(*p))
483 bp->dbg_lnum = getdigits(&p);
484 p = skipwhite(p);
486 else
487 bp->dbg_lnum = 0;
489 /* Find the function or file name. Don't accept a function name with (). */
490 if ((!here && *p == NUL)
491 || (here && *p != NUL)
492 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
494 EMSG2(_(e_invarg2), arg);
495 return FAIL;
498 if (bp->dbg_type == DBG_FUNC)
499 bp->dbg_name = vim_strsave(p);
500 else if (here)
501 bp->dbg_name = vim_strsave(curbuf->b_ffname);
502 else
504 /* Expand the file name in the same way as do_source(). This means
505 * doing it twice, so that $DIR/file gets expanded when $DIR is
506 * "~/dir". */
507 #ifdef RISCOS
508 q = mch_munge_fname(p);
509 #else
510 q = expand_env_save(p);
511 #endif
512 if (q == NULL)
513 return FAIL;
514 #ifdef RISCOS
515 p = mch_munge_fname(q);
516 #else
517 p = expand_env_save(q);
518 #endif
519 vim_free(q);
520 if (p == NULL)
521 return FAIL;
522 if (*p != '*')
524 bp->dbg_name = fix_fname(p);
525 vim_free(p);
527 else
528 bp->dbg_name = p;
531 if (bp->dbg_name == NULL)
532 return FAIL;
533 return OK;
537 * ":breakadd".
539 void
540 ex_breakadd(eap)
541 exarg_T *eap;
543 struct debuggy *bp;
544 char_u *pat;
545 garray_T *gap;
547 gap = &dbg_breakp;
548 #ifdef FEAT_PROFILE
549 if (eap->cmdidx == CMD_profile)
550 gap = &prof_ga;
551 #endif
553 if (dbg_parsearg(eap->arg, gap) == OK)
555 bp = &DEBUGGY(gap, gap->ga_len);
556 bp->dbg_forceit = eap->forceit;
558 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
559 if (pat != NULL)
561 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
562 vim_free(pat);
564 if (pat == NULL || bp->dbg_prog == NULL)
565 vim_free(bp->dbg_name);
566 else
568 if (bp->dbg_lnum == 0) /* default line number is 1 */
569 bp->dbg_lnum = 1;
570 #ifdef FEAT_PROFILE
571 if (eap->cmdidx != CMD_profile)
572 #endif
574 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
575 ++debug_tick;
577 ++gap->ga_len;
583 * ":debuggreedy".
585 void
586 ex_debuggreedy(eap)
587 exarg_T *eap;
589 if (eap->addr_count == 0 || eap->line2 != 0)
590 debug_greedy = TRUE;
591 else
592 debug_greedy = FALSE;
596 * ":breakdel" and ":profdel".
598 void
599 ex_breakdel(eap)
600 exarg_T *eap;
602 struct debuggy *bp, *bpi;
603 int nr;
604 int todel = -1;
605 int del_all = FALSE;
606 int i;
607 linenr_T best_lnum = 0;
608 garray_T *gap;
610 gap = &dbg_breakp;
611 #ifdef FEAT_PROFILE
612 if (eap->cmdidx == CMD_profdel)
613 gap = &prof_ga;
614 #endif
616 if (vim_isdigit(*eap->arg))
618 /* ":breakdel {nr}" */
619 nr = atol((char *)eap->arg);
620 for (i = 0; i < gap->ga_len; ++i)
621 if (DEBUGGY(gap, i).dbg_nr == nr)
623 todel = i;
624 break;
627 else if (*eap->arg == '*')
629 todel = 0;
630 del_all = TRUE;
632 else
634 /* ":breakdel {func|file} [lnum] {name}" */
635 if (dbg_parsearg(eap->arg, gap) == FAIL)
636 return;
637 bp = &DEBUGGY(gap, gap->ga_len);
638 for (i = 0; i < gap->ga_len; ++i)
640 bpi = &DEBUGGY(gap, i);
641 if (bp->dbg_type == bpi->dbg_type
642 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
643 && (bp->dbg_lnum == bpi->dbg_lnum
644 || (bp->dbg_lnum == 0
645 && (best_lnum == 0
646 || bpi->dbg_lnum < best_lnum))))
648 todel = i;
649 best_lnum = bpi->dbg_lnum;
652 vim_free(bp->dbg_name);
655 if (todel < 0)
656 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
657 else
659 while (gap->ga_len > 0)
661 vim_free(DEBUGGY(gap, todel).dbg_name);
662 vim_free(DEBUGGY(gap, todel).dbg_prog);
663 --gap->ga_len;
664 if (todel < gap->ga_len)
665 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
666 (gap->ga_len - todel) * sizeof(struct debuggy));
667 #ifdef FEAT_PROFILE
668 if (eap->cmdidx == CMD_breakdel)
669 #endif
670 ++debug_tick;
671 if (!del_all)
672 break;
675 /* If all breakpoints were removed clear the array. */
676 if (gap->ga_len == 0)
677 ga_clear(gap);
682 * ":breaklist".
684 void
685 ex_breaklist(eap)
686 exarg_T *eap UNUSED;
688 struct debuggy *bp;
689 int i;
691 if (dbg_breakp.ga_len == 0)
692 MSG(_("No breakpoints defined"));
693 else
694 for (i = 0; i < dbg_breakp.ga_len; ++i)
696 bp = &BREAKP(i);
697 smsg((char_u *)_("%3d %s %s line %ld"),
698 bp->dbg_nr,
699 bp->dbg_type == DBG_FUNC ? "func" : "file",
700 bp->dbg_name,
701 (long)bp->dbg_lnum);
706 * Find a breakpoint for a function or sourced file.
707 * Returns line number at which to break; zero when no matching breakpoint.
709 linenr_T
710 dbg_find_breakpoint(file, fname, after)
711 int file; /* TRUE for a file, FALSE for a function */
712 char_u *fname; /* file or function name */
713 linenr_T after; /* after this line number */
715 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
718 #if defined(FEAT_PROFILE) || defined(PROTO)
720 * Return TRUE if profiling is on for a function or sourced file.
723 has_profiling(file, fname, fp)
724 int file; /* TRUE for a file, FALSE for a function */
725 char_u *fname; /* file or function name */
726 int *fp; /* return: forceit */
728 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
729 != (linenr_T)0);
731 #endif
734 * Common code for dbg_find_breakpoint() and has_profiling().
736 static linenr_T
737 debuggy_find(file, fname, after, gap, fp)
738 int file; /* TRUE for a file, FALSE for a function */
739 char_u *fname; /* file or function name */
740 linenr_T after; /* after this line number */
741 garray_T *gap; /* either &dbg_breakp or &prof_ga */
742 int *fp; /* if not NULL: return forceit */
744 struct debuggy *bp;
745 int i;
746 linenr_T lnum = 0;
747 regmatch_T regmatch;
748 char_u *name = fname;
749 int prev_got_int;
751 /* Return quickly when there are no breakpoints. */
752 if (gap->ga_len == 0)
753 return (linenr_T)0;
755 /* Replace K_SNR in function name with "<SNR>". */
756 if (!file && fname[0] == K_SPECIAL)
758 name = alloc((unsigned)STRLEN(fname) + 3);
759 if (name == NULL)
760 name = fname;
761 else
763 STRCPY(name, "<SNR>");
764 STRCPY(name + 5, fname + 3);
768 for (i = 0; i < gap->ga_len; ++i)
770 /* Skip entries that are not useful or are for a line that is beyond
771 * an already found breakpoint. */
772 bp = &DEBUGGY(gap, i);
773 if (((bp->dbg_type == DBG_FILE) == file && (
774 #ifdef FEAT_PROFILE
775 gap == &prof_ga ||
776 #endif
777 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
779 regmatch.regprog = bp->dbg_prog;
780 regmatch.rm_ic = FALSE;
782 * Save the value of got_int and reset it. We don't want a
783 * previous interruption cancel matching, only hitting CTRL-C
784 * while matching should abort it.
786 prev_got_int = got_int;
787 got_int = FALSE;
788 if (vim_regexec(&regmatch, name, (colnr_T)0))
790 lnum = bp->dbg_lnum;
791 if (fp != NULL)
792 *fp = bp->dbg_forceit;
794 got_int |= prev_got_int;
797 if (name != fname)
798 vim_free(name);
800 return lnum;
804 * Called when a breakpoint was encountered.
806 void
807 dbg_breakpoint(name, lnum)
808 char_u *name;
809 linenr_T lnum;
811 /* We need to check if this line is actually executed in do_one_cmd() */
812 debug_breakpoint_name = name;
813 debug_breakpoint_lnum = lnum;
817 # if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
819 * Store the current time in "tm".
821 void
822 profile_start(tm)
823 proftime_T *tm;
825 # ifdef WIN3264
826 QueryPerformanceCounter(tm);
827 # else
828 gettimeofday(tm, NULL);
829 # endif
833 * Compute the elapsed time from "tm" till now and store in "tm".
835 void
836 profile_end(tm)
837 proftime_T *tm;
839 proftime_T now;
841 # ifdef WIN3264
842 QueryPerformanceCounter(&now);
843 tm->QuadPart = now.QuadPart - tm->QuadPart;
844 # else
845 gettimeofday(&now, NULL);
846 tm->tv_usec = now.tv_usec - tm->tv_usec;
847 tm->tv_sec = now.tv_sec - tm->tv_sec;
848 if (tm->tv_usec < 0)
850 tm->tv_usec += 1000000;
851 --tm->tv_sec;
853 # endif
857 * Subtract the time "tm2" from "tm".
859 void
860 profile_sub(tm, tm2)
861 proftime_T *tm, *tm2;
863 # ifdef WIN3264
864 tm->QuadPart -= tm2->QuadPart;
865 # else
866 tm->tv_usec -= tm2->tv_usec;
867 tm->tv_sec -= tm2->tv_sec;
868 if (tm->tv_usec < 0)
870 tm->tv_usec += 1000000;
871 --tm->tv_sec;
873 # endif
877 * Return a string that represents the time in "tm".
878 * Uses a static buffer!
880 char *
881 profile_msg(tm)
882 proftime_T *tm;
884 static char buf[50];
886 # ifdef WIN3264
887 LARGE_INTEGER fr;
889 QueryPerformanceFrequency(&fr);
890 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
891 # else
892 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
893 # endif
894 return buf;
898 * Put the time "msec" past now in "tm".
900 void
901 profile_setlimit(msec, tm)
902 long msec;
903 proftime_T *tm;
905 if (msec <= 0) /* no limit */
906 profile_zero(tm);
907 else
909 # ifdef WIN3264
910 LARGE_INTEGER fr;
912 QueryPerformanceCounter(tm);
913 QueryPerformanceFrequency(&fr);
914 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
915 # else
916 long usec;
918 gettimeofday(tm, NULL);
919 usec = (long)tm->tv_usec + (long)msec * 1000;
920 tm->tv_usec = usec % 1000000L;
921 tm->tv_sec += usec / 1000000L;
922 # endif
927 * Return TRUE if the current time is past "tm".
930 profile_passed_limit(tm)
931 proftime_T *tm;
933 proftime_T now;
935 # ifdef WIN3264
936 if (tm->QuadPart == 0) /* timer was not set */
937 return FALSE;
938 QueryPerformanceCounter(&now);
939 return (now.QuadPart > tm->QuadPart);
940 # else
941 if (tm->tv_sec == 0) /* timer was not set */
942 return FALSE;
943 gettimeofday(&now, NULL);
944 return (now.tv_sec > tm->tv_sec
945 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
946 # endif
950 * Set the time in "tm" to zero.
952 void
953 profile_zero(tm)
954 proftime_T *tm;
956 # ifdef WIN3264
957 tm->QuadPart = 0;
958 # else
959 tm->tv_usec = 0;
960 tm->tv_sec = 0;
961 # endif
964 # endif /* FEAT_PROFILE || FEAT_RELTIME */
966 # if defined(FEAT_PROFILE) || defined(PROTO)
968 * Functions for profiling.
970 static void script_do_profile __ARGS((scriptitem_T *si));
971 static void script_dump_profile __ARGS((FILE *fd));
972 static proftime_T prof_wait_time;
975 * Add the time "tm2" to "tm".
977 void
978 profile_add(tm, tm2)
979 proftime_T *tm, *tm2;
981 # ifdef WIN3264
982 tm->QuadPart += tm2->QuadPart;
983 # else
984 tm->tv_usec += tm2->tv_usec;
985 tm->tv_sec += tm2->tv_sec;
986 if (tm->tv_usec >= 1000000)
988 tm->tv_usec -= 1000000;
989 ++tm->tv_sec;
991 # endif
995 * Add the "self" time from the total time and the children's time.
997 void
998 profile_self(self, total, children)
999 proftime_T *self, *total, *children;
1001 /* Check that the result won't be negative. Can happen with recursive
1002 * calls. */
1003 #ifdef WIN3264
1004 if (total->QuadPart <= children->QuadPart)
1005 return;
1006 #else
1007 if (total->tv_sec < children->tv_sec
1008 || (total->tv_sec == children->tv_sec
1009 && total->tv_usec <= children->tv_usec))
1010 return;
1011 #endif
1012 profile_add(self, total);
1013 profile_sub(self, children);
1017 * Get the current waittime.
1019 void
1020 profile_get_wait(tm)
1021 proftime_T *tm;
1023 *tm = prof_wait_time;
1027 * Subtract the passed waittime since "tm" from "tma".
1029 void
1030 profile_sub_wait(tm, tma)
1031 proftime_T *tm, *tma;
1033 proftime_T tm3 = prof_wait_time;
1035 profile_sub(&tm3, tm);
1036 profile_sub(tma, &tm3);
1040 * Return TRUE if "tm1" and "tm2" are equal.
1043 profile_equal(tm1, tm2)
1044 proftime_T *tm1, *tm2;
1046 # ifdef WIN3264
1047 return (tm1->QuadPart == tm2->QuadPart);
1048 # else
1049 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
1050 # endif
1054 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1057 profile_cmp(tm1, tm2)
1058 proftime_T *tm1, *tm2;
1060 # ifdef WIN3264
1061 return (int)(tm2->QuadPart - tm1->QuadPart);
1062 # else
1063 if (tm1->tv_sec == tm2->tv_sec)
1064 return tm2->tv_usec - tm1->tv_usec;
1065 return tm2->tv_sec - tm1->tv_sec;
1066 # endif
1069 static char_u *profile_fname = NULL;
1070 static proftime_T pause_time;
1073 * ":profile cmd args"
1075 void
1076 ex_profile(eap)
1077 exarg_T *eap;
1079 char_u *e;
1080 int len;
1082 e = skiptowhite(eap->arg);
1083 len = (int)(e - eap->arg);
1084 e = skipwhite(e);
1086 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1088 vim_free(profile_fname);
1089 profile_fname = vim_strsave(e);
1090 do_profiling = PROF_YES;
1091 profile_zero(&prof_wait_time);
1092 set_vim_var_nr(VV_PROFILING, 1L);
1094 else if (do_profiling == PROF_NONE)
1095 EMSG(_("E750: First use \":profile start {fname}\""));
1096 else if (STRCMP(eap->arg, "pause") == 0)
1098 if (do_profiling == PROF_YES)
1099 profile_start(&pause_time);
1100 do_profiling = PROF_PAUSED;
1102 else if (STRCMP(eap->arg, "continue") == 0)
1104 if (do_profiling == PROF_PAUSED)
1106 profile_end(&pause_time);
1107 profile_add(&prof_wait_time, &pause_time);
1109 do_profiling = PROF_YES;
1111 else
1113 /* The rest is similar to ":breakadd". */
1114 ex_breakadd(eap);
1118 /* Command line expansion for :profile. */
1119 static enum
1121 PEXP_SUBCMD, /* expand :profile sub-commands */
1122 PEXP_FUNC, /* expand :profile func {funcname} */
1123 } pexpand_what;
1125 static char *pexpand_cmds[] = {
1126 "start",
1127 #define PROFCMD_START 0
1128 "pause",
1129 #define PROFCMD_PAUSE 1
1130 "continue",
1131 #define PROFCMD_CONTINUE 2
1132 "func",
1133 #define PROFCMD_FUNC 3
1134 "file",
1135 #define PROFCMD_FILE 4
1136 NULL
1137 #define PROFCMD_LAST 5
1141 * Function given to ExpandGeneric() to obtain the profile command
1142 * specific expansion.
1144 char_u *
1145 get_profile_name(xp, idx)
1146 expand_T *xp UNUSED;
1147 int idx;
1149 switch (pexpand_what)
1151 case PEXP_SUBCMD:
1152 return (char_u *)pexpand_cmds[idx];
1153 /* case PEXP_FUNC: TODO */
1154 default:
1155 return NULL;
1160 * Handle command line completion for :profile command.
1162 void
1163 set_context_in_profile_cmd(xp, arg)
1164 expand_T *xp;
1165 char_u *arg;
1167 char_u *end_subcmd;
1168 int len;
1170 /* Default: expand subcommands. */
1171 xp->xp_context = EXPAND_PROFILE;
1172 pexpand_what = PEXP_SUBCMD;
1173 xp->xp_pattern = arg;
1175 end_subcmd = skiptowhite(arg);
1176 if (*end_subcmd == NUL)
1177 return;
1179 len = end_subcmd - arg;
1180 if (len == 5 && STRNCMP(arg, "start", 5) == 0)
1182 xp->xp_context = EXPAND_FILES;
1183 xp->xp_pattern = skipwhite(end_subcmd);
1184 return;
1187 /* TODO: expand function names after "func" */
1188 xp->xp_context = EXPAND_NOTHING;
1192 * Dump the profiling info.
1194 void
1195 profile_dump()
1197 FILE *fd;
1199 if (profile_fname != NULL)
1201 fd = mch_fopen((char *)profile_fname, "w");
1202 if (fd == NULL)
1203 EMSG2(_(e_notopen), profile_fname);
1204 else
1206 script_dump_profile(fd);
1207 func_dump_profile(fd);
1208 fclose(fd);
1214 * Start profiling script "fp".
1216 static void
1217 script_do_profile(si)
1218 scriptitem_T *si;
1220 si->sn_pr_count = 0;
1221 profile_zero(&si->sn_pr_total);
1222 profile_zero(&si->sn_pr_self);
1224 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1225 si->sn_prl_idx = -1;
1226 si->sn_prof_on = TRUE;
1227 si->sn_pr_nest = 0;
1231 * save time when starting to invoke another script or function.
1233 void
1234 script_prof_save(tm)
1235 proftime_T *tm; /* place to store wait time */
1237 scriptitem_T *si;
1239 if (current_SID > 0 && current_SID <= script_items.ga_len)
1241 si = &SCRIPT_ITEM(current_SID);
1242 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1243 profile_start(&si->sn_pr_child);
1245 profile_get_wait(tm);
1249 * Count time spent in children after invoking another script or function.
1251 void
1252 script_prof_restore(tm)
1253 proftime_T *tm;
1255 scriptitem_T *si;
1257 if (current_SID > 0 && current_SID <= script_items.ga_len)
1259 si = &SCRIPT_ITEM(current_SID);
1260 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1262 profile_end(&si->sn_pr_child);
1263 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1264 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1265 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1270 static proftime_T inchar_time;
1273 * Called when starting to wait for the user to type a character.
1275 void
1276 prof_inchar_enter()
1278 profile_start(&inchar_time);
1282 * Called when finished waiting for the user to type a character.
1284 void
1285 prof_inchar_exit()
1287 profile_end(&inchar_time);
1288 profile_add(&prof_wait_time, &inchar_time);
1292 * Dump the profiling results for all scripts in file "fd".
1294 static void
1295 script_dump_profile(fd)
1296 FILE *fd;
1298 int id;
1299 scriptitem_T *si;
1300 int i;
1301 FILE *sfd;
1302 sn_prl_T *pp;
1304 for (id = 1; id <= script_items.ga_len; ++id)
1306 si = &SCRIPT_ITEM(id);
1307 if (si->sn_prof_on)
1309 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1310 if (si->sn_pr_count == 1)
1311 fprintf(fd, "Sourced 1 time\n");
1312 else
1313 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1314 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1315 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1316 fprintf(fd, "\n");
1317 fprintf(fd, "count total (s) self (s)\n");
1319 sfd = mch_fopen((char *)si->sn_name, "r");
1320 if (sfd == NULL)
1321 fprintf(fd, "Cannot open file!\n");
1322 else
1324 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1326 if (vim_fgets(IObuff, IOSIZE, sfd))
1327 break;
1328 pp = &PRL_ITEM(si, i);
1329 if (pp->snp_count > 0)
1331 fprintf(fd, "%5d ", pp->snp_count);
1332 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1333 fprintf(fd, " ");
1334 else
1335 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1336 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1338 else
1339 fprintf(fd, " ");
1340 fprintf(fd, "%s", IObuff);
1342 fclose(sfd);
1344 fprintf(fd, "\n");
1350 * Return TRUE when a function defined in the current script should be
1351 * profiled.
1354 prof_def_func()
1356 if (current_SID > 0)
1357 return SCRIPT_ITEM(current_SID).sn_pr_force;
1358 return FALSE;
1361 # endif
1362 #endif
1365 * If 'autowrite' option set, try to write the file.
1366 * Careful: autocommands may make "buf" invalid!
1368 * return FAIL for failure, OK otherwise
1371 autowrite(buf, forceit)
1372 buf_T *buf;
1373 int forceit;
1375 int r;
1377 if (!(p_aw || p_awa) || !p_write
1378 #ifdef FEAT_QUICKFIX
1379 /* never autowrite a "nofile" or "nowrite" buffer */
1380 || bt_dontwrite(buf)
1381 #endif
1382 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
1383 return FAIL;
1384 r = buf_write_all(buf, forceit);
1386 /* Writing may succeed but the buffer still changed, e.g., when there is a
1387 * conversion error. We do want to return FAIL then. */
1388 if (buf_valid(buf) && bufIsChanged(buf))
1389 r = FAIL;
1390 return r;
1394 * flush all buffers, except the ones that are readonly
1396 void
1397 autowrite_all()
1399 buf_T *buf;
1401 if (!(p_aw || p_awa) || !p_write)
1402 return;
1403 for (buf = firstbuf; buf; buf = buf->b_next)
1404 if (bufIsChanged(buf) && !buf->b_p_ro)
1406 (void)buf_write_all(buf, FALSE);
1407 #ifdef FEAT_AUTOCMD
1408 /* an autocommand may have deleted the buffer */
1409 if (!buf_valid(buf))
1410 buf = firstbuf;
1411 #endif
1416 * return TRUE if buffer was changed and cannot be abandoned.
1419 check_changed(buf, checkaw, mult_win, forceit, allbuf)
1420 buf_T *buf;
1421 int checkaw; /* do autowrite if buffer was changed */
1422 int mult_win; /* check also when several wins for the buf */
1423 int forceit;
1424 int allbuf UNUSED; /* may write all buffers */
1426 if ( !forceit
1427 && bufIsChanged(buf)
1428 && (mult_win || buf->b_nwindows <= 1)
1429 && (!checkaw || autowrite(buf, forceit) == FAIL))
1431 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1432 if ((p_confirm || cmdmod.confirm) && p_write)
1434 buf_T *buf2;
1435 int count = 0;
1437 if (allbuf)
1438 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1439 if (bufIsChanged(buf2)
1440 && (buf2->b_ffname != NULL
1441 # ifdef FEAT_BROWSE
1442 || cmdmod.browse
1443 # endif
1445 ++count;
1446 # ifdef FEAT_AUTOCMD
1447 if (!buf_valid(buf))
1448 /* Autocommand deleted buffer, oops! It's not changed now. */
1449 return FALSE;
1450 # endif
1451 dialog_changed(buf, count > 1);
1452 # ifdef FEAT_AUTOCMD
1453 if (!buf_valid(buf))
1454 /* Autocommand deleted buffer, oops! It's not changed now. */
1455 return FALSE;
1456 # endif
1457 return bufIsChanged(buf);
1459 #endif
1460 EMSG(_(e_nowrtmsg));
1461 return TRUE;
1463 return FALSE;
1466 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1468 #if defined(FEAT_BROWSE) || defined(PROTO)
1470 * When wanting to write a file without a file name, ask the user for a name.
1472 void
1473 browse_save_fname(buf)
1474 buf_T *buf;
1476 if (buf->b_fname == NULL)
1478 char_u *fname;
1480 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1481 NULL, NULL, NULL, NULL, buf);
1482 if (fname != NULL)
1484 if (setfname(buf, fname, NULL, TRUE) == OK)
1485 buf->b_flags |= BF_NOTEDITED;
1486 vim_free(fname);
1490 #endif
1493 * Ask the user what to do when abondoning a changed buffer.
1494 * Must check 'write' option first!
1496 void
1497 dialog_changed(buf, checkall)
1498 buf_T *buf;
1499 int checkall; /* may abandon all changed buffers */
1501 char_u buff[IOSIZE];
1502 int ret;
1503 buf_T *buf2;
1505 dialog_msg(buff, _("Save changes to \"%s\"?"),
1506 (buf->b_fname != NULL) ?
1507 buf->b_fname : (char_u *)_("Untitled"));
1508 if (checkall)
1509 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1510 else
1511 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
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 * Explicitly prepend "g:" to make it work in a function. */
2574 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
2575 if (old_cur_comp != NULL)
2576 old_cur_comp = vim_strsave(old_cur_comp);
2577 do_cmdline_cmd((char_u *)
2578 "command -nargs=* CompilerSet setlocal <args>");
2580 do_unlet((char_u *)"g:current_compiler", TRUE);
2581 do_unlet((char_u *)"b:current_compiler", TRUE);
2583 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
2584 if (source_runtime(buf, TRUE) == FAIL)
2585 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2586 vim_free(buf);
2588 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2590 /* Set "b:current_compiler" from "current_compiler". */
2591 p = get_var_value((char_u *)"g:current_compiler");
2592 if (p != NULL)
2593 set_internal_string_var((char_u *)"b:current_compiler", p);
2595 /* Restore "current_compiler" for ":compiler {name}". */
2596 if (!eap->forceit)
2598 if (old_cur_comp != NULL)
2600 set_internal_string_var((char_u *)"g:current_compiler",
2601 old_cur_comp);
2602 vim_free(old_cur_comp);
2604 else
2605 do_unlet((char_u *)"g:current_compiler", TRUE);
2610 #endif
2613 * ":runtime {name}"
2615 void
2616 ex_runtime(eap)
2617 exarg_T *eap;
2619 source_runtime(eap->arg, eap->forceit);
2622 static void source_callback __ARGS((char_u *fname, void *cookie));
2624 static void
2625 source_callback(fname, cookie)
2626 char_u *fname;
2627 void *cookie UNUSED;
2629 (void)do_source(fname, FALSE, DOSO_NONE);
2633 * Source the file "name" from all directories in 'runtimepath'.
2634 * "name" can contain wildcards.
2635 * When "all" is TRUE, source all files, otherwise only the first one.
2636 * return FAIL when no file could be sourced, OK otherwise.
2639 source_runtime(name, all)
2640 char_u *name;
2641 int all;
2643 return do_in_runtimepath(name, all, source_callback, NULL);
2647 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2648 * it: callback(fname, "cookie")
2649 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2650 * used.
2651 * Returns OK when at least one match found, FAIL otherwise.
2654 do_in_runtimepath(name, all, callback, cookie)
2655 char_u *name;
2656 int all;
2657 void (*callback)__ARGS((char_u *fname, void *ck));
2658 void *cookie;
2660 char_u *rtp;
2661 char_u *np;
2662 char_u *buf;
2663 char_u *rtp_copy;
2664 char_u *tail;
2665 int num_files;
2666 char_u **files;
2667 int i;
2668 int did_one = FALSE;
2669 #ifdef AMIGA
2670 struct Process *proc = (struct Process *)FindTask(0L);
2671 APTR save_winptr = proc->pr_WindowPtr;
2673 /* Avoid a requester here for a volume that doesn't exist. */
2674 proc->pr_WindowPtr = (APTR)-1L;
2675 #endif
2677 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2678 * value. */
2679 rtp_copy = vim_strsave(p_rtp);
2680 buf = alloc(MAXPATHL);
2681 if (buf != NULL && rtp_copy != NULL)
2683 if (p_verbose > 1)
2685 verbose_enter();
2686 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
2687 (char *)name, (char *)p_rtp);
2688 verbose_leave();
2691 /* Loop over all entries in 'runtimepath'. */
2692 rtp = rtp_copy;
2693 while (*rtp != NUL && (all || !did_one))
2695 /* Copy the path from 'runtimepath' to buf[]. */
2696 copy_option_part(&rtp, buf, MAXPATHL, ",");
2697 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2699 add_pathsep(buf);
2700 tail = buf + STRLEN(buf);
2702 /* Loop over all patterns in "name" */
2703 np = name;
2704 while (*np != NUL && (all || !did_one))
2706 /* Append the pattern from "name" to buf[]. */
2707 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2708 "\t ");
2710 if (p_verbose > 2)
2712 verbose_enter();
2713 smsg((char_u *)_("Searching for \"%s\""), buf);
2714 verbose_leave();
2717 /* Expand wildcards, invoke the callback for each match. */
2718 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2719 EW_FILE) == OK)
2721 for (i = 0; i < num_files; ++i)
2723 (*callback)(files[i], cookie);
2724 did_one = TRUE;
2725 if (!all)
2726 break;
2728 FreeWild(num_files, files);
2734 vim_free(buf);
2735 vim_free(rtp_copy);
2736 if (p_verbose > 0 && !did_one)
2738 verbose_enter();
2739 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
2740 verbose_leave();
2743 #ifdef AMIGA
2744 proc->pr_WindowPtr = save_winptr;
2745 #endif
2747 return did_one ? OK : FAIL;
2750 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2752 * ":options"
2754 void
2755 ex_options(eap)
2756 exarg_T *eap UNUSED;
2758 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2760 #endif
2763 * ":source {fname}"
2765 void
2766 ex_source(eap)
2767 exarg_T *eap;
2769 #ifdef FEAT_BROWSE
2770 if (cmdmod.browse)
2772 char_u *fname = NULL;
2774 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
2775 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2776 if (fname != NULL)
2778 cmd_source(fname, eap);
2779 vim_free(fname);
2782 else
2783 #endif
2784 cmd_source(eap->arg, eap);
2787 static void
2788 cmd_source(fname, eap)
2789 char_u *fname;
2790 exarg_T *eap;
2792 if (*fname == NUL)
2793 EMSG(_(e_argreq));
2795 else if (eap != NULL && eap->forceit)
2796 /* ":source!": read Normal mdoe commands
2797 * Need to execute the commands directly. This is required at least
2798 * for:
2799 * - ":g" command busy
2800 * - after ":argdo", ":windo" or ":bufdo"
2801 * - another command follows
2802 * - inside a loop
2804 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2805 #ifdef FEAT_EVAL
2806 || eap->cstack->cs_idx >= 0
2807 #endif
2810 /* ":source" read ex commands */
2811 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
2812 EMSG2(_(e_notopen), fname);
2816 * ":source" and associated commands.
2819 * Structure used to store info for each sourced file.
2820 * It is shared between do_source() and getsourceline().
2821 * This is required, because it needs to be handed to do_cmdline() and
2822 * sourcing can be done recursively.
2824 struct source_cookie
2826 FILE *fp; /* opened file for sourcing */
2827 char_u *nextline; /* if not NULL: line that was read ahead */
2828 int finished; /* ":finish" used */
2829 #if defined (USE_CRNL) || defined (USE_CR)
2830 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2831 int error; /* TRUE if LF found after CR-LF */
2832 #endif
2833 #ifdef FEAT_EVAL
2834 linenr_T breakpoint; /* next line with breakpoint or zero */
2835 char_u *fname; /* name of sourced file */
2836 int dbg_tick; /* debug_tick when breakpoint was set */
2837 int level; /* top nesting level of sourced file */
2838 #endif
2839 #ifdef FEAT_MBYTE
2840 vimconv_T conv; /* type of conversion */
2841 #endif
2844 #ifdef FEAT_EVAL
2846 * Return the address holding the next breakpoint line for a source cookie.
2848 linenr_T *
2849 source_breakpoint(cookie)
2850 void *cookie;
2852 return &((struct source_cookie *)cookie)->breakpoint;
2856 * Return the address holding the debug tick for a source cookie.
2858 int *
2859 source_dbg_tick(cookie)
2860 void *cookie;
2862 return &((struct source_cookie *)cookie)->dbg_tick;
2866 * Return the nesting level for a source cookie.
2869 source_level(cookie)
2870 void *cookie;
2872 return ((struct source_cookie *)cookie)->level;
2874 #endif
2876 static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2878 #if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2879 # define USE_FOPEN_NOINH
2880 static FILE *fopen_noinh_readbin __ARGS((char *filename));
2883 * Special function to open a file without handle inheritance.
2884 * When possible the handle is closed on exec().
2886 static FILE *
2887 fopen_noinh_readbin(filename)
2888 char *filename;
2890 # ifdef WIN32
2891 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2892 # else
2893 int fd_tmp = mch_open(filename, O_RDONLY, 0);
2894 # endif
2896 if (fd_tmp == -1)
2897 return NULL;
2899 # ifdef HAVE_FD_CLOEXEC
2901 int fdflags = fcntl(fd_tmp, F_GETFD);
2902 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
2903 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
2905 # endif
2907 return fdopen(fd_tmp, READBIN);
2909 #endif
2913 * do_source: Read the file "fname" and execute its lines as EX commands.
2915 * This function may be called recursively!
2917 * return FAIL if file could not be opened, OK otherwise
2920 do_source(fname, check_other, is_vimrc)
2921 char_u *fname;
2922 int check_other; /* check for .vimrc and _vimrc */
2923 int is_vimrc; /* DOSO_ value */
2925 struct source_cookie cookie;
2926 char_u *save_sourcing_name;
2927 linenr_T save_sourcing_lnum;
2928 char_u *p;
2929 char_u *fname_exp;
2930 char_u *firstline = NULL;
2931 int retval = FAIL;
2932 #ifdef FEAT_EVAL
2933 scid_T save_current_SID;
2934 static scid_T last_current_SID = 0;
2935 void *save_funccalp;
2936 int save_debug_break_level = debug_break_level;
2937 scriptitem_T *si = NULL;
2938 # ifdef UNIX
2939 struct stat st;
2940 int stat_ok;
2941 # endif
2942 #endif
2943 #ifdef STARTUPTIME
2944 struct timeval tv_rel;
2945 struct timeval tv_start;
2946 #endif
2947 #ifdef FEAT_PROFILE
2948 proftime_T wait_start;
2949 #endif
2951 #ifdef RISCOS
2952 p = mch_munge_fname(fname);
2953 #else
2954 p = expand_env_save(fname);
2955 #endif
2956 if (p == NULL)
2957 return retval;
2958 fname_exp = fix_fname(p);
2959 vim_free(p);
2960 if (fname_exp == NULL)
2961 return retval;
2962 if (mch_isdir(fname_exp))
2964 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
2965 goto theend;
2968 #ifdef FEAT_AUTOCMD
2969 /* Apply SourceCmd autocommands, they should get the file and source it. */
2970 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2971 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2972 FALSE, curbuf))
2974 # ifdef FEAT_EVAL
2975 retval = aborting() ? FAIL : OK;
2976 # else
2977 retval = OK;
2978 # endif
2979 goto theend;
2982 /* Apply SourcePre autocommands, they may get the file. */
2983 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2984 #endif
2986 #ifdef USE_FOPEN_NOINH
2987 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2988 #else
2989 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2990 #endif
2991 if (cookie.fp == NULL && check_other)
2994 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2995 * and ".exrc" by "_exrc" or vice versa.
2997 p = gettail(fname_exp);
2998 if ((*p == '.' || *p == '_')
2999 && (STRICMP(p + 1, "vimrc") == 0
3000 || STRICMP(p + 1, "gvimrc") == 0
3001 || STRICMP(p + 1, "exrc") == 0))
3003 if (*p == '_')
3004 *p = '.';
3005 else
3006 *p = '_';
3007 #ifdef USE_FOPEN_NOINH
3008 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3009 #else
3010 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3011 #endif
3015 if (cookie.fp == NULL)
3017 if (p_verbose > 0)
3019 verbose_enter();
3020 if (sourcing_name == NULL)
3021 smsg((char_u *)_("could not source \"%s\""), fname);
3022 else
3023 smsg((char_u *)_("line %ld: could not source \"%s\""),
3024 sourcing_lnum, fname);
3025 verbose_leave();
3027 goto theend;
3031 * The file exists.
3032 * - In verbose mode, give a message.
3033 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3035 if (p_verbose > 1)
3037 verbose_enter();
3038 if (sourcing_name == NULL)
3039 smsg((char_u *)_("sourcing \"%s\""), fname);
3040 else
3041 smsg((char_u *)_("line %ld: sourcing \"%s\""),
3042 sourcing_lnum, fname);
3043 verbose_leave();
3045 if (is_vimrc == DOSO_VIMRC)
3046 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3047 else if (is_vimrc == DOSO_GVIMRC)
3048 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
3050 #ifdef USE_CRNL
3051 /* If no automatic file format: Set default to CR-NL. */
3052 if (*p_ffs == NUL)
3053 cookie.fileformat = EOL_DOS;
3054 else
3055 cookie.fileformat = EOL_UNKNOWN;
3056 cookie.error = FALSE;
3057 #endif
3059 #ifdef USE_CR
3060 /* If no automatic file format: Set default to CR. */
3061 if (*p_ffs == NUL)
3062 cookie.fileformat = EOL_MAC;
3063 else
3064 cookie.fileformat = EOL_UNKNOWN;
3065 cookie.error = FALSE;
3066 #endif
3068 cookie.nextline = NULL;
3069 cookie.finished = FALSE;
3071 #ifdef FEAT_EVAL
3073 * Check if this script has a breakpoint.
3075 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3076 cookie.fname = fname_exp;
3077 cookie.dbg_tick = debug_tick;
3079 cookie.level = ex_nesting_level;
3080 #endif
3083 * Keep the sourcing name/lnum, for recursive calls.
3085 save_sourcing_name = sourcing_name;
3086 sourcing_name = fname_exp;
3087 save_sourcing_lnum = sourcing_lnum;
3088 sourcing_lnum = 0;
3090 #ifdef FEAT_MBYTE
3091 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3093 /* Read the first line so we can check for a UTF-8 BOM. */
3094 firstline = getsourceline(0, (void *)&cookie, 0);
3095 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3096 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3098 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3099 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3100 p = string_convert(&cookie.conv, firstline + 3, NULL);
3101 if (p == NULL)
3102 p = vim_strsave(firstline + 3);
3103 if (p != NULL)
3105 vim_free(firstline);
3106 firstline = p;
3109 #endif
3111 #ifdef STARTUPTIME
3112 if (time_fd != NULL)
3113 time_push(&tv_rel, &tv_start);
3114 #endif
3116 #ifdef FEAT_EVAL
3117 # ifdef FEAT_PROFILE
3118 if (do_profiling == PROF_YES)
3119 prof_child_enter(&wait_start); /* entering a child now */
3120 # endif
3122 /* Don't use local function variables, if called from a function.
3123 * Also starts profiling timer for nested script. */
3124 save_funccalp = save_funccal();
3127 * Check if this script was sourced before to finds its SID.
3128 * If it's new, generate a new SID.
3130 save_current_SID = current_SID;
3131 # ifdef UNIX
3132 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3133 # endif
3134 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3136 si = &SCRIPT_ITEM(current_SID);
3137 if (si->sn_name != NULL
3138 && (
3139 # ifdef UNIX
3140 /* Compare dev/ino when possible, it catches symbolic
3141 * links. Also compare file names, the inode may change
3142 * when the file was edited. */
3143 ((stat_ok && si->sn_dev_valid)
3144 && (si->sn_dev == st.st_dev
3145 && si->sn_ino == st.st_ino)) ||
3146 # endif
3147 fnamecmp(si->sn_name, fname_exp) == 0))
3148 break;
3150 if (current_SID == 0)
3152 current_SID = ++last_current_SID;
3153 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3154 == FAIL)
3155 goto almosttheend;
3156 while (script_items.ga_len < current_SID)
3158 ++script_items.ga_len;
3159 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3160 # ifdef FEAT_PROFILE
3161 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
3162 # endif
3164 si = &SCRIPT_ITEM(current_SID);
3165 si->sn_name = fname_exp;
3166 fname_exp = NULL;
3167 # ifdef UNIX
3168 if (stat_ok)
3170 si->sn_dev_valid = TRUE;
3171 si->sn_dev = st.st_dev;
3172 si->sn_ino = st.st_ino;
3174 else
3175 si->sn_dev_valid = FALSE;
3176 # endif
3178 /* Allocate the local script variables to use for this script. */
3179 new_script_vars(current_SID);
3182 # ifdef FEAT_PROFILE
3183 if (do_profiling == PROF_YES)
3185 int forceit;
3187 /* Check if we do profiling for this script. */
3188 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3190 script_do_profile(si);
3191 si->sn_pr_force = forceit;
3193 if (si->sn_prof_on)
3195 ++si->sn_pr_count;
3196 profile_start(&si->sn_pr_start);
3197 profile_zero(&si->sn_pr_children);
3200 # endif
3201 #endif
3204 * Call do_cmdline, which will call getsourceline() to get the lines.
3206 do_cmdline(firstline, getsourceline, (void *)&cookie,
3207 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
3208 retval = OK;
3210 #ifdef FEAT_PROFILE
3211 if (do_profiling == PROF_YES)
3213 /* Get "si" again, "script_items" may have been reallocated. */
3214 si = &SCRIPT_ITEM(current_SID);
3215 if (si->sn_prof_on)
3217 profile_end(&si->sn_pr_start);
3218 profile_sub_wait(&wait_start, &si->sn_pr_start);
3219 profile_add(&si->sn_pr_total, &si->sn_pr_start);
3220 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3221 &si->sn_pr_children);
3224 #endif
3226 if (got_int)
3227 EMSG(_(e_interr));
3228 sourcing_name = save_sourcing_name;
3229 sourcing_lnum = save_sourcing_lnum;
3230 if (p_verbose > 1)
3232 verbose_enter();
3233 smsg((char_u *)_("finished sourcing %s"), fname);
3234 if (sourcing_name != NULL)
3235 smsg((char_u *)_("continuing in %s"), sourcing_name);
3236 verbose_leave();
3238 #ifdef STARTUPTIME
3239 if (time_fd != NULL)
3241 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3242 time_msg((char *)IObuff, &tv_start);
3243 time_pop(&tv_rel);
3245 #endif
3247 #ifdef FEAT_EVAL
3249 * After a "finish" in debug mode, need to break at first command of next
3250 * sourced file.
3252 if (save_debug_break_level > ex_nesting_level
3253 && debug_break_level == ex_nesting_level)
3254 ++debug_break_level;
3255 #endif
3257 #ifdef FEAT_EVAL
3258 almosttheend:
3259 current_SID = save_current_SID;
3260 restore_funccal(save_funccalp);
3261 # ifdef FEAT_PROFILE
3262 if (do_profiling == PROF_YES)
3263 prof_child_exit(&wait_start); /* leaving a child now */
3264 # endif
3265 #endif
3266 fclose(cookie.fp);
3267 vim_free(cookie.nextline);
3268 vim_free(firstline);
3269 #ifdef FEAT_MBYTE
3270 convert_setup(&cookie.conv, NULL, NULL);
3271 #endif
3273 theend:
3274 vim_free(fname_exp);
3275 return retval;
3278 #if defined(FEAT_EVAL) || defined(PROTO)
3281 * ":scriptnames"
3283 void
3284 ex_scriptnames(eap)
3285 exarg_T *eap UNUSED;
3287 int i;
3289 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3290 if (SCRIPT_ITEM(i).sn_name != NULL)
3291 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
3294 # if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3296 * Fix slashes in the list of script names for 'shellslash'.
3298 void
3299 scriptnames_slash_adjust()
3301 int i;
3303 for (i = 1; i <= script_items.ga_len; ++i)
3304 if (SCRIPT_ITEM(i).sn_name != NULL)
3305 slash_adjust(SCRIPT_ITEM(i).sn_name);
3307 # endif
3310 * Get a pointer to a script name. Used for ":verbose set".
3312 char_u *
3313 get_scriptname(id)
3314 scid_T id;
3316 if (id == SID_MODELINE)
3317 return (char_u *)_("modeline");
3318 if (id == SID_CMDARG)
3319 return (char_u *)_("--cmd argument");
3320 if (id == SID_CARG)
3321 return (char_u *)_("-c argument");
3322 if (id == SID_ENV)
3323 return (char_u *)_("environment variable");
3324 if (id == SID_ERROR)
3325 return (char_u *)_("error handler");
3326 return SCRIPT_ITEM(id).sn_name;
3329 # if defined(EXITFREE) || defined(PROTO)
3330 void
3331 free_scriptnames()
3333 int i;
3335 for (i = script_items.ga_len; i > 0; --i)
3336 vim_free(SCRIPT_ITEM(i).sn_name);
3337 ga_clear(&script_items);
3339 # endif
3341 #endif
3343 #if defined(USE_CR) || defined(PROTO)
3345 # if defined(__MSL__) && (__MSL__ >= 22)
3347 * Newer version of the Metrowerks library handle DOS and UNIX files
3348 * without help.
3349 * Test with earlier versions, MSL 2.2 is the library supplied with
3350 * Codewarrior Pro 2.
3352 char *
3353 fgets_cr(s, n, stream)
3354 char *s;
3355 int n;
3356 FILE *stream;
3358 return fgets(s, n, stream);
3360 # else
3362 * Version of fgets() which also works for lines ending in a <CR> only
3363 * (Macintosh format).
3364 * For older versions of the Metrowerks library.
3365 * At least CodeWarrior 9 needed this code.
3367 char *
3368 fgets_cr(s, n, stream)
3369 char *s;
3370 int n;
3371 FILE *stream;
3373 int c = 0;
3374 int char_read = 0;
3376 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3378 c = fgetc(stream);
3379 s[char_read++] = c;
3380 /* If the file is in DOS format, we need to skip a NL after a CR. I
3381 * thought it was the other way around, but this appears to work... */
3382 if (c == '\n')
3384 c = fgetc(stream);
3385 if (c != '\r')
3386 ungetc(c, stream);
3390 s[char_read] = 0;
3391 if (char_read == 0)
3392 return NULL;
3394 if (feof(stream) && char_read == 1)
3395 return NULL;
3397 return s;
3399 # endif
3400 #endif
3403 * Get one full line from a sourced file.
3404 * Called by do_cmdline() when it's called from do_source().
3406 * Return a pointer to the line in allocated memory.
3407 * Return NULL for end-of-file or some error.
3409 char_u *
3410 getsourceline(c, cookie, indent)
3411 int c UNUSED;
3412 void *cookie;
3413 int indent UNUSED;
3415 struct source_cookie *sp = (struct source_cookie *)cookie;
3416 char_u *line;
3417 char_u *p, *s;
3419 #ifdef FEAT_EVAL
3420 /* If breakpoints have been added/deleted need to check for it. */
3421 if (sp->dbg_tick < debug_tick)
3423 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3424 sp->dbg_tick = debug_tick;
3426 # ifdef FEAT_PROFILE
3427 if (do_profiling == PROF_YES)
3428 script_line_end();
3429 # endif
3430 #endif
3432 * Get current line. If there is a read-ahead line, use it, otherwise get
3433 * one now.
3435 if (sp->finished)
3436 line = NULL;
3437 else if (sp->nextline == NULL)
3438 line = get_one_sourceline(sp);
3439 else
3441 line = sp->nextline;
3442 sp->nextline = NULL;
3443 ++sourcing_lnum;
3445 #ifdef FEAT_PROFILE
3446 if (line != NULL && do_profiling == PROF_YES)
3447 script_line_start();
3448 #endif
3450 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3451 * contain the 'C' flag. */
3452 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3454 /* compensate for the one line read-ahead */
3455 --sourcing_lnum;
3456 for (;;)
3458 sp->nextline = get_one_sourceline(sp);
3459 if (sp->nextline == NULL)
3460 break;
3461 p = skipwhite(sp->nextline);
3462 if (*p != '\\')
3463 break;
3464 s = alloc((unsigned)(STRLEN(line) + STRLEN(p)));
3465 if (s == NULL) /* out of memory */
3466 break;
3467 STRCPY(s, line);
3468 STRCAT(s, p + 1);
3469 vim_free(line);
3470 line = s;
3471 vim_free(sp->nextline);
3475 #ifdef FEAT_MBYTE
3476 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3478 /* Convert the encoding of the script line. */
3479 s = string_convert(&sp->conv, line, NULL);
3480 if (s != NULL)
3482 vim_free(line);
3483 line = s;
3486 #endif
3488 #ifdef FEAT_EVAL
3489 /* Did we encounter a breakpoint? */
3490 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3492 dbg_breakpoint(sp->fname, sourcing_lnum);
3493 /* Find next breakpoint. */
3494 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3495 sp->dbg_tick = debug_tick;
3497 #endif
3499 return line;
3502 static char_u *
3503 get_one_sourceline(sp)
3504 struct source_cookie *sp;
3506 garray_T ga;
3507 int len;
3508 int c;
3509 char_u *buf;
3510 #ifdef USE_CRNL
3511 int has_cr; /* CR-LF found */
3512 #endif
3513 #ifdef USE_CR
3514 char_u *scan;
3515 #endif
3516 int have_read = FALSE;
3518 /* use a growarray to store the sourced line */
3519 ga_init2(&ga, 1, 250);
3522 * Loop until there is a finished line (or end-of-file).
3524 sourcing_lnum++;
3525 for (;;)
3527 /* make room to read at least 120 (more) characters */
3528 if (ga_grow(&ga, 120) == FAIL)
3529 break;
3530 buf = (char_u *)ga.ga_data;
3532 #ifdef USE_CR
3533 if (sp->fileformat == EOL_MAC)
3535 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3536 sp->fp) == NULL)
3537 break;
3539 else
3540 #endif
3541 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3542 sp->fp) == NULL)
3543 break;
3544 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
3545 #ifdef USE_CRNL
3546 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3547 * CTRL-Z by its own, or after a NL. */
3548 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3549 && sp->fileformat == EOL_DOS
3550 && buf[len - 1] == Ctrl_Z)
3552 buf[len - 1] = NUL;
3553 break;
3555 #endif
3557 #ifdef USE_CR
3558 /* If the read doesn't stop on a new line, and there's
3559 * some CR then we assume a Mac format */
3560 if (sp->fileformat == EOL_UNKNOWN)
3562 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3563 sp->fileformat = EOL_MAC;
3564 else
3565 sp->fileformat = EOL_UNIX;
3568 if (sp->fileformat == EOL_MAC)
3570 scan = vim_strchr(buf, '\r');
3572 if (scan != NULL)
3574 *scan = '\n';
3575 if (*(scan + 1) != 0)
3577 *(scan + 1) = 0;
3578 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3581 len = STRLEN(buf);
3583 #endif
3585 have_read = TRUE;
3586 ga.ga_len = len;
3588 /* If the line was longer than the buffer, read more. */
3589 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
3590 continue;
3592 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3594 #ifdef USE_CRNL
3595 has_cr = (len >= 2 && buf[len - 2] == '\r');
3596 if (sp->fileformat == EOL_UNKNOWN)
3598 if (has_cr)
3599 sp->fileformat = EOL_DOS;
3600 else
3601 sp->fileformat = EOL_UNIX;
3604 if (sp->fileformat == EOL_DOS)
3606 if (has_cr) /* replace trailing CR */
3608 buf[len - 2] = '\n';
3609 --len;
3610 --ga.ga_len;
3612 else /* lines like ":map xx yy^M" will have failed */
3614 if (!sp->error)
3616 msg_source(hl_attr(HLF_W));
3617 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
3619 sp->error = TRUE;
3620 sp->fileformat = EOL_UNIX;
3623 #endif
3624 /* The '\n' is escaped if there is an odd number of ^V's just
3625 * before it, first set "c" just before the 'V's and then check
3626 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3627 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3629 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3631 sourcing_lnum++;
3632 continue;
3635 buf[len - 1] = NUL; /* remove the NL */
3639 * Check for ^C here now and then, so recursive :so can be broken.
3641 line_breakcheck();
3642 break;
3645 if (have_read)
3646 return (char_u *)ga.ga_data;
3648 vim_free(ga.ga_data);
3649 return NULL;
3652 #if defined(FEAT_PROFILE) || defined(PROTO)
3654 * Called when starting to read a script line.
3655 * "sourcing_lnum" must be correct!
3656 * When skipping lines it may not actually be executed, but we won't find out
3657 * until later and we need to store the time now.
3659 void
3660 script_line_start()
3662 scriptitem_T *si;
3663 sn_prl_T *pp;
3665 if (current_SID <= 0 || current_SID > script_items.ga_len)
3666 return;
3667 si = &SCRIPT_ITEM(current_SID);
3668 if (si->sn_prof_on && sourcing_lnum >= 1)
3670 /* Grow the array before starting the timer, so that the time spent
3671 * here isn't counted. */
3672 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3673 si->sn_prl_idx = sourcing_lnum - 1;
3674 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3675 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3677 /* Zero counters for a line that was not used before. */
3678 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3679 pp->snp_count = 0;
3680 profile_zero(&pp->sn_prl_total);
3681 profile_zero(&pp->sn_prl_self);
3682 ++si->sn_prl_ga.ga_len;
3684 si->sn_prl_execed = FALSE;
3685 profile_start(&si->sn_prl_start);
3686 profile_zero(&si->sn_prl_children);
3687 profile_get_wait(&si->sn_prl_wait);
3692 * Called when actually executing a function line.
3694 void
3695 script_line_exec()
3697 scriptitem_T *si;
3699 if (current_SID <= 0 || current_SID > script_items.ga_len)
3700 return;
3701 si = &SCRIPT_ITEM(current_SID);
3702 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3703 si->sn_prl_execed = TRUE;
3707 * Called when done with a function line.
3709 void
3710 script_line_end()
3712 scriptitem_T *si;
3713 sn_prl_T *pp;
3715 if (current_SID <= 0 || current_SID > script_items.ga_len)
3716 return;
3717 si = &SCRIPT_ITEM(current_SID);
3718 if (si->sn_prof_on && si->sn_prl_idx >= 0
3719 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3721 if (si->sn_prl_execed)
3723 pp = &PRL_ITEM(si, si->sn_prl_idx);
3724 ++pp->snp_count;
3725 profile_end(&si->sn_prl_start);
3726 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
3727 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
3728 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3729 &si->sn_prl_children);
3731 si->sn_prl_idx = -1;
3734 #endif
3737 * ":scriptencoding": Set encoding conversion for a sourced script.
3738 * Without the multi-byte feature it's simply ignored.
3740 void
3741 ex_scriptencoding(eap)
3742 exarg_T *eap UNUSED;
3744 #ifdef FEAT_MBYTE
3745 struct source_cookie *sp;
3746 char_u *name;
3748 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3750 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3751 return;
3754 if (*eap->arg != NUL)
3756 name = enc_canonize(eap->arg);
3757 if (name == NULL) /* out of memory */
3758 return;
3760 else
3761 name = eap->arg;
3763 /* Setup for conversion from the specified encoding to 'encoding'. */
3764 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3765 convert_setup(&sp->conv, name, p_enc);
3767 if (name != eap->arg)
3768 vim_free(name);
3769 #endif
3772 #if defined(FEAT_EVAL) || defined(PROTO)
3774 * ":finish": Mark a sourced file as finished.
3776 void
3777 ex_finish(eap)
3778 exarg_T *eap;
3780 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3781 do_finish(eap, FALSE);
3782 else
3783 EMSG(_("E168: :finish used outside of a sourced file"));
3787 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3788 * Also called for a pending finish at the ":endtry" or after returning from
3789 * an extra do_cmdline(). "reanimate" is used in the latter case.
3791 void
3792 do_finish(eap, reanimate)
3793 exarg_T *eap;
3794 int reanimate;
3796 int idx;
3798 if (reanimate)
3799 ((struct source_cookie *)getline_cookie(eap->getline,
3800 eap->cookie))->finished = FALSE;
3803 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3804 * not in its finally clause (which then is to be executed next) is found.
3805 * In this case, make the ":finish" pending for execution at the ":endtry".
3806 * Otherwise, finish normally.
3808 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3809 if (idx >= 0)
3811 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3812 report_make_pending(CSTP_FINISH, NULL);
3814 else
3815 ((struct source_cookie *)getline_cookie(eap->getline,
3816 eap->cookie))->finished = TRUE;
3821 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3822 * message for missing ":endif".
3823 * Return FALSE when not sourcing a file.
3826 source_finished(fgetline, cookie)
3827 char_u *(*fgetline) __ARGS((int, void *, int));
3828 void *cookie;
3830 return (getline_equal(fgetline, cookie, getsourceline)
3831 && ((struct source_cookie *)getline_cookie(
3832 fgetline, cookie))->finished);
3834 #endif
3836 #if defined(FEAT_LISTCMDS) || defined(PROTO)
3838 * ":checktime [buffer]"
3840 void
3841 ex_checktime(eap)
3842 exarg_T *eap;
3844 buf_T *buf;
3845 int save_no_check_timestamps = no_check_timestamps;
3847 no_check_timestamps = 0;
3848 if (eap->addr_count == 0) /* default is all buffers */
3849 check_timestamps(FALSE);
3850 else
3852 buf = buflist_findnr((int)eap->line2);
3853 if (buf != NULL) /* cannot happen? */
3854 (void)buf_check_timestamp(buf, FALSE);
3856 no_check_timestamps = save_no_check_timestamps;
3858 #endif
3860 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3861 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3862 static char *get_locale_val __ARGS((int what));
3864 static char *
3865 get_locale_val(what)
3866 int what;
3868 char *loc;
3870 /* Obtain the locale value from the libraries. For DJGPP this is
3871 * redefined and it doesn't use the arguments. */
3872 loc = setlocale(what, NULL);
3874 # ifdef WIN32
3875 if (loc != NULL)
3877 char_u *p;
3879 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3880 * one of the values (e.g., LC_CTYPE) differs. */
3881 p = vim_strchr(loc, '=');
3882 if (p != NULL)
3884 loc = ++p;
3885 while (*p != NUL) /* remove trailing newline */
3887 if (*p < ' ' || *p == ';')
3889 *p = NUL;
3890 break;
3892 ++p;
3896 # endif
3898 return loc;
3900 #endif
3903 #ifdef WIN32
3905 * On MS-Windows locale names are strings like "German_Germany.1252", but
3906 * gettext expects "de". Try to translate one into another here for a few
3907 * supported languages.
3909 static char_u *
3910 gettext_lang(char_u *name)
3912 int i;
3913 static char *(mtable[]) = {
3914 "afrikaans", "af",
3915 "czech", "cs",
3916 "dutch", "nl",
3917 "german", "de",
3918 "english_united kingdom", "en_GB",
3919 "spanish", "es",
3920 "french", "fr",
3921 "italian", "it",
3922 "japanese", "ja",
3923 "korean", "ko",
3924 "norwegian", "no",
3925 "polish", "pl",
3926 "russian", "ru",
3927 "slovak", "sk",
3928 "swedish", "sv",
3929 "ukrainian", "uk",
3930 "chinese_china", "zh_CN",
3931 "chinese_taiwan", "zh_TW",
3932 NULL};
3934 for (i = 0; mtable[i] != NULL; i += 2)
3935 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3936 return mtable[i + 1];
3937 return name;
3939 #endif
3941 #if defined(FEAT_MULTI_LANG) || defined(PROTO)
3943 * Obtain the current messages language. Used to set the default for
3944 * 'helplang'. May return NULL or an empty string.
3946 char_u *
3947 get_mess_lang()
3949 char_u *p;
3951 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3952 # if defined(LC_MESSAGES)
3953 p = (char_u *)get_locale_val(LC_MESSAGES);
3954 # else
3955 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
3956 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3957 * and LC_MONETARY may be set differently for a Japanese working in the
3958 * US. */
3959 p = (char_u *)get_locale_val(LC_COLLATE);
3960 # endif
3961 # else
3962 p = mch_getenv((char_u *)"LC_ALL");
3963 if (p == NULL || *p == NUL)
3965 p = mch_getenv((char_u *)"LC_MESSAGES");
3966 if (p == NULL || *p == NUL)
3967 p = mch_getenv((char_u *)"LANG");
3969 # endif
3970 # ifdef WIN32
3971 p = gettext_lang(p);
3972 # endif
3973 return p;
3975 #endif
3977 /* Complicated #if; matches with where get_mess_env() is used below. */
3978 #if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3979 && defined(LC_MESSAGES))) \
3980 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3981 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3982 && !defined(LC_MESSAGES))
3983 static char_u *get_mess_env __ARGS((void));
3986 * Get the language used for messages from the environment.
3988 static char_u *
3989 get_mess_env()
3991 char_u *p;
3993 p = mch_getenv((char_u *)"LC_ALL");
3994 if (p == NULL || *p == NUL)
3996 p = mch_getenv((char_u *)"LC_MESSAGES");
3997 if (p == NULL || *p == NUL)
3999 p = mch_getenv((char_u *)"LANG");
4000 if (p != NULL && VIM_ISDIGIT(*p))
4001 p = NULL; /* ignore something like "1043" */
4002 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4003 if (p == NULL || *p == NUL)
4004 p = (char_u *)get_locale_val(LC_CTYPE);
4005 # endif
4008 return p;
4010 #endif
4012 #if defined(FEAT_EVAL) || defined(PROTO)
4015 * Set the "v:lang" variable according to the current locale setting.
4016 * Also do "v:lc_time"and "v:ctype".
4018 void
4019 set_lang_var()
4021 char_u *loc;
4023 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4024 loc = (char_u *)get_locale_val(LC_CTYPE);
4025 # else
4026 /* setlocale() not supported: use the default value */
4027 loc = (char_u *)"C";
4028 # endif
4029 set_vim_var_string(VV_CTYPE, loc, -1);
4031 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4032 * back to LC_CTYPE if it's empty. */
4033 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
4034 loc = (char_u *)get_locale_val(LC_MESSAGES);
4035 # else
4036 loc = get_mess_env();
4037 # endif
4038 set_vim_var_string(VV_LANG, loc, -1);
4040 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4041 loc = (char_u *)get_locale_val(LC_TIME);
4042 # endif
4043 set_vim_var_string(VV_LC_TIME, loc, -1);
4045 #endif
4047 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4048 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4050 * ":language": Set the language (locale).
4052 void
4053 ex_language(eap)
4054 exarg_T *eap;
4056 char *loc;
4057 char_u *p;
4058 char_u *name;
4059 int what = LC_ALL;
4060 char *whatstr = "";
4061 #ifdef LC_MESSAGES
4062 # define VIM_LC_MESSAGES LC_MESSAGES
4063 #else
4064 # define VIM_LC_MESSAGES 6789
4065 #endif
4067 name = eap->arg;
4069 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4070 * Allow abbreviation, but require at least 3 characters to avoid
4071 * confusion with a two letter language name "me" or "ct". */
4072 p = skiptowhite(eap->arg);
4073 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4075 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4077 what = VIM_LC_MESSAGES;
4078 name = skipwhite(p);
4079 whatstr = "messages ";
4081 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4083 what = LC_CTYPE;
4084 name = skipwhite(p);
4085 whatstr = "ctype ";
4087 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4089 what = LC_TIME;
4090 name = skipwhite(p);
4091 whatstr = "time ";
4095 if (*name == NUL)
4097 #ifndef LC_MESSAGES
4098 if (what == VIM_LC_MESSAGES)
4099 p = get_mess_env();
4100 else
4101 #endif
4102 p = (char_u *)setlocale(what, NULL);
4103 if (p == NULL || *p == NUL)
4104 p = (char_u *)"Unknown";
4105 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4107 else
4109 #ifndef LC_MESSAGES
4110 if (what == VIM_LC_MESSAGES)
4111 loc = "";
4112 else
4113 #endif
4115 loc = setlocale(what, (char *)name);
4116 #if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4117 /* Make sure strtod() uses a decimal point, not a comma. */
4118 setlocale(LC_NUMERIC, "C");
4119 #endif
4121 if (loc == NULL)
4122 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4123 else
4125 #ifdef HAVE_NL_MSG_CAT_CNTR
4126 /* Need to do this for GNU gettext, otherwise cached translations
4127 * will be used again. */
4128 extern int _nl_msg_cat_cntr;
4130 ++_nl_msg_cat_cntr;
4131 #endif
4132 /* Reset $LC_ALL, otherwise it would overrule everything. */
4133 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4135 if (what != LC_TIME)
4137 /* Tell gettext() what to translate to. It apparently doesn't
4138 * use the currently effective locale. Also do this when
4139 * FEAT_GETTEXT isn't defined, so that shell commands use this
4140 * value. */
4141 if (what == LC_ALL)
4143 vim_setenv((char_u *)"LANG", name);
4144 # ifdef WIN32
4145 /* Apparently MS-Windows printf() may cause a crash when
4146 * we give it 8-bit text while it's expecting text in the
4147 * current locale. This call avoids that. */
4148 setlocale(LC_CTYPE, "C");
4149 # endif
4151 if (what != LC_CTYPE)
4153 char_u *mname;
4154 #ifdef WIN32
4155 mname = gettext_lang(name);
4156 #else
4157 mname = name;
4158 #endif
4159 vim_setenv((char_u *)"LC_MESSAGES", mname);
4160 #ifdef FEAT_MULTI_LANG
4161 set_helplang_default(mname);
4162 #endif
4165 /* Set $LC_CTYPE, because it overrules $LANG, and
4166 * gtk_set_locale() calls setlocale() again. gnome_init()
4167 * sets $LC_CTYPE to "en_US" (that's a bug!). */
4168 if (what != VIM_LC_MESSAGES)
4169 vim_setenv((char_u *)"LC_CTYPE", name);
4170 # ifdef FEAT_GUI_GTK
4171 /* Let GTK know what locale we're using. Not sure this is
4172 * really needed... */
4173 if (gui.in_use)
4174 (void)gtk_set_locale();
4175 # endif
4178 # ifdef FEAT_EVAL
4179 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4180 set_lang_var();
4181 # endif
4186 # if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4188 * Function given to ExpandGeneric() to obtain the possible arguments of the
4189 * ":language" command.
4191 char_u *
4192 get_lang_arg(xp, idx)
4193 expand_T *xp UNUSED;
4194 int idx;
4196 if (idx == 0)
4197 return (char_u *)"messages";
4198 if (idx == 1)
4199 return (char_u *)"ctype";
4200 if (idx == 2)
4201 return (char_u *)"time";
4202 return NULL;
4204 # endif
4206 #endif