Fixed memory leak in -[MMAppController openFiles:withArguments:]
[MacVim.git] / src / ex_cmds2.c
blob26eebf30e79b3de673a89d48b1d7ebb52da644db
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;
32 ino_t sn_ino;
33 # endif
34 # ifdef FEAT_PROFILE
35 int sn_prof_on; /* TRUE when script is/was profiled */
36 int sn_pr_force; /* forceit: profile functions in this script */
37 proftime_T sn_pr_child; /* time set when going into first child */
38 int sn_pr_nest; /* nesting for sn_pr_child */
39 /* profiling the script as a whole */
40 int sn_pr_count; /* nr of times sourced */
41 proftime_T sn_pr_total; /* time spent in script + children */
42 proftime_T sn_pr_self; /* time spent in script itself */
43 proftime_T sn_pr_start; /* time at script start */
44 proftime_T sn_pr_children; /* time in children after script start */
45 /* profiling the script per line */
46 garray_T sn_prl_ga; /* things stored for every line */
47 proftime_T sn_prl_start; /* start time for current line */
48 proftime_T sn_prl_children; /* time spent in children for this line */
49 proftime_T sn_prl_wait; /* wait start time for current line */
50 int sn_prl_idx; /* index of line being timed; -1 if none */
51 int sn_prl_execed; /* line being timed was executed */
52 # endif
53 } scriptitem_T;
55 static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
56 #define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
58 # ifdef FEAT_PROFILE
59 /* Struct used in sn_prl_ga for every line of a script. */
60 typedef struct sn_prl_S
62 int snp_count; /* nr of times line was executed */
63 proftime_T sn_prl_total; /* time spent in a line + children */
64 proftime_T sn_prl_self; /* time spent in a line itself */
65 } sn_prl_T;
67 # define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
68 # endif
69 #endif
71 #if defined(FEAT_EVAL) || defined(PROTO)
72 static int debug_greedy = FALSE; /* batch mode debugging: don't save
73 and restore typeahead. */
76 * do_debug(): Debug mode.
77 * Repeatedly get Ex commands, until told to continue normal execution.
79 void
80 do_debug(cmd)
81 char_u *cmd;
83 int save_msg_scroll = msg_scroll;
84 int save_State = State;
85 int save_did_emsg = did_emsg;
86 int save_cmd_silent = cmd_silent;
87 int save_msg_silent = msg_silent;
88 int save_emsg_silent = emsg_silent;
89 int save_redir_off = redir_off;
90 tasave_T typeaheadbuf;
91 int typeahead_saved = FALSE;
92 int save_ignore_script = 0;
93 # ifdef FEAT_EX_EXTRA
94 int save_ex_normal_busy;
95 # endif
96 int n;
97 char_u *cmdline = NULL;
98 char_u *p;
99 char *tail = NULL;
100 static int last_cmd = 0;
101 #define CMD_CONT 1
102 #define CMD_NEXT 2
103 #define CMD_STEP 3
104 #define CMD_FINISH 4
105 #define CMD_QUIT 5
106 #define CMD_INTERRUPT 6
108 #ifdef ALWAYS_USE_GUI
109 /* Can't do this when there is no terminal for input/output. */
110 if (!gui.in_use)
112 /* Break as soon as possible. */
113 debug_break_level = 9999;
114 return;
116 #endif
118 /* Make sure we are in raw mode and start termcap mode. Might have side
119 * effects... */
120 settmode(TMODE_RAW);
121 starttermcap();
123 ++RedrawingDisabled; /* don't redisplay the window */
124 ++no_wait_return; /* don't wait for return */
125 did_emsg = FALSE; /* don't use error from debugged stuff */
126 cmd_silent = FALSE; /* display commands */
127 msg_silent = FALSE; /* display messages */
128 emsg_silent = FALSE; /* display error messages */
129 redir_off = TRUE; /* don't redirect debug commands */
131 State = NORMAL;
132 #ifdef FEAT_SNIFF
133 want_sniff_request = 0; /* No K_SNIFF wanted */
134 #endif
136 if (!debug_did_msg)
137 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
138 if (sourcing_name != NULL)
139 msg(sourcing_name);
140 if (sourcing_lnum != 0)
141 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
142 else
143 smsg((char_u *)_("cmd: %s"), cmd);
146 * Repeat getting a command and executing it.
148 for (;;)
150 msg_scroll = TRUE;
151 need_wait_return = FALSE;
152 #ifdef FEAT_SNIFF
153 ProcessSniffRequests();
154 #endif
155 /* Save the current typeahead buffer and replace it with an empty one.
156 * This makes sure we get input from the user here and don't interfere
157 * with the commands being executed. Reset "ex_normal_busy" to avoid
158 * the side effects of using ":normal". Save the stuff buffer and make
159 * it empty. Set ignore_script to avoid reading from script input. */
160 # ifdef FEAT_EX_EXTRA
161 save_ex_normal_busy = ex_normal_busy;
162 ex_normal_busy = 0;
163 # endif
164 if (!debug_greedy)
166 save_typeahead(&typeaheadbuf);
167 typeahead_saved = TRUE;
168 save_ignore_script = ignore_script;
169 ignore_script = TRUE;
172 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
174 if (typeahead_saved)
176 restore_typeahead(&typeaheadbuf);
177 ignore_script = save_ignore_script;
179 # ifdef FEAT_EX_EXTRA
180 ex_normal_busy = save_ex_normal_busy;
181 # endif
183 cmdline_row = msg_row;
184 if (cmdline != NULL)
186 /* If this is a debug command, set "last_cmd".
187 * If not, reset "last_cmd".
188 * For a blank line use previous command. */
189 p = skipwhite(cmdline);
190 if (*p != NUL)
192 switch (*p)
194 case 'c': last_cmd = CMD_CONT;
195 tail = "ont";
196 break;
197 case 'n': last_cmd = CMD_NEXT;
198 tail = "ext";
199 break;
200 case 's': last_cmd = CMD_STEP;
201 tail = "tep";
202 break;
203 case 'f': last_cmd = CMD_FINISH;
204 tail = "inish";
205 break;
206 case 'q': last_cmd = CMD_QUIT;
207 tail = "uit";
208 break;
209 case 'i': last_cmd = CMD_INTERRUPT;
210 tail = "nterrupt";
211 break;
212 default: last_cmd = 0;
214 if (last_cmd != 0)
216 /* Check that the tail matches. */
217 ++p;
218 while (*p != NUL && *p == *tail)
220 ++p;
221 ++tail;
223 if (ASCII_ISALPHA(*p))
224 last_cmd = 0;
228 if (last_cmd != 0)
230 /* Execute debug command: decided where to break next and
231 * return. */
232 switch (last_cmd)
234 case CMD_CONT:
235 debug_break_level = -1;
236 break;
237 case CMD_NEXT:
238 debug_break_level = ex_nesting_level;
239 break;
240 case CMD_STEP:
241 debug_break_level = 9999;
242 break;
243 case CMD_FINISH:
244 debug_break_level = ex_nesting_level - 1;
245 break;
246 case CMD_QUIT:
247 got_int = TRUE;
248 debug_break_level = -1;
249 break;
250 case CMD_INTERRUPT:
251 got_int = TRUE;
252 debug_break_level = 9999;
253 /* Do not repeat ">interrupt" cmd, continue stepping. */
254 last_cmd = CMD_STEP;
255 break;
257 break;
260 /* don't debug this command */
261 n = debug_break_level;
262 debug_break_level = -1;
263 (void)do_cmdline(cmdline, getexline, NULL,
264 DOCMD_VERBOSE|DOCMD_EXCRESET);
265 debug_break_level = n;
267 vim_free(cmdline);
269 lines_left = Rows - 1;
271 vim_free(cmdline);
273 --RedrawingDisabled;
274 --no_wait_return;
275 redraw_all_later(NOT_VALID);
276 need_wait_return = FALSE;
277 msg_scroll = save_msg_scroll;
278 lines_left = Rows - 1;
279 State = save_State;
280 did_emsg = save_did_emsg;
281 cmd_silent = save_cmd_silent;
282 msg_silent = save_msg_silent;
283 emsg_silent = save_emsg_silent;
284 redir_off = save_redir_off;
286 /* Only print the message again when typing a command before coming back
287 * here. */
288 debug_did_msg = TRUE;
292 * ":debug".
294 void
295 ex_debug(eap)
296 exarg_T *eap;
298 int debug_break_level_save = debug_break_level;
300 debug_break_level = 9999;
301 do_cmdline_cmd(eap->arg);
302 debug_break_level = debug_break_level_save;
305 static char_u *debug_breakpoint_name = NULL;
306 static linenr_T debug_breakpoint_lnum;
309 * When debugging or a breakpoint is set on a skipped command, no debug prompt
310 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
311 * debug_skipped_name is then set to the source name in the breakpoint case. If
312 * a skipped command decides itself that a debug prompt should be displayed, it
313 * can do so by calling dbg_check_skipped().
315 static int debug_skipped;
316 static char_u *debug_skipped_name;
319 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
320 * at or below the break level. But only when the line is actually
321 * executed. Return TRUE and set breakpoint_name for skipped commands that
322 * decide to execute something themselves.
323 * Called from do_one_cmd() before executing a command.
325 void
326 dbg_check_breakpoint(eap)
327 exarg_T *eap;
329 char_u *p;
331 debug_skipped = FALSE;
332 if (debug_breakpoint_name != NULL)
334 if (!eap->skip)
336 /* replace K_SNR with "<SNR>" */
337 if (debug_breakpoint_name[0] == K_SPECIAL
338 && debug_breakpoint_name[1] == KS_EXTRA
339 && debug_breakpoint_name[2] == (int)KE_SNR)
340 p = (char_u *)"<SNR>";
341 else
342 p = (char_u *)"";
343 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
345 debug_breakpoint_name + (*p == NUL ? 0 : 3),
346 (long)debug_breakpoint_lnum);
347 debug_breakpoint_name = NULL;
348 do_debug(eap->cmd);
350 else
352 debug_skipped = TRUE;
353 debug_skipped_name = debug_breakpoint_name;
354 debug_breakpoint_name = NULL;
357 else if (ex_nesting_level <= debug_break_level)
359 if (!eap->skip)
360 do_debug(eap->cmd);
361 else
363 debug_skipped = TRUE;
364 debug_skipped_name = NULL;
370 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
371 * set. Return TRUE when the debug mode is entered this time.
374 dbg_check_skipped(eap)
375 exarg_T *eap;
377 int prev_got_int;
379 if (debug_skipped)
382 * Save the value of got_int and reset it. We don't want a previous
383 * interruption cause flushing the input buffer.
385 prev_got_int = got_int;
386 got_int = FALSE;
387 debug_breakpoint_name = debug_skipped_name;
388 /* eap->skip is TRUE */
389 eap->skip = FALSE;
390 (void)dbg_check_breakpoint(eap);
391 eap->skip = TRUE;
392 got_int |= prev_got_int;
393 return TRUE;
395 return FALSE;
399 * The list of breakpoints: dbg_breakp.
400 * This is a grow-array of structs.
402 struct debuggy
404 int dbg_nr; /* breakpoint number */
405 int dbg_type; /* DBG_FUNC or DBG_FILE */
406 char_u *dbg_name; /* function or file name */
407 regprog_T *dbg_prog; /* regexp program */
408 linenr_T dbg_lnum; /* line number in function or file */
409 int dbg_forceit; /* ! used */
412 static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
413 #define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
414 #define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
415 static int last_breakp = 0; /* nr of last defined breakpoint */
417 #ifdef FEAT_PROFILE
418 /* Profiling uses file and func names similar to breakpoints. */
419 static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
420 #endif
421 #define DBG_FUNC 1
422 #define DBG_FILE 2
424 static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
425 static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, garray_T *gap, int *fp));
428 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
429 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
430 * is allocated.
431 * Returns FAIL for failure.
433 static int
434 dbg_parsearg(arg, gap)
435 char_u *arg;
436 garray_T *gap; /* either &dbg_breakp or &prof_ga */
438 char_u *p = arg;
439 char_u *q;
440 struct debuggy *bp;
441 int here = FALSE;
443 if (ga_grow(gap, 1) == FAIL)
444 return FAIL;
445 bp = &DEBUGGY(gap, gap->ga_len);
447 /* Find "func" or "file". */
448 if (STRNCMP(p, "func", 4) == 0)
449 bp->dbg_type = DBG_FUNC;
450 else if (STRNCMP(p, "file", 4) == 0)
451 bp->dbg_type = DBG_FILE;
452 else if (
453 #ifdef FEAT_PROFILE
454 gap != &prof_ga &&
455 #endif
456 STRNCMP(p, "here", 4) == 0)
458 if (curbuf->b_ffname == NULL)
460 EMSG(_(e_noname));
461 return FAIL;
463 bp->dbg_type = DBG_FILE;
464 here = TRUE;
466 else
468 EMSG2(_(e_invarg2), p);
469 return FAIL;
471 p = skipwhite(p + 4);
473 /* Find optional line number. */
474 if (here)
475 bp->dbg_lnum = curwin->w_cursor.lnum;
476 else if (
477 #ifdef FEAT_PROFILE
478 gap != &prof_ga &&
479 #endif
480 VIM_ISDIGIT(*p))
482 bp->dbg_lnum = getdigits(&p);
483 p = skipwhite(p);
485 else
486 bp->dbg_lnum = 0;
488 /* Find the function or file name. Don't accept a function name with (). */
489 if ((!here && *p == NUL)
490 || (here && *p != NUL)
491 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
493 EMSG2(_(e_invarg2), arg);
494 return FAIL;
497 if (bp->dbg_type == DBG_FUNC)
498 bp->dbg_name = vim_strsave(p);
499 else if (here)
500 bp->dbg_name = vim_strsave(curbuf->b_ffname);
501 else
503 /* Expand the file name in the same way as do_source(). This means
504 * doing it twice, so that $DIR/file gets expanded when $DIR is
505 * "~/dir". */
506 #ifdef RISCOS
507 q = mch_munge_fname(p);
508 #else
509 q = expand_env_save(p);
510 #endif
511 if (q == NULL)
512 return FAIL;
513 #ifdef RISCOS
514 p = mch_munge_fname(q);
515 #else
516 p = expand_env_save(q);
517 #endif
518 vim_free(q);
519 if (p == NULL)
520 return FAIL;
521 if (*p != '*')
523 bp->dbg_name = fix_fname(p);
524 vim_free(p);
526 else
527 bp->dbg_name = p;
530 if (bp->dbg_name == NULL)
531 return FAIL;
532 return OK;
536 * ":breakadd".
538 void
539 ex_breakadd(eap)
540 exarg_T *eap;
542 struct debuggy *bp;
543 char_u *pat;
544 garray_T *gap;
546 gap = &dbg_breakp;
547 #ifdef FEAT_PROFILE
548 if (eap->cmdidx == CMD_profile)
549 gap = &prof_ga;
550 #endif
552 if (dbg_parsearg(eap->arg, gap) == OK)
554 bp = &DEBUGGY(gap, gap->ga_len);
555 bp->dbg_forceit = eap->forceit;
557 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
558 if (pat != NULL)
560 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
561 vim_free(pat);
563 if (pat == NULL || bp->dbg_prog == NULL)
564 vim_free(bp->dbg_name);
565 else
567 if (bp->dbg_lnum == 0) /* default line number is 1 */
568 bp->dbg_lnum = 1;
569 #ifdef FEAT_PROFILE
570 if (eap->cmdidx != CMD_profile)
571 #endif
573 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
574 ++debug_tick;
576 ++gap->ga_len;
582 * ":debuggreedy".
584 void
585 ex_debuggreedy(eap)
586 exarg_T *eap;
588 if (eap->addr_count == 0 || eap->line2 != 0)
589 debug_greedy = TRUE;
590 else
591 debug_greedy = FALSE;
595 * ":breakdel" and ":profdel".
597 void
598 ex_breakdel(eap)
599 exarg_T *eap;
601 struct debuggy *bp, *bpi;
602 int nr;
603 int todel = -1;
604 int del_all = FALSE;
605 int i;
606 linenr_T best_lnum = 0;
607 garray_T *gap;
609 gap = &dbg_breakp;
610 #ifdef FEAT_PROFILE
611 if (eap->cmdidx == CMD_profdel)
612 gap = &prof_ga;
613 #endif
615 if (vim_isdigit(*eap->arg))
617 /* ":breakdel {nr}" */
618 nr = atol((char *)eap->arg);
619 for (i = 0; i < gap->ga_len; ++i)
620 if (DEBUGGY(gap, i).dbg_nr == nr)
622 todel = i;
623 break;
626 else if (*eap->arg == '*')
628 todel = 0;
629 del_all = TRUE;
631 else
633 /* ":breakdel {func|file} [lnum] {name}" */
634 if (dbg_parsearg(eap->arg, gap) == FAIL)
635 return;
636 bp = &DEBUGGY(gap, gap->ga_len);
637 for (i = 0; i < gap->ga_len; ++i)
639 bpi = &DEBUGGY(gap, i);
640 if (bp->dbg_type == bpi->dbg_type
641 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
642 && (bp->dbg_lnum == bpi->dbg_lnum
643 || (bp->dbg_lnum == 0
644 && (best_lnum == 0
645 || bpi->dbg_lnum < best_lnum))))
647 todel = i;
648 best_lnum = bpi->dbg_lnum;
651 vim_free(bp->dbg_name);
654 if (todel < 0)
655 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
656 else
658 while (gap->ga_len > 0)
660 vim_free(DEBUGGY(gap, todel).dbg_name);
661 vim_free(DEBUGGY(gap, todel).dbg_prog);
662 --gap->ga_len;
663 if (todel < gap->ga_len)
664 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
665 (gap->ga_len - todel) * sizeof(struct debuggy));
666 #ifdef FEAT_PROFILE
667 if (eap->cmdidx == CMD_breakdel)
668 #endif
669 ++debug_tick;
670 if (!del_all)
671 break;
674 /* If all breakpoints were removed clear the array. */
675 if (gap->ga_len == 0)
676 ga_clear(gap);
681 * ":breaklist".
683 /*ARGSUSED*/
684 void
685 ex_breaklist(eap)
686 exarg_T *eap;
688 struct debuggy *bp;
689 int i;
691 if (dbg_breakp.ga_len == 0)
692 MSG(_("No breakpoints defined"));
693 else
694 for (i = 0; i < dbg_breakp.ga_len; ++i)
696 bp = &BREAKP(i);
697 smsg((char_u *)_("%3d %s %s line %ld"),
698 bp->dbg_nr,
699 bp->dbg_type == DBG_FUNC ? "func" : "file",
700 bp->dbg_name,
701 (long)bp->dbg_lnum);
706 * Find a breakpoint for a function or sourced file.
707 * Returns line number at which to break; zero when no matching breakpoint.
709 linenr_T
710 dbg_find_breakpoint(file, fname, after)
711 int file; /* TRUE for a file, FALSE for a function */
712 char_u *fname; /* file or function name */
713 linenr_T after; /* after this line number */
715 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
718 #if defined(FEAT_PROFILE) || defined(PROTO)
720 * Return TRUE if profiling is on for a function or sourced file.
723 has_profiling(file, fname, fp)
724 int file; /* TRUE for a file, FALSE for a function */
725 char_u *fname; /* file or function name */
726 int *fp; /* return: forceit */
728 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
729 != (linenr_T)0);
731 #endif
734 * Common code for dbg_find_breakpoint() and has_profiling().
736 static linenr_T
737 debuggy_find(file, fname, after, gap, fp)
738 int file; /* TRUE for a file, FALSE for a function */
739 char_u *fname; /* file or function name */
740 linenr_T after; /* after this line number */
741 garray_T *gap; /* either &dbg_breakp or &prof_ga */
742 int *fp; /* if not NULL: return forceit */
744 struct debuggy *bp;
745 int i;
746 linenr_T lnum = 0;
747 regmatch_T regmatch;
748 char_u *name = fname;
749 int prev_got_int;
751 /* Return quickly when there are no breakpoints. */
752 if (gap->ga_len == 0)
753 return (linenr_T)0;
755 /* Replace K_SNR in function name with "<SNR>". */
756 if (!file && fname[0] == K_SPECIAL)
758 name = alloc((unsigned)STRLEN(fname) + 3);
759 if (name == NULL)
760 name = fname;
761 else
763 STRCPY(name, "<SNR>");
764 STRCPY(name + 5, fname + 3);
768 for (i = 0; i < gap->ga_len; ++i)
770 /* Skip entries that are not useful or are for a line that is beyond
771 * an already found breakpoint. */
772 bp = &DEBUGGY(gap, i);
773 if (((bp->dbg_type == DBG_FILE) == file && (
774 #ifdef FEAT_PROFILE
775 gap == &prof_ga ||
776 #endif
777 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
779 regmatch.regprog = bp->dbg_prog;
780 regmatch.rm_ic = FALSE;
782 * Save the value of got_int and reset it. We don't want a
783 * previous interruption cancel matching, only hitting CTRL-C
784 * while matching should abort it.
786 prev_got_int = got_int;
787 got_int = FALSE;
788 if (vim_regexec(&regmatch, name, (colnr_T)0))
790 lnum = bp->dbg_lnum;
791 if (fp != NULL)
792 *fp = bp->dbg_forceit;
794 got_int |= prev_got_int;
797 if (name != fname)
798 vim_free(name);
800 return lnum;
804 * Called when a breakpoint was encountered.
806 void
807 dbg_breakpoint(name, lnum)
808 char_u *name;
809 linenr_T lnum;
811 /* We need to check if this line is actually executed in do_one_cmd() */
812 debug_breakpoint_name = name;
813 debug_breakpoint_lnum = lnum;
817 # if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
819 * Store the current time in "tm".
821 void
822 profile_start(tm)
823 proftime_T *tm;
825 # ifdef WIN3264
826 QueryPerformanceCounter(tm);
827 # else
828 gettimeofday(tm, NULL);
829 # endif
833 * Compute the elapsed time from "tm" till now and store in "tm".
835 void
836 profile_end(tm)
837 proftime_T *tm;
839 proftime_T now;
841 # ifdef WIN3264
842 QueryPerformanceCounter(&now);
843 tm->QuadPart = now.QuadPart - tm->QuadPart;
844 # else
845 gettimeofday(&now, NULL);
846 tm->tv_usec = now.tv_usec - tm->tv_usec;
847 tm->tv_sec = now.tv_sec - tm->tv_sec;
848 if (tm->tv_usec < 0)
850 tm->tv_usec += 1000000;
851 --tm->tv_sec;
853 # endif
857 * Subtract the time "tm2" from "tm".
859 void
860 profile_sub(tm, tm2)
861 proftime_T *tm, *tm2;
863 # ifdef WIN3264
864 tm->QuadPart -= tm2->QuadPart;
865 # else
866 tm->tv_usec -= tm2->tv_usec;
867 tm->tv_sec -= tm2->tv_sec;
868 if (tm->tv_usec < 0)
870 tm->tv_usec += 1000000;
871 --tm->tv_sec;
873 # endif
877 * Return a string that represents the time in "tm".
878 * Uses a static buffer!
880 char *
881 profile_msg(tm)
882 proftime_T *tm;
884 static char buf[50];
886 # ifdef WIN3264
887 LARGE_INTEGER fr;
889 QueryPerformanceFrequency(&fr);
890 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
891 # else
892 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
893 # endif
894 return buf;
898 * Put the time "msec" past now in "tm".
900 void
901 profile_setlimit(msec, tm)
902 long msec;
903 proftime_T *tm;
905 if (msec <= 0) /* no limit */
906 profile_zero(tm);
907 else
909 # ifdef WIN3264
910 LARGE_INTEGER fr;
912 QueryPerformanceCounter(tm);
913 QueryPerformanceFrequency(&fr);
914 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
915 # else
916 long usec;
918 gettimeofday(tm, NULL);
919 usec = (long)tm->tv_usec + (long)msec * 1000;
920 tm->tv_usec = usec % 1000000L;
921 tm->tv_sec += usec / 1000000L;
922 # endif
927 * Return TRUE if the current time is past "tm".
930 profile_passed_limit(tm)
931 proftime_T *tm;
933 proftime_T now;
935 # ifdef WIN3264
936 if (tm->QuadPart == 0) /* timer was not set */
937 return FALSE;
938 QueryPerformanceCounter(&now);
939 return (now.QuadPart > tm->QuadPart);
940 # else
941 if (tm->tv_sec == 0) /* timer was not set */
942 return FALSE;
943 gettimeofday(&now, NULL);
944 return (now.tv_sec > tm->tv_sec
945 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
946 # endif
950 * Set the time in "tm" to zero.
952 void
953 profile_zero(tm)
954 proftime_T *tm;
956 # ifdef WIN3264
957 tm->QuadPart = 0;
958 # else
959 tm->tv_usec = 0;
960 tm->tv_sec = 0;
961 # endif
964 # endif /* FEAT_PROFILE || FEAT_RELTIME */
966 # if defined(FEAT_PROFILE) || defined(PROTO)
968 * Functions for profiling.
970 static void script_do_profile __ARGS((scriptitem_T *si));
971 static void script_dump_profile __ARGS((FILE *fd));
972 static proftime_T prof_wait_time;
975 * Add the time "tm2" to "tm".
977 void
978 profile_add(tm, tm2)
979 proftime_T *tm, *tm2;
981 # ifdef WIN3264
982 tm->QuadPart += tm2->QuadPart;
983 # else
984 tm->tv_usec += tm2->tv_usec;
985 tm->tv_sec += tm2->tv_sec;
986 if (tm->tv_usec >= 1000000)
988 tm->tv_usec -= 1000000;
989 ++tm->tv_sec;
991 # endif
995 * Add the "self" time from the total time and the children's time.
997 void
998 profile_self(self, total, children)
999 proftime_T *self, *total, *children;
1001 /* Check that the result won't be negative. Can happen with recursive
1002 * calls. */
1003 #ifdef WIN3264
1004 if (total->QuadPart <= children->QuadPart)
1005 return;
1006 #else
1007 if (total->tv_sec < children->tv_sec
1008 || (total->tv_sec == children->tv_sec
1009 && total->tv_usec <= children->tv_usec))
1010 return;
1011 #endif
1012 profile_add(self, total);
1013 profile_sub(self, children);
1017 * Get the current waittime.
1019 void
1020 profile_get_wait(tm)
1021 proftime_T *tm;
1023 *tm = prof_wait_time;
1027 * Subtract the passed waittime since "tm" from "tma".
1029 void
1030 profile_sub_wait(tm, tma)
1031 proftime_T *tm, *tma;
1033 proftime_T tm3 = prof_wait_time;
1035 profile_sub(&tm3, tm);
1036 profile_sub(tma, &tm3);
1040 * Return TRUE if "tm1" and "tm2" are equal.
1043 profile_equal(tm1, tm2)
1044 proftime_T *tm1, *tm2;
1046 # ifdef WIN3264
1047 return (tm1->QuadPart == tm2->QuadPart);
1048 # else
1049 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
1050 # endif
1054 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1057 profile_cmp(tm1, tm2)
1058 proftime_T *tm1, *tm2;
1060 # ifdef WIN3264
1061 return (int)(tm2->QuadPart - tm1->QuadPart);
1062 # else
1063 if (tm1->tv_sec == tm2->tv_sec)
1064 return tm2->tv_usec - tm1->tv_usec;
1065 return tm2->tv_sec - tm1->tv_sec;
1066 # endif
1069 static char_u *profile_fname = NULL;
1070 static proftime_T pause_time;
1073 * ":profile cmd args"
1075 void
1076 ex_profile(eap)
1077 exarg_T *eap;
1079 char_u *e;
1080 int len;
1082 e = skiptowhite(eap->arg);
1083 len = (int)(e - eap->arg);
1084 e = skipwhite(e);
1086 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1088 vim_free(profile_fname);
1089 profile_fname = vim_strsave(e);
1090 do_profiling = PROF_YES;
1091 profile_zero(&prof_wait_time);
1092 set_vim_var_nr(VV_PROFILING, 1L);
1094 else if (do_profiling == PROF_NONE)
1095 EMSG(_("E750: First use :profile start <fname>"));
1096 else if (STRCMP(eap->arg, "pause") == 0)
1098 if (do_profiling == PROF_YES)
1099 profile_start(&pause_time);
1100 do_profiling = PROF_PAUSED;
1102 else if (STRCMP(eap->arg, "continue") == 0)
1104 if (do_profiling == PROF_PAUSED)
1106 profile_end(&pause_time);
1107 profile_add(&prof_wait_time, &pause_time);
1109 do_profiling = PROF_YES;
1111 else
1113 /* The rest is similar to ":breakadd". */
1114 ex_breakadd(eap);
1119 * Dump the profiling info.
1121 void
1122 profile_dump()
1124 FILE *fd;
1126 if (profile_fname != NULL)
1128 fd = mch_fopen((char *)profile_fname, "w");
1129 if (fd == NULL)
1130 EMSG2(_(e_notopen), profile_fname);
1131 else
1133 script_dump_profile(fd);
1134 func_dump_profile(fd);
1135 fclose(fd);
1141 * Start profiling script "fp".
1143 static void
1144 script_do_profile(si)
1145 scriptitem_T *si;
1147 si->sn_pr_count = 0;
1148 profile_zero(&si->sn_pr_total);
1149 profile_zero(&si->sn_pr_self);
1151 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1152 si->sn_prl_idx = -1;
1153 si->sn_prof_on = TRUE;
1154 si->sn_pr_nest = 0;
1158 * save time when starting to invoke another script or function.
1160 void
1161 script_prof_save(tm)
1162 proftime_T *tm; /* place to store wait time */
1164 scriptitem_T *si;
1166 if (current_SID > 0 && current_SID <= script_items.ga_len)
1168 si = &SCRIPT_ITEM(current_SID);
1169 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1170 profile_start(&si->sn_pr_child);
1172 profile_get_wait(tm);
1176 * Count time spent in children after invoking another script or function.
1178 void
1179 script_prof_restore(tm)
1180 proftime_T *tm;
1182 scriptitem_T *si;
1184 if (current_SID > 0 && current_SID <= script_items.ga_len)
1186 si = &SCRIPT_ITEM(current_SID);
1187 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1189 profile_end(&si->sn_pr_child);
1190 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1191 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1192 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1197 static proftime_T inchar_time;
1200 * Called when starting to wait for the user to type a character.
1202 void
1203 prof_inchar_enter()
1205 profile_start(&inchar_time);
1209 * Called when finished waiting for the user to type a character.
1211 void
1212 prof_inchar_exit()
1214 profile_end(&inchar_time);
1215 profile_add(&prof_wait_time, &inchar_time);
1219 * Dump the profiling results for all scripts in file "fd".
1221 static void
1222 script_dump_profile(fd)
1223 FILE *fd;
1225 int id;
1226 scriptitem_T *si;
1227 int i;
1228 FILE *sfd;
1229 sn_prl_T *pp;
1231 for (id = 1; id <= script_items.ga_len; ++id)
1233 si = &SCRIPT_ITEM(id);
1234 if (si->sn_prof_on)
1236 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1237 if (si->sn_pr_count == 1)
1238 fprintf(fd, "Sourced 1 time\n");
1239 else
1240 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1241 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1242 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1243 fprintf(fd, "\n");
1244 fprintf(fd, "count total (s) self (s)\n");
1246 sfd = mch_fopen((char *)si->sn_name, "r");
1247 if (sfd == NULL)
1248 fprintf(fd, "Cannot open file!\n");
1249 else
1251 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1253 if (vim_fgets(IObuff, IOSIZE, sfd))
1254 break;
1255 pp = &PRL_ITEM(si, i);
1256 if (pp->snp_count > 0)
1258 fprintf(fd, "%5d ", pp->snp_count);
1259 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1260 fprintf(fd, " ");
1261 else
1262 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1263 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1265 else
1266 fprintf(fd, " ");
1267 fprintf(fd, "%s", IObuff);
1269 fclose(sfd);
1271 fprintf(fd, "\n");
1277 * Return TRUE when a function defined in the current script should be
1278 * profiled.
1281 prof_def_func()
1283 if (current_SID > 0)
1284 return SCRIPT_ITEM(current_SID).sn_pr_force;
1285 return FALSE;
1288 # endif
1289 #endif
1292 * If 'autowrite' option set, try to write the file.
1293 * Careful: autocommands may make "buf" invalid!
1295 * return FAIL for failure, OK otherwise
1298 autowrite(buf, forceit)
1299 buf_T *buf;
1300 int forceit;
1302 int r;
1304 if (!(p_aw || p_awa) || !p_write
1305 #ifdef FEAT_QUICKFIX
1306 /* never autowrite a "nofile" or "nowrite" buffer */
1307 || bt_dontwrite(buf)
1308 #endif
1309 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
1310 return FAIL;
1311 r = buf_write_all(buf, forceit);
1313 /* Writing may succeed but the buffer still changed, e.g., when there is a
1314 * conversion error. We do want to return FAIL then. */
1315 if (buf_valid(buf) && bufIsChanged(buf))
1316 r = FAIL;
1317 return r;
1321 * flush all buffers, except the ones that are readonly
1323 void
1324 autowrite_all()
1326 buf_T *buf;
1328 if (!(p_aw || p_awa) || !p_write)
1329 return;
1330 for (buf = firstbuf; buf; buf = buf->b_next)
1331 if (bufIsChanged(buf) && !buf->b_p_ro)
1333 (void)buf_write_all(buf, FALSE);
1334 #ifdef FEAT_AUTOCMD
1335 /* an autocommand may have deleted the buffer */
1336 if (!buf_valid(buf))
1337 buf = firstbuf;
1338 #endif
1343 * return TRUE if buffer was changed and cannot be abandoned.
1345 /*ARGSUSED*/
1347 check_changed(buf, checkaw, mult_win, forceit, allbuf)
1348 buf_T *buf;
1349 int checkaw; /* do autowrite if buffer was changed */
1350 int mult_win; /* check also when several wins for the buf */
1351 int forceit;
1352 int allbuf; /* may write all buffers */
1354 if ( !forceit
1355 && bufIsChanged(buf)
1356 && (mult_win || buf->b_nwindows <= 1)
1357 && (!checkaw || autowrite(buf, forceit) == FAIL))
1359 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1360 if ((p_confirm || cmdmod.confirm) && p_write)
1362 buf_T *buf2;
1363 int count = 0;
1365 if (allbuf)
1366 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1367 if (bufIsChanged(buf2)
1368 && (buf2->b_ffname != NULL
1369 # ifdef FEAT_BROWSE
1370 || cmdmod.browse
1371 # endif
1373 ++count;
1374 # ifdef FEAT_AUTOCMD
1375 if (!buf_valid(buf))
1376 /* Autocommand deleted buffer, oops! It's not changed now. */
1377 return FALSE;
1378 # endif
1379 dialog_changed(buf, count > 1);
1380 # ifdef FEAT_AUTOCMD
1381 if (!buf_valid(buf))
1382 /* Autocommand deleted buffer, oops! It's not changed now. */
1383 return FALSE;
1384 # endif
1385 return bufIsChanged(buf);
1387 #endif
1388 EMSG(_(e_nowrtmsg));
1389 return TRUE;
1391 return FALSE;
1394 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1396 #if defined(FEAT_BROWSE) || defined(PROTO)
1398 * When wanting to write a file without a file name, ask the user for a name.
1400 void
1401 browse_save_fname(buf)
1402 buf_T *buf;
1404 if (buf->b_fname == NULL)
1406 char_u *fname;
1408 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1409 NULL, NULL, NULL, NULL, buf);
1410 if (fname != NULL)
1412 if (setfname(buf, fname, NULL, TRUE) == OK)
1413 buf->b_flags |= BF_NOTEDITED;
1414 vim_free(fname);
1418 #endif
1420 #ifdef FEAT_GUI_MACVIM
1422 * "Save changes" dialog that conforms to the Apple HIG.
1425 vim_dialog_save_changes(buf)
1426 buf_T *buf;
1428 char_u buff[IOSIZE];
1430 dialog_msg(buff, _("Do you want to save the changes you made in the "
1431 "document \"%s\"?"), buf->b_fname);
1432 switch (do_dialog(VIM_QUESTION, buff,
1433 (char_u*) _("Your changes will be lost if you don't save "
1434 "them."),
1435 (buf->b_fname != NULL)
1436 ? (char_u *)_("&Save\n&Cancel\n&Don't Save")
1437 : (char_u *)_("&Save...\n&Cancel\n&Don't Save"),
1438 1, NULL))
1440 case 1: return VIM_YES;
1441 case 3: return VIM_NO;
1444 return VIM_CANCEL;
1448 * "Save all changes" dialog that tries to emulate the above "Save changes"
1449 * dialog for the case of several modified buffers.
1452 vim_dialog_save_all_changes(buf)
1453 buf_T *buf;
1455 char_u buff[IOSIZE];
1457 dialog_msg(buff, _("There are several documents with unsaved changes. "
1458 "Do you want to save the changes you made in the "
1459 "document \"%s\"?"), buf->b_fname);
1460 switch (do_dialog(VIM_QUESTION, buff,
1461 (char_u*) _("Your changes will be lost if you don't save "
1462 "them."),
1463 (char_u *)_("&Save\n&Don't Save\nS&ave All\nD&iscard All\n"
1464 "&Cancel"),
1465 1, NULL))
1467 case 1: return VIM_YES;
1468 case 2: return VIM_NO;
1469 case 3: return VIM_ALL;
1470 case 4: return VIM_DISCARDALL;
1473 return VIM_CANCEL;
1475 #endif
1478 * Ask the user what to do when abondoning a changed buffer.
1479 * Must check 'write' option first!
1481 void
1482 dialog_changed(buf, checkall)
1483 buf_T *buf;
1484 int checkall; /* may abandon all changed buffers */
1486 char_u buff[IOSIZE];
1487 int ret;
1488 buf_T *buf2;
1490 #ifdef FEAT_GUI_MACVIM
1491 /* Save dialogs on Mac OS X are standardized so in case the GUI is enabled
1492 * and "c" isn't in 'guioptions' we use a OS X specific dialog. */
1493 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
1495 if (checkall)
1496 ret = vim_dialog_save_all_changes(buf);
1497 else
1498 ret = vim_dialog_save_changes(buf);
1500 else
1502 #endif
1503 dialog_msg(buff, _("Save changes to \"%s\"?"),
1504 (buf->b_fname != NULL) ?
1505 buf->b_fname : (char_u *)_("Untitled"));
1506 if (checkall)
1507 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1508 else
1509 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1510 #ifdef FEAT_GUI_MACVIM
1512 #endif
1514 if (ret == VIM_YES)
1516 #ifdef FEAT_BROWSE
1517 /* May get file name, when there is none */
1518 browse_save_fname(buf);
1519 #endif
1520 if (buf->b_fname != NULL) /* didn't hit Cancel */
1521 (void)buf_write_all(buf, FALSE);
1523 else if (ret == VIM_NO)
1525 unchanged(buf, TRUE);
1527 else if (ret == VIM_ALL)
1530 * Write all modified files that can be written.
1531 * Skip readonly buffers, these need to be confirmed
1532 * individually.
1534 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1536 if (bufIsChanged(buf2)
1537 && (buf2->b_ffname != NULL
1538 #ifdef FEAT_BROWSE
1539 || cmdmod.browse
1540 #endif
1542 && !buf2->b_p_ro)
1544 #ifdef FEAT_BROWSE
1545 /* May get file name, when there is none */
1546 browse_save_fname(buf2);
1547 #endif
1548 if (buf2->b_fname != NULL) /* didn't hit Cancel */
1549 (void)buf_write_all(buf2, FALSE);
1550 #ifdef FEAT_AUTOCMD
1551 /* an autocommand may have deleted the buffer */
1552 if (!buf_valid(buf2))
1553 buf2 = firstbuf;
1554 #endif
1558 else if (ret == VIM_DISCARDALL)
1561 * mark all buffers as unchanged
1563 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1564 unchanged(buf2, TRUE);
1567 #endif
1570 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1571 * hidden, autowriting it or unloading it.
1574 can_abandon(buf, forceit)
1575 buf_T *buf;
1576 int forceit;
1578 return ( P_HID(buf)
1579 || !bufIsChanged(buf)
1580 || buf->b_nwindows > 1
1581 || autowrite(buf, forceit) == OK
1582 || forceit);
1586 * Return TRUE if any buffer was changed and cannot be abandoned.
1587 * That changed buffer becomes the current buffer.
1590 check_changed_any(hidden)
1591 int hidden; /* Only check hidden buffers */
1593 buf_T *buf;
1594 int save;
1595 #ifdef FEAT_WINDOWS
1596 win_T *wp;
1597 #endif
1599 for (;;)
1601 /* check curbuf first: if it was changed we can't abandon it */
1602 if (!hidden && curbufIsChanged())
1603 buf = curbuf;
1604 else
1606 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1607 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1608 break;
1610 if (buf == NULL) /* No buffers changed */
1611 return FALSE;
1613 /* Try auto-writing the buffer. If this fails but the buffer no
1614 * longer exists it's not changed, that's OK. */
1615 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
1616 break; /* didn't save - still changes */
1619 exiting = FALSE;
1620 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1622 * When ":confirm" used, don't give an error message.
1624 if (!(p_confirm || cmdmod.confirm))
1625 #endif
1627 /* There must be a wait_return for this message, do_buffer()
1628 * may cause a redraw. But wait_return() is a no-op when vgetc()
1629 * is busy (Quit used from window menu), then make sure we don't
1630 * cause a scroll up. */
1631 if (vgetc_busy > 0)
1633 msg_row = cmdline_row;
1634 msg_col = 0;
1635 msg_didout = FALSE;
1637 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
1638 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
1639 buf->b_fname))
1641 save = no_wait_return;
1642 no_wait_return = FALSE;
1643 wait_return(FALSE);
1644 no_wait_return = save;
1648 #ifdef FEAT_WINDOWS
1649 /* Try to find a window that contains the buffer. */
1650 if (buf != curbuf)
1651 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1652 if (wp->w_buffer == buf)
1654 win_goto(wp);
1655 # ifdef FEAT_AUTOCMD
1656 /* Paranoia: did autocms wipe out the buffer with changes? */
1657 if (!buf_valid(buf))
1658 return TRUE;
1659 # endif
1660 break;
1662 #endif
1664 /* Open the changed buffer in the current window. */
1665 if (buf != curbuf)
1666 set_curbuf(buf, DOBUF_GOTO);
1668 return TRUE;
1672 * return FAIL if there is no file name, OK if there is one
1673 * give error message for FAIL
1676 check_fname()
1678 if (curbuf->b_ffname == NULL)
1680 EMSG(_(e_noname));
1681 return FAIL;
1683 return OK;
1687 * flush the contents of a buffer, unless it has no file name
1689 * return FAIL for failure, OK otherwise
1692 buf_write_all(buf, forceit)
1693 buf_T *buf;
1694 int forceit;
1696 int retval;
1697 #ifdef FEAT_AUTOCMD
1698 buf_T *old_curbuf = curbuf;
1699 #endif
1701 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1702 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1703 FALSE, forceit, TRUE, FALSE));
1704 #ifdef FEAT_AUTOCMD
1705 if (curbuf != old_curbuf)
1707 msg_source(hl_attr(HLF_W));
1708 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
1710 #endif
1711 return retval;
1715 * Code to handle the argument list.
1718 static char_u *do_one_arg __ARGS((char_u *str));
1719 static int do_arglist __ARGS((char_u *str, int what, int after));
1720 static void alist_check_arg_idx __ARGS((void));
1721 static int editing_arg_idx __ARGS((win_T *win));
1722 #ifdef FEAT_LISTCMDS
1723 static int alist_add_list __ARGS((int count, char_u **files, int after));
1724 #endif
1725 #define AL_SET 1
1726 #define AL_ADD 2
1727 #define AL_DEL 3
1730 * Isolate one argument, taking backticks.
1731 * Changes the argument in-place, puts a NUL after it. Backticks remain.
1732 * Return a pointer to the start of the next argument.
1734 static char_u *
1735 do_one_arg(str)
1736 char_u *str;
1738 char_u *p;
1739 int inbacktick;
1741 inbacktick = FALSE;
1742 for (p = str; *str; ++str)
1744 /* When the backslash is used for escaping the special meaning of a
1745 * character we need to keep it until wildcard expansion. */
1746 if (rem_backslash(str))
1748 *p++ = *str++;
1749 *p++ = *str;
1751 else
1753 /* An item ends at a space not in backticks */
1754 if (!inbacktick && vim_isspace(*str))
1755 break;
1756 if (*str == '`')
1757 inbacktick ^= TRUE;
1758 *p++ = *str;
1761 str = skipwhite(str);
1762 *p = NUL;
1764 return str;
1768 * Separate the arguments in "str" and return a list of pointers in the
1769 * growarray "gap".
1772 get_arglist(gap, str)
1773 garray_T *gap;
1774 char_u *str;
1776 ga_init2(gap, (int)sizeof(char_u *), 20);
1777 while (*str != NUL)
1779 if (ga_grow(gap, 1) == FAIL)
1781 ga_clear(gap);
1782 return FAIL;
1784 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1786 /* Isolate one argument, change it in-place, put a NUL after it. */
1787 str = do_one_arg(str);
1789 return OK;
1792 #if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
1794 * Parse a list of arguments (file names), expand them and return in
1795 * "fnames[fcountp]".
1796 * Return FAIL or OK.
1799 get_arglist_exp(str, fcountp, fnamesp)
1800 char_u *str;
1801 int *fcountp;
1802 char_u ***fnamesp;
1804 garray_T ga;
1805 int i;
1807 if (get_arglist(&ga, str) == FAIL)
1808 return FAIL;
1809 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1810 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1811 ga_clear(&ga);
1812 return i;
1814 #endif
1816 #if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1818 * Redefine the argument list.
1820 void
1821 set_arglist(str)
1822 char_u *str;
1824 do_arglist(str, AL_SET, 0);
1826 #endif
1829 * "what" == AL_SET: Redefine the argument list to 'str'.
1830 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1831 * "what" == AL_DEL: remove files in 'str' from the argument list.
1833 * Return FAIL for failure, OK otherwise.
1835 /*ARGSUSED*/
1836 static int
1837 do_arglist(str, what, after)
1838 char_u *str;
1839 int what;
1840 int after; /* 0 means before first one */
1842 garray_T new_ga;
1843 int exp_count;
1844 char_u **exp_files;
1845 int i;
1846 #ifdef FEAT_LISTCMDS
1847 char_u *p;
1848 int match;
1849 #endif
1852 * Collect all file name arguments in "new_ga".
1854 if (get_arglist(&new_ga, str) == FAIL)
1855 return FAIL;
1857 #ifdef FEAT_LISTCMDS
1858 if (what == AL_DEL)
1860 regmatch_T regmatch;
1861 int didone;
1864 * Delete the items: use each item as a regexp and find a match in the
1865 * argument list.
1867 #ifdef CASE_INSENSITIVE_FILENAME
1868 regmatch.rm_ic = TRUE; /* Always ignore case */
1869 #else
1870 regmatch.rm_ic = FALSE; /* Never ignore case */
1871 #endif
1872 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1874 p = ((char_u **)new_ga.ga_data)[i];
1875 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1876 if (p == NULL)
1877 break;
1878 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1879 if (regmatch.regprog == NULL)
1881 vim_free(p);
1882 break;
1885 didone = FALSE;
1886 for (match = 0; match < ARGCOUNT; ++match)
1887 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1888 (colnr_T)0))
1890 didone = TRUE;
1891 vim_free(ARGLIST[match].ae_fname);
1892 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1893 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1894 --ALIST(curwin)->al_ga.ga_len;
1895 if (curwin->w_arg_idx > match)
1896 --curwin->w_arg_idx;
1897 --match;
1900 vim_free(regmatch.regprog);
1901 vim_free(p);
1902 if (!didone)
1903 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1905 ga_clear(&new_ga);
1907 else
1908 #endif
1910 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1911 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1912 ga_clear(&new_ga);
1913 if (i == FAIL)
1914 return FAIL;
1915 if (exp_count == 0)
1917 EMSG(_(e_nomatch));
1918 return FAIL;
1921 #ifdef FEAT_LISTCMDS
1922 if (what == AL_ADD)
1924 (void)alist_add_list(exp_count, exp_files, after);
1925 vim_free(exp_files);
1927 else /* what == AL_SET */
1928 #endif
1929 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
1932 alist_check_arg_idx();
1934 return OK;
1938 * Check the validity of the arg_idx for each other window.
1940 static void
1941 alist_check_arg_idx()
1943 #ifdef FEAT_WINDOWS
1944 win_T *win;
1945 tabpage_T *tp;
1947 FOR_ALL_TAB_WINDOWS(tp, win)
1948 if (win->w_alist == curwin->w_alist)
1949 check_arg_idx(win);
1950 #else
1951 check_arg_idx(curwin);
1952 #endif
1956 * Return TRUE if window "win" is editing then file at the current argument
1957 * index.
1959 static int
1960 editing_arg_idx(win)
1961 win_T *win;
1963 return !(win->w_arg_idx >= WARGCOUNT(win)
1964 || (win->w_buffer->b_fnum
1965 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1966 && (win->w_buffer->b_ffname == NULL
1967 || !(fullpathcmp(
1968 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1969 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1973 * Check if window "win" is editing the w_arg_idx file in its argument list.
1975 void
1976 check_arg_idx(win)
1977 win_T *win;
1979 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
1981 /* We are not editing the current entry in the argument list.
1982 * Set "arg_had_last" if we are editing the last one. */
1983 win->w_arg_idx_invalid = TRUE;
1984 if (win->w_arg_idx != WARGCOUNT(win) - 1
1985 && arg_had_last == FALSE
1986 #ifdef FEAT_WINDOWS
1987 && ALIST(win) == &global_alist
1988 #endif
1989 && GARGCOUNT > 0
1990 && win->w_arg_idx < GARGCOUNT
1991 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1992 || (win->w_buffer->b_ffname != NULL
1993 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1994 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1995 arg_had_last = TRUE;
1997 else
1999 /* We are editing the current entry in the argument list.
2000 * Set "arg_had_last" if it's also the last one */
2001 win->w_arg_idx_invalid = FALSE;
2002 if (win->w_arg_idx == WARGCOUNT(win) - 1
2003 #ifdef FEAT_WINDOWS
2004 && win->w_alist == &global_alist
2005 #endif
2007 arg_had_last = TRUE;
2012 * ":args", ":argslocal" and ":argsglobal".
2014 void
2015 ex_args(eap)
2016 exarg_T *eap;
2018 int i;
2020 if (eap->cmdidx != CMD_args)
2022 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2023 alist_unlink(ALIST(curwin));
2024 if (eap->cmdidx == CMD_argglobal)
2025 ALIST(curwin) = &global_alist;
2026 else /* eap->cmdidx == CMD_arglocal */
2027 alist_new();
2028 #else
2029 ex_ni(eap);
2030 return;
2031 #endif
2034 if (!ends_excmd(*eap->arg))
2037 * ":args file ..": define new argument list, handle like ":next"
2038 * Also for ":argslocal file .." and ":argsglobal file ..".
2040 ex_next(eap);
2042 else
2043 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2044 if (eap->cmdidx == CMD_args)
2045 #endif
2048 * ":args": list arguments.
2050 if (ARGCOUNT > 0)
2052 /* Overwrite the command, for a short list there is no scrolling
2053 * required and no wait_return(). */
2054 gotocmdline(TRUE);
2055 for (i = 0; i < ARGCOUNT; ++i)
2057 if (i == curwin->w_arg_idx)
2058 msg_putchar('[');
2059 msg_outtrans(alist_name(&ARGLIST[i]));
2060 if (i == curwin->w_arg_idx)
2061 msg_putchar(']');
2062 msg_putchar(' ');
2066 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2067 else if (eap->cmdidx == CMD_arglocal)
2069 garray_T *gap = &curwin->w_alist->al_ga;
2072 * ":argslocal": make a local copy of the global argument list.
2074 if (ga_grow(gap, GARGCOUNT) == OK)
2075 for (i = 0; i < GARGCOUNT; ++i)
2076 if (GARGLIST[i].ae_fname != NULL)
2078 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2079 vim_strsave(GARGLIST[i].ae_fname);
2080 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2081 GARGLIST[i].ae_fnum;
2082 ++gap->ga_len;
2085 #endif
2089 * ":previous", ":sprevious", ":Next" and ":sNext".
2091 void
2092 ex_previous(eap)
2093 exarg_T *eap;
2095 /* If past the last one already, go to the last one. */
2096 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2097 do_argfile(eap, ARGCOUNT - 1);
2098 else
2099 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2103 * ":rewind", ":first", ":sfirst" and ":srewind".
2105 void
2106 ex_rewind(eap)
2107 exarg_T *eap;
2109 do_argfile(eap, 0);
2113 * ":last" and ":slast".
2115 void
2116 ex_last(eap)
2117 exarg_T *eap;
2119 do_argfile(eap, ARGCOUNT - 1);
2123 * ":argument" and ":sargument".
2125 void
2126 ex_argument(eap)
2127 exarg_T *eap;
2129 int i;
2131 if (eap->addr_count > 0)
2132 i = eap->line2 - 1;
2133 else
2134 i = curwin->w_arg_idx;
2135 do_argfile(eap, i);
2139 * Edit file "argn" of the argument lists.
2141 void
2142 do_argfile(eap, argn)
2143 exarg_T *eap;
2144 int argn;
2146 int other;
2147 char_u *p;
2148 int old_arg_idx = curwin->w_arg_idx;
2150 if (argn < 0 || argn >= ARGCOUNT)
2152 if (ARGCOUNT <= 1)
2153 EMSG(_("E163: There is only one file to edit"));
2154 else if (argn < 0)
2155 EMSG(_("E164: Cannot go before first file"));
2156 else
2157 EMSG(_("E165: Cannot go beyond last file"));
2159 else
2161 setpcmark();
2162 #ifdef FEAT_GUI
2163 need_mouse_correct = TRUE;
2164 #endif
2166 #ifdef FEAT_WINDOWS
2167 /* split window or create new tab page first */
2168 if (*eap->cmd == 's' || cmdmod.tab != 0)
2170 if (win_split(0, 0) == FAIL)
2171 return;
2172 # ifdef FEAT_SCROLLBIND
2173 curwin->w_p_scb = FALSE;
2174 # endif
2176 else
2177 #endif
2180 * if 'hidden' set, only check for changed file when re-editing
2181 * the same buffer
2183 other = TRUE;
2184 if (P_HID(curbuf))
2186 p = fix_fname(alist_name(&ARGLIST[argn]));
2187 other = otherfile(p);
2188 vim_free(p);
2190 if ((!P_HID(curbuf) || !other)
2191 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
2192 return;
2195 curwin->w_arg_idx = argn;
2196 if (argn == ARGCOUNT - 1
2197 #ifdef FEAT_WINDOWS
2198 && curwin->w_alist == &global_alist
2199 #endif
2201 arg_had_last = TRUE;
2203 /* Edit the file; always use the last known line number.
2204 * When it fails (e.g. Abort for already edited file) restore the
2205 * argument index. */
2206 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
2207 eap, ECMD_LAST,
2208 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) +
2209 (eap->forceit ? ECMD_FORCEIT : 0)) == FAIL)
2210 curwin->w_arg_idx = old_arg_idx;
2211 /* like Vi: set the mark where the cursor is in the file. */
2212 else if (eap->cmdidx != CMD_argdo)
2213 setmark('\'');
2218 * ":next", and commands that behave like it.
2220 void
2221 ex_next(eap)
2222 exarg_T *eap;
2224 int i;
2227 * check for changed buffer now, if this fails the argument list is not
2228 * redefined.
2230 if ( P_HID(curbuf)
2231 || eap->cmdidx == CMD_snext
2232 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2234 if (*eap->arg != NUL) /* redefine file list */
2236 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2237 return;
2238 i = 0;
2240 else
2241 i = curwin->w_arg_idx + (int)eap->line2;
2242 do_argfile(eap, i);
2246 #ifdef FEAT_LISTCMDS
2248 * ":argedit"
2250 void
2251 ex_argedit(eap)
2252 exarg_T *eap;
2254 int fnum;
2255 int i;
2256 char_u *s;
2258 /* Add the argument to the buffer list and get the buffer number. */
2259 fnum = buflist_add(eap->arg, BLN_LISTED);
2261 /* Check if this argument is already in the argument list. */
2262 for (i = 0; i < ARGCOUNT; ++i)
2263 if (ARGLIST[i].ae_fnum == fnum)
2264 break;
2265 if (i == ARGCOUNT)
2267 /* Can't find it, add it to the argument list. */
2268 s = vim_strsave(eap->arg);
2269 if (s == NULL)
2270 return;
2271 i = alist_add_list(1, &s,
2272 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2273 if (i < 0)
2274 return;
2275 curwin->w_arg_idx = i;
2278 alist_check_arg_idx();
2280 /* Edit the argument. */
2281 do_argfile(eap, i);
2285 * ":argadd"
2287 void
2288 ex_argadd(eap)
2289 exarg_T *eap;
2291 do_arglist(eap->arg, AL_ADD,
2292 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2293 #ifdef FEAT_TITLE
2294 maketitle();
2295 #endif
2299 * ":argdelete"
2301 void
2302 ex_argdelete(eap)
2303 exarg_T *eap;
2305 int i;
2306 int n;
2308 if (eap->addr_count > 0)
2310 /* ":1,4argdel": Delete all arguments in the range. */
2311 if (eap->line2 > ARGCOUNT)
2312 eap->line2 = ARGCOUNT;
2313 n = eap->line2 - eap->line1 + 1;
2314 if (*eap->arg != NUL || n <= 0)
2315 EMSG(_(e_invarg));
2316 else
2318 for (i = eap->line1; i <= eap->line2; ++i)
2319 vim_free(ARGLIST[i - 1].ae_fname);
2320 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2321 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2322 ALIST(curwin)->al_ga.ga_len -= n;
2323 if (curwin->w_arg_idx >= eap->line2)
2324 curwin->w_arg_idx -= n;
2325 else if (curwin->w_arg_idx > eap->line1)
2326 curwin->w_arg_idx = eap->line1;
2329 else if (*eap->arg == NUL)
2330 EMSG(_(e_argreq));
2331 else
2332 do_arglist(eap->arg, AL_DEL, 0);
2333 #ifdef FEAT_TITLE
2334 maketitle();
2335 #endif
2339 * ":argdo", ":windo", ":bufdo", ":tabdo"
2341 void
2342 ex_listdo(eap)
2343 exarg_T *eap;
2345 int i;
2346 #ifdef FEAT_WINDOWS
2347 win_T *wp;
2348 tabpage_T *tp;
2349 #endif
2350 buf_T *buf;
2351 int next_fnum = 0;
2352 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2353 char_u *save_ei = NULL;
2354 #endif
2355 char_u *p_shm_save;
2357 #ifndef FEAT_WINDOWS
2358 if (eap->cmdidx == CMD_windo)
2360 ex_ni(eap);
2361 return;
2363 #endif
2365 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2366 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
2367 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2368 * great speed improvement. */
2369 save_ei = au_event_disable(",Syntax");
2370 #endif
2372 if (eap->cmdidx == CMD_windo
2373 || eap->cmdidx == CMD_tabdo
2374 || P_HID(curbuf)
2375 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
2377 /* start at the first argument/window/buffer */
2378 i = 0;
2379 #ifdef FEAT_WINDOWS
2380 wp = firstwin;
2381 tp = first_tabpage;
2382 #endif
2383 /* set pcmark now */
2384 if (eap->cmdidx == CMD_bufdo)
2385 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2386 else
2387 setpcmark();
2388 listcmd_busy = TRUE; /* avoids setting pcmark below */
2390 while (!got_int)
2392 if (eap->cmdidx == CMD_argdo)
2394 /* go to argument "i" */
2395 if (i == ARGCOUNT)
2396 break;
2397 /* Don't call do_argfile() when already there, it will try
2398 * reloading the file. */
2399 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
2401 /* Clear 'shm' to avoid that the file message overwrites
2402 * any output from the command. */
2403 p_shm_save = vim_strsave(p_shm);
2404 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
2405 do_argfile(eap, i);
2406 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2407 vim_free(p_shm_save);
2409 if (curwin->w_arg_idx != i)
2410 break;
2411 ++i;
2413 #ifdef FEAT_WINDOWS
2414 else if (eap->cmdidx == CMD_windo)
2416 /* go to window "wp" */
2417 if (!win_valid(wp))
2418 break;
2419 win_goto(wp);
2420 if (curwin != wp)
2421 break; /* something must be wrong */
2422 wp = curwin->w_next;
2424 else if (eap->cmdidx == CMD_tabdo)
2426 /* go to window "tp" */
2427 if (!valid_tabpage(tp))
2428 break;
2429 goto_tabpage_tp(tp);
2430 tp = tp->tp_next;
2432 #endif
2433 else if (eap->cmdidx == CMD_bufdo)
2435 /* Remember the number of the next listed buffer, in case
2436 * ":bwipe" is used or autocommands do something strange. */
2437 next_fnum = -1;
2438 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2439 if (buf->b_p_bl)
2441 next_fnum = buf->b_fnum;
2442 break;
2446 /* execute the command */
2447 do_cmdline(eap->arg, eap->getline, eap->cookie,
2448 DOCMD_VERBOSE + DOCMD_NOWAIT);
2450 if (eap->cmdidx == CMD_bufdo)
2452 /* Done? */
2453 if (next_fnum < 0)
2454 break;
2455 /* Check if the buffer still exists. */
2456 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2457 if (buf->b_fnum == next_fnum)
2458 break;
2459 if (buf == NULL)
2460 break;
2462 /* Go to the next buffer. Clear 'shm' to avoid that the file
2463 * message overwrites any output from the command. */
2464 p_shm_save = vim_strsave(p_shm);
2465 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
2466 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
2467 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2468 vim_free(p_shm_save);
2470 /* If autocommands took us elsewhere, quit here */
2471 if (curbuf->b_fnum != next_fnum)
2472 break;
2475 if (eap->cmdidx == CMD_windo)
2477 validate_cursor(); /* cursor may have moved */
2478 #ifdef FEAT_SCROLLBIND
2479 /* required when 'scrollbind' has been set */
2480 if (curwin->w_p_scb)
2481 do_check_scrollbind(TRUE);
2482 #endif
2485 listcmd_busy = FALSE;
2488 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2489 if (save_ei != NULL)
2491 au_event_restore(save_ei);
2492 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2493 curbuf->b_fname, TRUE, curbuf);
2495 #endif
2499 * Add files[count] to the arglist of the current window after arg "after".
2500 * The file names in files[count] must have been allocated and are taken over.
2501 * Files[] itself is not taken over.
2502 * Returns index of first added argument. Returns -1 when failed (out of mem).
2504 static int
2505 alist_add_list(count, files, after)
2506 int count;
2507 char_u **files;
2508 int after; /* where to add: 0 = before first one */
2510 int i;
2512 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2514 if (after < 0)
2515 after = 0;
2516 if (after > ARGCOUNT)
2517 after = ARGCOUNT;
2518 if (after < ARGCOUNT)
2519 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2520 (ARGCOUNT - after) * sizeof(aentry_T));
2521 for (i = 0; i < count; ++i)
2523 ARGLIST[after + i].ae_fname = files[i];
2524 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2526 ALIST(curwin)->al_ga.ga_len += count;
2527 if (curwin->w_arg_idx >= after)
2528 ++curwin->w_arg_idx;
2529 return after;
2532 for (i = 0; i < count; ++i)
2533 vim_free(files[i]);
2534 return -1;
2537 #endif /* FEAT_LISTCMDS */
2539 #ifdef FEAT_EVAL
2541 * ":compiler[!] {name}"
2543 void
2544 ex_compiler(eap)
2545 exarg_T *eap;
2547 char_u *buf;
2548 char_u *old_cur_comp = NULL;
2549 char_u *p;
2551 if (*eap->arg == NUL)
2553 /* List all compiler scripts. */
2554 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2555 /* ) keep the indenter happy... */
2557 else
2559 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2560 if (buf != NULL)
2562 if (eap->forceit)
2564 /* ":compiler! {name}" sets global options */
2565 do_cmdline_cmd((char_u *)
2566 "command -nargs=* CompilerSet set <args>");
2568 else
2570 /* ":compiler! {name}" sets local options.
2571 * To remain backwards compatible "current_compiler" is always
2572 * used. A user's compiler plugin may set it, the distributed
2573 * plugin will then skip the settings. Afterwards set
2574 * "b:current_compiler" and restore "current_compiler". */
2575 old_cur_comp = get_var_value((char_u *)"current_compiler");
2576 if (old_cur_comp != NULL)
2577 old_cur_comp = vim_strsave(old_cur_comp);
2578 do_cmdline_cmd((char_u *)
2579 "command -nargs=* CompilerSet setlocal <args>");
2581 do_unlet((char_u *)"current_compiler", TRUE);
2582 do_unlet((char_u *)"b:current_compiler", TRUE);
2584 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
2585 if (source_runtime(buf, TRUE) == FAIL)
2586 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2587 vim_free(buf);
2589 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2591 /* Set "b:current_compiler" from "current_compiler". */
2592 p = get_var_value((char_u *)"current_compiler");
2593 if (p != NULL)
2594 set_internal_string_var((char_u *)"b:current_compiler", p);
2596 /* Restore "current_compiler" for ":compiler {name}". */
2597 if (!eap->forceit)
2599 if (old_cur_comp != NULL)
2601 set_internal_string_var((char_u *)"current_compiler",
2602 old_cur_comp);
2603 vim_free(old_cur_comp);
2605 else
2606 do_unlet((char_u *)"current_compiler", TRUE);
2611 #endif
2614 * ":runtime {name}"
2616 void
2617 ex_runtime(eap)
2618 exarg_T *eap;
2620 source_runtime(eap->arg, eap->forceit);
2623 static void source_callback __ARGS((char_u *fname, void *cookie));
2625 /*ARGSUSED*/
2626 static void
2627 source_callback(fname, cookie)
2628 char_u *fname;
2629 void *cookie;
2631 (void)do_source(fname, FALSE, DOSO_NONE);
2635 * Source the file "name" from all directories in 'runtimepath'.
2636 * "name" can contain wildcards.
2637 * When "all" is TRUE, source all files, otherwise only the first one.
2638 * return FAIL when no file could be sourced, OK otherwise.
2641 source_runtime(name, all)
2642 char_u *name;
2643 int all;
2645 return do_in_runtimepath(name, all, source_callback, NULL);
2649 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2650 * it: callback(fname, "cookie")
2651 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2652 * used.
2653 * Returns OK when at least one match found, FAIL otherwise.
2656 do_in_runtimepath(name, all, callback, cookie)
2657 char_u *name;
2658 int all;
2659 void (*callback)__ARGS((char_u *fname, void *ck));
2660 void *cookie;
2662 char_u *rtp;
2663 char_u *np;
2664 char_u *buf;
2665 char_u *rtp_copy;
2666 char_u *tail;
2667 int num_files;
2668 char_u **files;
2669 int i;
2670 int did_one = FALSE;
2671 #ifdef AMIGA
2672 struct Process *proc = (struct Process *)FindTask(0L);
2673 APTR save_winptr = proc->pr_WindowPtr;
2675 /* Avoid a requester here for a volume that doesn't exist. */
2676 proc->pr_WindowPtr = (APTR)-1L;
2677 #endif
2679 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2680 * value. */
2681 rtp_copy = vim_strsave(p_rtp);
2682 buf = alloc(MAXPATHL);
2683 if (buf != NULL && rtp_copy != NULL)
2685 if (p_verbose > 1)
2687 verbose_enter();
2688 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
2689 (char *)name, (char *)p_rtp);
2690 verbose_leave();
2693 /* Loop over all entries in 'runtimepath'. */
2694 rtp = rtp_copy;
2695 while (*rtp != NUL && (all || !did_one))
2697 /* Copy the path from 'runtimepath' to buf[]. */
2698 copy_option_part(&rtp, buf, MAXPATHL, ",");
2699 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
2701 add_pathsep(buf);
2702 tail = buf + STRLEN(buf);
2704 /* Loop over all patterns in "name" */
2705 np = name;
2706 while (*np != NUL && (all || !did_one))
2708 /* Append the pattern from "name" to buf[]. */
2709 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2710 "\t ");
2712 if (p_verbose > 2)
2714 verbose_enter();
2715 smsg((char_u *)_("Searching for \"%s\""), buf);
2716 verbose_leave();
2719 /* Expand wildcards, invoke the callback for each match. */
2720 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2721 EW_FILE) == OK)
2723 for (i = 0; i < num_files; ++i)
2725 (*callback)(files[i], cookie);
2726 did_one = TRUE;
2727 if (!all)
2728 break;
2730 FreeWild(num_files, files);
2736 vim_free(buf);
2737 vim_free(rtp_copy);
2738 if (p_verbose > 0 && !did_one)
2740 verbose_enter();
2741 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
2742 verbose_leave();
2745 #ifdef AMIGA
2746 proc->pr_WindowPtr = save_winptr;
2747 #endif
2749 return did_one ? OK : FAIL;
2752 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2754 * ":options"
2756 /*ARGSUSED*/
2757 void
2758 ex_options(eap)
2759 exarg_T *eap;
2761 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2763 #endif
2766 * ":source {fname}"
2768 void
2769 ex_source(eap)
2770 exarg_T *eap;
2772 #ifdef FEAT_BROWSE
2773 if (cmdmod.browse)
2775 char_u *fname = NULL;
2777 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
2778 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2779 if (fname != NULL)
2781 cmd_source(fname, eap);
2782 vim_free(fname);
2785 else
2786 #endif
2787 cmd_source(eap->arg, eap);
2790 static void
2791 cmd_source(fname, eap)
2792 char_u *fname;
2793 exarg_T *eap;
2795 if (*fname == NUL)
2796 EMSG(_(e_argreq));
2798 else if (eap != NULL && eap->forceit)
2799 /* ":source!": read Normal mdoe commands
2800 * Need to execute the commands directly. This is required at least
2801 * for:
2802 * - ":g" command busy
2803 * - after ":argdo", ":windo" or ":bufdo"
2804 * - another command follows
2805 * - inside a loop
2807 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2808 #ifdef FEAT_EVAL
2809 || eap->cstack->cs_idx >= 0
2810 #endif
2813 /* ":source" read ex commands */
2814 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
2815 EMSG2(_(e_notopen), fname);
2819 * ":source" and associated commands.
2822 * Structure used to store info for each sourced file.
2823 * It is shared between do_source() and getsourceline().
2824 * This is required, because it needs to be handed to do_cmdline() and
2825 * sourcing can be done recursively.
2827 struct source_cookie
2829 FILE *fp; /* opened file for sourcing */
2830 char_u *nextline; /* if not NULL: line that was read ahead */
2831 int finished; /* ":finish" used */
2832 #if defined (USE_CRNL) || defined (USE_CR)
2833 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2834 int error; /* TRUE if LF found after CR-LF */
2835 #endif
2836 #ifdef FEAT_EVAL
2837 linenr_T breakpoint; /* next line with breakpoint or zero */
2838 char_u *fname; /* name of sourced file */
2839 int dbg_tick; /* debug_tick when breakpoint was set */
2840 int level; /* top nesting level of sourced file */
2841 #endif
2842 #ifdef FEAT_MBYTE
2843 vimconv_T conv; /* type of conversion */
2844 #endif
2847 #ifdef FEAT_EVAL
2849 * Return the address holding the next breakpoint line for a source cookie.
2851 linenr_T *
2852 source_breakpoint(cookie)
2853 void *cookie;
2855 return &((struct source_cookie *)cookie)->breakpoint;
2859 * Return the address holding the debug tick for a source cookie.
2861 int *
2862 source_dbg_tick(cookie)
2863 void *cookie;
2865 return &((struct source_cookie *)cookie)->dbg_tick;
2869 * Return the nesting level for a source cookie.
2872 source_level(cookie)
2873 void *cookie;
2875 return ((struct source_cookie *)cookie)->level;
2877 #endif
2879 static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2881 #if defined(WIN32) && defined(FEAT_CSCOPE)
2882 static FILE *fopen_noinh_readbin __ARGS((char *filename));
2885 * Special function to open a file without handle inheritance.
2887 static FILE *
2888 fopen_noinh_readbin(filename)
2889 char *filename;
2891 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2893 if (fd_tmp == -1)
2894 return NULL;
2895 return fdopen(fd_tmp, READBIN);
2897 #endif
2901 * do_source: Read the file "fname" and execute its lines as EX commands.
2903 * This function may be called recursively!
2905 * return FAIL if file could not be opened, OK otherwise
2908 do_source(fname, check_other, is_vimrc)
2909 char_u *fname;
2910 int check_other; /* check for .vimrc and _vimrc */
2911 int is_vimrc; /* DOSO_ value */
2913 struct source_cookie cookie;
2914 char_u *save_sourcing_name;
2915 linenr_T save_sourcing_lnum;
2916 char_u *p;
2917 char_u *fname_exp;
2918 int retval = FAIL;
2919 #ifdef FEAT_EVAL
2920 scid_T save_current_SID;
2921 static scid_T last_current_SID = 0;
2922 void *save_funccalp;
2923 int save_debug_break_level = debug_break_level;
2924 scriptitem_T *si = NULL;
2925 # ifdef UNIX
2926 struct stat st;
2927 int stat_ok;
2928 # endif
2929 #endif
2930 #ifdef STARTUPTIME
2931 struct timeval tv_rel;
2932 struct timeval tv_start;
2933 #endif
2934 #ifdef FEAT_PROFILE
2935 proftime_T wait_start;
2936 #endif
2938 #ifdef RISCOS
2939 p = mch_munge_fname(fname);
2940 #else
2941 p = expand_env_save(fname);
2942 #endif
2943 if (p == NULL)
2944 return retval;
2945 fname_exp = fix_fname(p);
2946 vim_free(p);
2947 if (fname_exp == NULL)
2948 return retval;
2949 if (mch_isdir(fname_exp))
2951 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
2952 goto theend;
2955 #ifdef FEAT_AUTOCMD
2956 /* Apply SourceCmd autocommands, they should get the file and source it. */
2957 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2958 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2959 FALSE, curbuf))
2961 # ifdef FEAT_EVAL
2962 retval = aborting() ? FAIL : OK;
2963 # else
2964 retval = OK;
2965 # endif
2966 goto theend;
2969 /* Apply SourcePre autocommands, they may get the file. */
2970 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
2971 #endif
2973 #if defined(WIN32) && defined(FEAT_CSCOPE)
2974 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2975 #else
2976 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2977 #endif
2978 if (cookie.fp == NULL && check_other)
2981 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2982 * and ".exrc" by "_exrc" or vice versa.
2984 p = gettail(fname_exp);
2985 if ((*p == '.' || *p == '_')
2986 && (STRICMP(p + 1, "vimrc") == 0
2987 || STRICMP(p + 1, "gvimrc") == 0
2988 || STRICMP(p + 1, "exrc") == 0))
2990 if (*p == '_')
2991 *p = '.';
2992 else
2993 *p = '_';
2994 #if defined(WIN32) && defined(FEAT_CSCOPE)
2995 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2996 #else
2997 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2998 #endif
3002 if (cookie.fp == NULL)
3004 if (p_verbose > 0)
3006 verbose_enter();
3007 if (sourcing_name == NULL)
3008 smsg((char_u *)_("could not source \"%s\""), fname);
3009 else
3010 smsg((char_u *)_("line %ld: could not source \"%s\""),
3011 sourcing_lnum, fname);
3012 verbose_leave();
3014 goto theend;
3018 * The file exists.
3019 * - In verbose mode, give a message.
3020 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3022 if (p_verbose > 1)
3024 verbose_enter();
3025 if (sourcing_name == NULL)
3026 smsg((char_u *)_("sourcing \"%s\""), fname);
3027 else
3028 smsg((char_u *)_("line %ld: sourcing \"%s\""),
3029 sourcing_lnum, fname);
3030 verbose_leave();
3032 if (is_vimrc == DOSO_VIMRC)
3033 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3034 else if (is_vimrc == DOSO_GVIMRC)
3035 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
3037 #ifdef USE_CRNL
3038 /* If no automatic file format: Set default to CR-NL. */
3039 if (*p_ffs == NUL)
3040 cookie.fileformat = EOL_DOS;
3041 else
3042 cookie.fileformat = EOL_UNKNOWN;
3043 cookie.error = FALSE;
3044 #endif
3046 #ifdef USE_CR
3047 /* If no automatic file format: Set default to CR. */
3048 if (*p_ffs == NUL)
3049 cookie.fileformat = EOL_MAC;
3050 else
3051 cookie.fileformat = EOL_UNKNOWN;
3052 cookie.error = FALSE;
3053 #endif
3055 cookie.nextline = NULL;
3056 cookie.finished = FALSE;
3058 #ifdef FEAT_EVAL
3060 * Check if this script has a breakpoint.
3062 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3063 cookie.fname = fname_exp;
3064 cookie.dbg_tick = debug_tick;
3066 cookie.level = ex_nesting_level;
3067 #endif
3068 #ifdef FEAT_MBYTE
3069 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3071 /* Try reading the first few bytes to check for a UTF-8 BOM. */
3073 char_u buf[3];
3075 if (fread((char *)buf, sizeof(char_u), (size_t)3, cookie.fp)
3076 == (size_t)3
3077 && buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf)
3078 /* Found BOM, setup conversion and skip over it. */
3079 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3080 else
3081 /* No BOM found, rewind. */
3082 fseek(cookie.fp, 0L, SEEK_SET);
3084 #endif
3087 * Keep the sourcing name/lnum, for recursive calls.
3089 save_sourcing_name = sourcing_name;
3090 sourcing_name = fname_exp;
3091 save_sourcing_lnum = sourcing_lnum;
3092 sourcing_lnum = 0;
3094 #ifdef STARTUPTIME
3095 time_push(&tv_rel, &tv_start);
3096 #endif
3098 #ifdef FEAT_EVAL
3099 # ifdef FEAT_PROFILE
3100 if (do_profiling == PROF_YES)
3101 prof_child_enter(&wait_start); /* entering a child now */
3102 # endif
3104 /* Don't use local function variables, if called from a function.
3105 * Also starts profiling timer for nested script. */
3106 save_funccalp = save_funccal();
3109 * Check if this script was sourced before to finds its SID.
3110 * If it's new, generate a new SID.
3112 save_current_SID = current_SID;
3113 # ifdef UNIX
3114 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3115 # endif
3116 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3118 si = &SCRIPT_ITEM(current_SID);
3119 if (si->sn_name != NULL
3120 && (
3121 # ifdef UNIX
3122 /* Compare dev/ino when possible, it catches symbolic
3123 * links. Also compare file names, the inode may change
3124 * when the file was edited. */
3125 ((stat_ok && si->sn_dev != -1)
3126 && (si->sn_dev == st.st_dev
3127 && si->sn_ino == st.st_ino)) ||
3128 # endif
3129 fnamecmp(si->sn_name, fname_exp) == 0))
3130 break;
3132 if (current_SID == 0)
3134 current_SID = ++last_current_SID;
3135 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3136 == FAIL)
3137 goto almosttheend;
3138 while (script_items.ga_len < current_SID)
3140 ++script_items.ga_len;
3141 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3142 # ifdef FEAT_PROFILE
3143 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
3144 # endif
3146 si = &SCRIPT_ITEM(current_SID);
3147 si->sn_name = fname_exp;
3148 fname_exp = NULL;
3149 # ifdef UNIX
3150 if (stat_ok)
3152 si->sn_dev = st.st_dev;
3153 si->sn_ino = st.st_ino;
3155 else
3156 si->sn_dev = -1;
3157 # endif
3159 /* Allocate the local script variables to use for this script. */
3160 new_script_vars(current_SID);
3163 # ifdef FEAT_PROFILE
3164 if (do_profiling == PROF_YES)
3166 int forceit;
3168 /* Check if we do profiling for this script. */
3169 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3171 script_do_profile(si);
3172 si->sn_pr_force = forceit;
3174 if (si->sn_prof_on)
3176 ++si->sn_pr_count;
3177 profile_start(&si->sn_pr_start);
3178 profile_zero(&si->sn_pr_children);
3181 # endif
3182 #endif
3185 * Call do_cmdline, which will call getsourceline() to get the lines.
3187 do_cmdline(NULL, getsourceline, (void *)&cookie,
3188 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
3190 retval = OK;
3192 #ifdef FEAT_PROFILE
3193 if (do_profiling == PROF_YES)
3195 /* Get "si" again, "script_items" may have been reallocated. */
3196 si = &SCRIPT_ITEM(current_SID);
3197 if (si->sn_prof_on)
3199 profile_end(&si->sn_pr_start);
3200 profile_sub_wait(&wait_start, &si->sn_pr_start);
3201 profile_add(&si->sn_pr_total, &si->sn_pr_start);
3202 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3203 &si->sn_pr_children);
3206 #endif
3208 if (got_int)
3209 EMSG(_(e_interr));
3210 sourcing_name = save_sourcing_name;
3211 sourcing_lnum = save_sourcing_lnum;
3212 if (p_verbose > 1)
3214 verbose_enter();
3215 smsg((char_u *)_("finished sourcing %s"), fname);
3216 if (sourcing_name != NULL)
3217 smsg((char_u *)_("continuing in %s"), sourcing_name);
3218 verbose_leave();
3220 #ifdef STARTUPTIME
3221 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3222 time_msg((char *)IObuff, &tv_start);
3223 time_pop(&tv_rel);
3224 #endif
3226 #ifdef FEAT_EVAL
3228 * After a "finish" in debug mode, need to break at first command of next
3229 * sourced file.
3231 if (save_debug_break_level > ex_nesting_level
3232 && debug_break_level == ex_nesting_level)
3233 ++debug_break_level;
3234 #endif
3236 #ifdef FEAT_EVAL
3237 almosttheend:
3238 current_SID = save_current_SID;
3239 restore_funccal(save_funccalp);
3240 # ifdef FEAT_PROFILE
3241 if (do_profiling == PROF_YES)
3242 prof_child_exit(&wait_start); /* leaving a child now */
3243 # endif
3244 #endif
3245 fclose(cookie.fp);
3246 vim_free(cookie.nextline);
3247 #ifdef FEAT_MBYTE
3248 convert_setup(&cookie.conv, NULL, NULL);
3249 #endif
3251 theend:
3252 vim_free(fname_exp);
3253 return retval;
3256 #if defined(FEAT_EVAL) || defined(PROTO)
3259 * ":scriptnames"
3261 /*ARGSUSED*/
3262 void
3263 ex_scriptnames(eap)
3264 exarg_T *eap;
3266 int i;
3268 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3269 if (SCRIPT_ITEM(i).sn_name != NULL)
3270 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
3273 # if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3275 * Fix slashes in the list of script names for 'shellslash'.
3277 void
3278 scriptnames_slash_adjust()
3280 int i;
3282 for (i = 1; i <= script_items.ga_len; ++i)
3283 if (SCRIPT_ITEM(i).sn_name != NULL)
3284 slash_adjust(SCRIPT_ITEM(i).sn_name);
3286 # endif
3289 * Get a pointer to a script name. Used for ":verbose set".
3291 char_u *
3292 get_scriptname(id)
3293 scid_T id;
3295 if (id == SID_MODELINE)
3296 return (char_u *)_("modeline");
3297 if (id == SID_CMDARG)
3298 return (char_u *)_("--cmd argument");
3299 if (id == SID_CARG)
3300 return (char_u *)_("-c argument");
3301 if (id == SID_ENV)
3302 return (char_u *)_("environment variable");
3303 if (id == SID_ERROR)
3304 return (char_u *)_("error handler");
3305 return SCRIPT_ITEM(id).sn_name;
3308 # if defined(EXITFREE) || defined(PROTO)
3309 void
3310 free_scriptnames()
3312 int i;
3314 for (i = script_items.ga_len; i > 0; --i)
3315 vim_free(SCRIPT_ITEM(i).sn_name);
3316 ga_clear(&script_items);
3318 # endif
3320 #endif
3322 #if defined(USE_CR) || defined(PROTO)
3324 # if defined(__MSL__) && (__MSL__ >= 22)
3326 * Newer version of the Metrowerks library handle DOS and UNIX files
3327 * without help.
3328 * Test with earlier versions, MSL 2.2 is the library supplied with
3329 * Codewarrior Pro 2.
3331 char *
3332 fgets_cr(s, n, stream)
3333 char *s;
3334 int n;
3335 FILE *stream;
3337 return fgets(s, n, stream);
3339 # else
3341 * Version of fgets() which also works for lines ending in a <CR> only
3342 * (Macintosh format).
3343 * For older versions of the Metrowerks library.
3344 * At least CodeWarrior 9 needed this code.
3346 char *
3347 fgets_cr(s, n, stream)
3348 char *s;
3349 int n;
3350 FILE *stream;
3352 int c = 0;
3353 int char_read = 0;
3355 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3357 c = fgetc(stream);
3358 s[char_read++] = c;
3359 /* If the file is in DOS format, we need to skip a NL after a CR. I
3360 * thought it was the other way around, but this appears to work... */
3361 if (c == '\n')
3363 c = fgetc(stream);
3364 if (c != '\r')
3365 ungetc(c, stream);
3369 s[char_read] = 0;
3370 if (char_read == 0)
3371 return NULL;
3373 if (feof(stream) && char_read == 1)
3374 return NULL;
3376 return s;
3378 # endif
3379 #endif
3382 * Get one full line from a sourced file.
3383 * Called by do_cmdline() when it's called from do_source().
3385 * Return a pointer to the line in allocated memory.
3386 * Return NULL for end-of-file or some error.
3388 /* ARGSUSED */
3389 char_u *
3390 getsourceline(c, cookie, indent)
3391 int c; /* not used */
3392 void *cookie;
3393 int indent; /* not used */
3395 struct source_cookie *sp = (struct source_cookie *)cookie;
3396 char_u *line;
3397 char_u *p, *s;
3399 #ifdef FEAT_EVAL
3400 /* If breakpoints have been added/deleted need to check for it. */
3401 if (sp->dbg_tick < debug_tick)
3403 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3404 sp->dbg_tick = debug_tick;
3406 # ifdef FEAT_PROFILE
3407 if (do_profiling == PROF_YES)
3408 script_line_end();
3409 # endif
3410 #endif
3412 * Get current line. If there is a read-ahead line, use it, otherwise get
3413 * one now.
3415 if (sp->finished)
3416 line = NULL;
3417 else if (sp->nextline == NULL)
3418 line = get_one_sourceline(sp);
3419 else
3421 line = sp->nextline;
3422 sp->nextline = NULL;
3423 ++sourcing_lnum;
3425 #ifdef FEAT_PROFILE
3426 if (line != NULL && do_profiling == PROF_YES)
3427 script_line_start();
3428 #endif
3430 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3431 * contain the 'C' flag. */
3432 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3434 /* compensate for the one line read-ahead */
3435 --sourcing_lnum;
3436 for (;;)
3438 sp->nextline = get_one_sourceline(sp);
3439 if (sp->nextline == NULL)
3440 break;
3441 p = skipwhite(sp->nextline);
3442 if (*p != '\\')
3443 break;
3444 s = alloc((int)(STRLEN(line) + STRLEN(p)));
3445 if (s == NULL) /* out of memory */
3446 break;
3447 STRCPY(s, line);
3448 STRCAT(s, p + 1);
3449 vim_free(line);
3450 line = s;
3451 vim_free(sp->nextline);
3455 #ifdef FEAT_MBYTE
3456 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3458 /* Convert the encoding of the script line. */
3459 s = string_convert(&sp->conv, line, NULL);
3460 if (s != NULL)
3462 vim_free(line);
3463 line = s;
3466 #endif
3468 #ifdef FEAT_EVAL
3469 /* Did we encounter a breakpoint? */
3470 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3472 dbg_breakpoint(sp->fname, sourcing_lnum);
3473 /* Find next breakpoint. */
3474 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3475 sp->dbg_tick = debug_tick;
3477 #endif
3479 return line;
3482 static char_u *
3483 get_one_sourceline(sp)
3484 struct source_cookie *sp;
3486 garray_T ga;
3487 int len;
3488 int c;
3489 char_u *buf;
3490 #ifdef USE_CRNL
3491 int has_cr; /* CR-LF found */
3492 #endif
3493 #ifdef USE_CR
3494 char_u *scan;
3495 #endif
3496 int have_read = FALSE;
3498 /* use a growarray to store the sourced line */
3499 ga_init2(&ga, 1, 250);
3502 * Loop until there is a finished line (or end-of-file).
3504 sourcing_lnum++;
3505 for (;;)
3507 /* make room to read at least 120 (more) characters */
3508 if (ga_grow(&ga, 120) == FAIL)
3509 break;
3510 buf = (char_u *)ga.ga_data;
3512 #ifdef USE_CR
3513 if (sp->fileformat == EOL_MAC)
3515 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3516 sp->fp) == NULL)
3517 break;
3519 else
3520 #endif
3521 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3522 sp->fp) == NULL)
3523 break;
3524 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
3525 #ifdef USE_CRNL
3526 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3527 * CTRL-Z by its own, or after a NL. */
3528 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3529 && sp->fileformat == EOL_DOS
3530 && buf[len - 1] == Ctrl_Z)
3532 buf[len - 1] = NUL;
3533 break;
3535 #endif
3537 #ifdef USE_CR
3538 /* If the read doesn't stop on a new line, and there's
3539 * some CR then we assume a Mac format */
3540 if (sp->fileformat == EOL_UNKNOWN)
3542 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3543 sp->fileformat = EOL_MAC;
3544 else
3545 sp->fileformat = EOL_UNIX;
3548 if (sp->fileformat == EOL_MAC)
3550 scan = vim_strchr(buf, '\r');
3552 if (scan != NULL)
3554 *scan = '\n';
3555 if (*(scan + 1) != 0)
3557 *(scan + 1) = 0;
3558 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3561 len = STRLEN(buf);
3563 #endif
3565 have_read = TRUE;
3566 ga.ga_len = len;
3568 /* If the line was longer than the buffer, read more. */
3569 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
3570 continue;
3572 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3574 #ifdef USE_CRNL
3575 has_cr = (len >= 2 && buf[len - 2] == '\r');
3576 if (sp->fileformat == EOL_UNKNOWN)
3578 if (has_cr)
3579 sp->fileformat = EOL_DOS;
3580 else
3581 sp->fileformat = EOL_UNIX;
3584 if (sp->fileformat == EOL_DOS)
3586 if (has_cr) /* replace trailing CR */
3588 buf[len - 2] = '\n';
3589 --len;
3590 --ga.ga_len;
3592 else /* lines like ":map xx yy^M" will have failed */
3594 if (!sp->error)
3596 msg_source(hl_attr(HLF_W));
3597 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
3599 sp->error = TRUE;
3600 sp->fileformat = EOL_UNIX;
3603 #endif
3604 /* The '\n' is escaped if there is an odd number of ^V's just
3605 * before it, first set "c" just before the 'V's and then check
3606 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3607 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3609 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3611 sourcing_lnum++;
3612 continue;
3615 buf[len - 1] = NUL; /* remove the NL */
3619 * Check for ^C here now and then, so recursive :so can be broken.
3621 line_breakcheck();
3622 break;
3625 if (have_read)
3626 return (char_u *)ga.ga_data;
3628 vim_free(ga.ga_data);
3629 return NULL;
3632 #if defined(FEAT_PROFILE) || defined(PROTO)
3634 * Called when starting to read a script line.
3635 * "sourcing_lnum" must be correct!
3636 * When skipping lines it may not actually be executed, but we won't find out
3637 * until later and we need to store the time now.
3639 void
3640 script_line_start()
3642 scriptitem_T *si;
3643 sn_prl_T *pp;
3645 if (current_SID <= 0 || current_SID > script_items.ga_len)
3646 return;
3647 si = &SCRIPT_ITEM(current_SID);
3648 if (si->sn_prof_on && sourcing_lnum >= 1)
3650 /* Grow the array before starting the timer, so that the time spent
3651 * here isn't counted. */
3652 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3653 si->sn_prl_idx = sourcing_lnum - 1;
3654 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3655 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3657 /* Zero counters for a line that was not used before. */
3658 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3659 pp->snp_count = 0;
3660 profile_zero(&pp->sn_prl_total);
3661 profile_zero(&pp->sn_prl_self);
3662 ++si->sn_prl_ga.ga_len;
3664 si->sn_prl_execed = FALSE;
3665 profile_start(&si->sn_prl_start);
3666 profile_zero(&si->sn_prl_children);
3667 profile_get_wait(&si->sn_prl_wait);
3672 * Called when actually executing a function line.
3674 void
3675 script_line_exec()
3677 scriptitem_T *si;
3679 if (current_SID <= 0 || current_SID > script_items.ga_len)
3680 return;
3681 si = &SCRIPT_ITEM(current_SID);
3682 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3683 si->sn_prl_execed = TRUE;
3687 * Called when done with a function line.
3689 void
3690 script_line_end()
3692 scriptitem_T *si;
3693 sn_prl_T *pp;
3695 if (current_SID <= 0 || current_SID > script_items.ga_len)
3696 return;
3697 si = &SCRIPT_ITEM(current_SID);
3698 if (si->sn_prof_on && si->sn_prl_idx >= 0
3699 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3701 if (si->sn_prl_execed)
3703 pp = &PRL_ITEM(si, si->sn_prl_idx);
3704 ++pp->snp_count;
3705 profile_end(&si->sn_prl_start);
3706 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
3707 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
3708 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3709 &si->sn_prl_children);
3711 si->sn_prl_idx = -1;
3714 #endif
3717 * ":scriptencoding": Set encoding conversion for a sourced script.
3718 * Without the multi-byte feature it's simply ignored.
3720 /*ARGSUSED*/
3721 void
3722 ex_scriptencoding(eap)
3723 exarg_T *eap;
3725 #ifdef FEAT_MBYTE
3726 struct source_cookie *sp;
3727 char_u *name;
3729 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3731 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3732 return;
3735 if (*eap->arg != NUL)
3737 name = enc_canonize(eap->arg);
3738 if (name == NULL) /* out of memory */
3739 return;
3741 else
3742 name = eap->arg;
3744 /* Setup for conversion from the specified encoding to 'encoding'. */
3745 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3746 convert_setup(&sp->conv, name, p_enc);
3748 if (name != eap->arg)
3749 vim_free(name);
3750 #endif
3753 #if defined(FEAT_EVAL) || defined(PROTO)
3755 * ":finish": Mark a sourced file as finished.
3757 void
3758 ex_finish(eap)
3759 exarg_T *eap;
3761 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3762 do_finish(eap, FALSE);
3763 else
3764 EMSG(_("E168: :finish used outside of a sourced file"));
3768 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3769 * Also called for a pending finish at the ":endtry" or after returning from
3770 * an extra do_cmdline(). "reanimate" is used in the latter case.
3772 void
3773 do_finish(eap, reanimate)
3774 exarg_T *eap;
3775 int reanimate;
3777 int idx;
3779 if (reanimate)
3780 ((struct source_cookie *)getline_cookie(eap->getline,
3781 eap->cookie))->finished = FALSE;
3784 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3785 * not in its finally clause (which then is to be executed next) is found.
3786 * In this case, make the ":finish" pending for execution at the ":endtry".
3787 * Otherwise, finish normally.
3789 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3790 if (idx >= 0)
3792 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3793 report_make_pending(CSTP_FINISH, NULL);
3795 else
3796 ((struct source_cookie *)getline_cookie(eap->getline,
3797 eap->cookie))->finished = TRUE;
3802 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3803 * message for missing ":endif".
3804 * Return FALSE when not sourcing a file.
3807 source_finished(fgetline, cookie)
3808 char_u *(*fgetline) __ARGS((int, void *, int));
3809 void *cookie;
3811 return (getline_equal(fgetline, cookie, getsourceline)
3812 && ((struct source_cookie *)getline_cookie(
3813 fgetline, cookie))->finished);
3815 #endif
3817 #if defined(FEAT_LISTCMDS) || defined(PROTO)
3819 * ":checktime [buffer]"
3821 void
3822 ex_checktime(eap)
3823 exarg_T *eap;
3825 buf_T *buf;
3826 int save_no_check_timestamps = no_check_timestamps;
3828 no_check_timestamps = 0;
3829 if (eap->addr_count == 0) /* default is all buffers */
3830 check_timestamps(FALSE);
3831 else
3833 buf = buflist_findnr((int)eap->line2);
3834 if (buf != NULL) /* cannot happen? */
3835 (void)buf_check_timestamp(buf, FALSE);
3837 no_check_timestamps = save_no_check_timestamps;
3839 #endif
3841 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3842 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
3843 static char *get_locale_val __ARGS((int what));
3845 static char *
3846 get_locale_val(what)
3847 int what;
3849 char *loc;
3851 /* Obtain the locale value from the libraries. For DJGPP this is
3852 * redefined and it doesn't use the arguments. */
3853 loc = setlocale(what, NULL);
3855 # ifdef WIN32
3856 if (loc != NULL)
3858 char_u *p;
3860 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3861 * one of the values (e.g., LC_CTYPE) differs. */
3862 p = vim_strchr(loc, '=');
3863 if (p != NULL)
3865 loc = ++p;
3866 while (*p != NUL) /* remove trailing newline */
3868 if (*p < ' ' || *p == ';')
3870 *p = NUL;
3871 break;
3873 ++p;
3877 # endif
3879 return loc;
3881 #endif
3884 #ifdef WIN32
3886 * On MS-Windows locale names are strings like "German_Germany.1252", but
3887 * gettext expects "de". Try to translate one into another here for a few
3888 * supported languages.
3890 static char_u *
3891 gettext_lang(char_u *name)
3893 int i;
3894 static char *(mtable[]) = {
3895 "afrikaans", "af",
3896 "czech", "cs",
3897 "dutch", "nl",
3898 "german", "de",
3899 "english_united kingdom", "en_GB",
3900 "spanish", "es",
3901 "french", "fr",
3902 "italian", "it",
3903 "japanese", "ja",
3904 "korean", "ko",
3905 "norwegian", "no",
3906 "polish", "pl",
3907 "russian", "ru",
3908 "slovak", "sk",
3909 "swedish", "sv",
3910 "ukrainian", "uk",
3911 "chinese_china", "zh_CN",
3912 "chinese_taiwan", "zh_TW",
3913 NULL};
3915 for (i = 0; mtable[i] != NULL; i += 2)
3916 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
3917 return mtable[i + 1];
3918 return name;
3920 #endif
3922 #if defined(FEAT_MULTI_LANG) || defined(PROTO)
3924 * Obtain the current messages language. Used to set the default for
3925 * 'helplang'. May return NULL or an empty string.
3927 char_u *
3928 get_mess_lang()
3930 char_u *p;
3932 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
3933 # if defined(LC_MESSAGES)
3934 p = (char_u *)get_locale_val(LC_MESSAGES);
3935 # else
3936 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
3937 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3938 * and LC_MONETARY may be set differently for a Japanese working in the
3939 * US. */
3940 p = (char_u *)get_locale_val(LC_COLLATE);
3941 # endif
3942 # else
3943 p = mch_getenv((char_u *)"LC_ALL");
3944 if (p == NULL || *p == NUL)
3946 p = mch_getenv((char_u *)"LC_MESSAGES");
3947 if (p == NULL || *p == NUL)
3948 p = mch_getenv((char_u *)"LANG");
3950 # endif
3951 # ifdef WIN32
3952 p = gettext_lang(p);
3953 # endif
3954 return p;
3956 #endif
3958 /* Complicated #if; matches with where get_mess_env() is used below. */
3959 #if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3960 && defined(LC_MESSAGES))) \
3961 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3962 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
3963 && !defined(LC_MESSAGES))
3964 static char_u *get_mess_env __ARGS((void));
3967 * Get the language used for messages from the environment.
3969 static char_u *
3970 get_mess_env()
3972 char_u *p;
3974 p = mch_getenv((char_u *)"LC_ALL");
3975 if (p == NULL || *p == NUL)
3977 p = mch_getenv((char_u *)"LC_MESSAGES");
3978 if (p == NULL || *p == NUL)
3980 p = mch_getenv((char_u *)"LANG");
3981 if (p != NULL && VIM_ISDIGIT(*p))
3982 p = NULL; /* ignore something like "1043" */
3983 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
3984 if (p == NULL || *p == NUL)
3985 p = (char_u *)get_locale_val(LC_CTYPE);
3986 # endif
3989 return p;
3991 #endif
3993 #if defined(FEAT_EVAL) || defined(PROTO)
3996 * Set the "v:lang" variable according to the current locale setting.
3997 * Also do "v:lc_time"and "v:ctype".
3999 void
4000 set_lang_var()
4002 char_u *loc;
4004 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4005 loc = (char_u *)get_locale_val(LC_CTYPE);
4006 # else
4007 /* setlocale() not supported: use the default value */
4008 loc = (char_u *)"C";
4009 # endif
4010 set_vim_var_string(VV_CTYPE, loc, -1);
4012 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4013 * back to LC_CTYPE if it's empty. */
4014 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
4015 loc = (char_u *)get_locale_val(LC_MESSAGES);
4016 # else
4017 loc = get_mess_env();
4018 # endif
4019 set_vim_var_string(VV_LANG, loc, -1);
4021 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
4022 loc = (char_u *)get_locale_val(LC_TIME);
4023 # endif
4024 set_vim_var_string(VV_LC_TIME, loc, -1);
4026 #endif
4028 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4029 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4031 * ":language": Set the language (locale).
4033 void
4034 ex_language(eap)
4035 exarg_T *eap;
4037 char *loc;
4038 char_u *p;
4039 char_u *name;
4040 int what = LC_ALL;
4041 char *whatstr = "";
4042 #ifdef LC_MESSAGES
4043 # define VIM_LC_MESSAGES LC_MESSAGES
4044 #else
4045 # define VIM_LC_MESSAGES 6789
4046 #endif
4048 name = eap->arg;
4050 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4051 * Allow abbreviation, but require at least 3 characters to avoid
4052 * confusion with a two letter language name "me" or "ct". */
4053 p = skiptowhite(eap->arg);
4054 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4056 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4058 what = VIM_LC_MESSAGES;
4059 name = skipwhite(p);
4060 whatstr = "messages ";
4062 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4064 what = LC_CTYPE;
4065 name = skipwhite(p);
4066 whatstr = "ctype ";
4068 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4070 what = LC_TIME;
4071 name = skipwhite(p);
4072 whatstr = "time ";
4076 if (*name == NUL)
4078 #ifndef LC_MESSAGES
4079 if (what == VIM_LC_MESSAGES)
4080 p = get_mess_env();
4081 else
4082 #endif
4083 p = (char_u *)setlocale(what, NULL);
4084 if (p == NULL || *p == NUL)
4085 p = (char_u *)"Unknown";
4086 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4088 else
4090 #ifndef LC_MESSAGES
4091 if (what == VIM_LC_MESSAGES)
4092 loc = "";
4093 else
4094 #endif
4096 loc = setlocale(what, (char *)name);
4097 #if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4098 /* Make sure strtod() uses a decimal point, not a comma. */
4099 setlocale(LC_NUMERIC, "C");
4100 #endif
4102 if (loc == NULL)
4103 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4104 else
4106 #ifdef HAVE_NL_MSG_CAT_CNTR
4107 /* Need to do this for GNU gettext, otherwise cached translations
4108 * will be used again. */
4109 extern int _nl_msg_cat_cntr;
4111 ++_nl_msg_cat_cntr;
4112 #endif
4113 /* Reset $LC_ALL, otherwise it would overrule everything. */
4114 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4116 if (what != LC_TIME)
4118 /* Tell gettext() what to translate to. It apparently doesn't
4119 * use the currently effective locale. Also do this when
4120 * FEAT_GETTEXT isn't defined, so that shell commands use this
4121 * value. */
4122 if (what == LC_ALL)
4124 vim_setenv((char_u *)"LANG", name);
4125 # ifdef WIN32
4126 /* Apparently MS-Windows printf() may cause a crash when
4127 * we give it 8-bit text while it's expecting text in the
4128 * current locale. This call avoids that. */
4129 setlocale(LC_CTYPE, "C");
4130 # endif
4132 if (what != LC_CTYPE)
4134 char_u *mname;
4135 #ifdef WIN32
4136 mname = gettext_lang(name);
4137 #else
4138 mname = name;
4139 #endif
4140 vim_setenv((char_u *)"LC_MESSAGES", mname);
4141 #ifdef FEAT_MULTI_LANG
4142 set_helplang_default(mname);
4143 #endif
4146 /* Set $LC_CTYPE, because it overrules $LANG, and
4147 * gtk_set_locale() calls setlocale() again. gnome_init()
4148 * sets $LC_CTYPE to "en_US" (that's a bug!). */
4149 if (what != VIM_LC_MESSAGES)
4150 vim_setenv((char_u *)"LC_CTYPE", name);
4151 # ifdef FEAT_GUI_GTK
4152 /* Let GTK know what locale we're using. Not sure this is
4153 * really needed... */
4154 if (gui.in_use)
4155 (void)gtk_set_locale();
4156 # endif
4159 # ifdef FEAT_EVAL
4160 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4161 set_lang_var();
4162 # endif
4167 # if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4169 * Function given to ExpandGeneric() to obtain the possible arguments of the
4170 * ":language" command.
4172 /*ARGSUSED*/
4173 char_u *
4174 get_lang_arg(xp, idx)
4175 expand_T *xp;
4176 int idx;
4178 if (idx == 0)
4179 return (char_u *)"messages";
4180 if (idx == 1)
4181 return (char_u *)"ctype";
4182 if (idx == 2)
4183 return (char_u *)"time";
4184 return NULL;
4186 # endif
4188 #endif