1/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved	by Bram Moolenaar
4 *
5 * Do ":help uganda"  in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
11# include "vimio.h"		/* for close() and dup() */
12#endif
13
14#define EXTERN
15#include "vim.h"
16
17#ifdef SPAWNO
18# include <spawno.h>		/* special MS-DOS swapping library */
19#endif
20
21#ifdef __CYGWIN__
22# ifndef WIN32
23#  include <cygwin/version.h>
24#  include <sys/cygwin.h>	/* for cygwin_conv_to_posix_path() and/or
25				 * cygwin_conv_path() */
26# endif
27# include <limits.h>
28#endif
29
30/* Maximum number of commands from + or -c arguments. */
31#define MAX_ARG_CMDS 10
32
33/* values for "window_layout" */
34#define WIN_HOR	    1	    /* "-o" horizontally split windows */
35#define	WIN_VER	    2	    /* "-O" vertically split windows */
36#define	WIN_TABS    3	    /* "-p" windows on tab pages */
37
38/* Struct for various parameters passed between main() and other functions. */
39typedef struct
40{
41    int		argc;
42    char	**argv;
43
44    int		evim_mode;		/* started as "evim" */
45    char_u	*use_vimrc;		/* vimrc from -u argument */
46
47    int		n_commands;		     /* no. of commands from + or -c */
48    char_u	*commands[MAX_ARG_CMDS];     /* commands from + or -c arg. */
49    char_u	cmds_tofree[MAX_ARG_CMDS];   /* commands that need free() */
50    int		n_pre_commands;		     /* no. of commands from --cmd */
51    char_u	*pre_commands[MAX_ARG_CMDS]; /* commands from --cmd argument */
52
53    int		edit_type;		/* type of editing to do */
54    char_u	*tagname;		/* tag from -t argument */
55#ifdef FEAT_QUICKFIX
56    char_u	*use_ef;		/* 'errorfile' from -q argument */
57#endif
58
59    int		want_full_screen;
60    int		stdout_isatty;		/* is stdout a terminal? */
61    char_u	*term;			/* specified terminal name */
62#ifdef FEAT_CRYPT
63    int		ask_for_key;		/* -x argument */
64#endif
65    int		no_swap_file;		/* "-n" argument used */
66#ifdef FEAT_EVAL
67    int		use_debug_break_level;
68#endif
69#ifdef FEAT_WINDOWS
70    int		window_count;		/* number of windows to use */
71    int		window_layout;		/* 0, WIN_HOR, WIN_VER or WIN_TABS */
72#endif
73
74#ifdef FEAT_CLIENTSERVER
75    int		serverArg;		/* TRUE when argument for a server */
76    char_u	*serverName_arg;	/* cmdline arg for server name */
77    char_u	*serverStr;		/* remote server command */
78    char_u	*serverStrEnc;		/* encoding of serverStr */
79    char_u	*servername;		/* allocated name for our server */
80#endif
81#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE)
82    int		literal;		/* don't expand file names */
83#endif
84#ifdef MSWIN
85    int		full_path;		/* file name argument was full path */
86#endif
87#ifdef FEAT_DIFF
88    int		diff_mode;		/* start with 'diff' set */
89#endif
90} mparm_T;
91
92/* Values for edit_type. */
93#define EDIT_NONE   0	    /* no edit type yet */
94#define EDIT_FILE   1	    /* file name argument[s] given, use argument list */
95#define EDIT_STDIN  2	    /* read file from stdin */
96#define EDIT_TAG    3	    /* tag name argument given, use tagname */
97#define EDIT_QF	    4	    /* start in quickfix mode */
98
99#if defined(UNIX) || defined(VMS)
100static int file_owned __ARGS((char *fname));
101#endif
102static void mainerr __ARGS((int, char_u *));
103static void main_msg __ARGS((char *s));
104static void usage __ARGS((void));
105static int get_number_arg __ARGS((char_u *p, int *idx, int def));
106#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
107static void init_locale __ARGS((void));
108#endif
109static void parse_command_name __ARGS((mparm_T *parmp));
110static void early_arg_scan __ARGS((mparm_T *parmp));
111static void command_line_scan __ARGS((mparm_T *parmp));
112static void check_tty __ARGS((mparm_T *parmp));
113static void read_stdin __ARGS((void));
114static void create_windows __ARGS((mparm_T *parmp));
115#ifdef FEAT_WINDOWS
116static void edit_buffers __ARGS((mparm_T *parmp));
117#endif
118static void exe_pre_commands __ARGS((mparm_T *parmp));
119static void exe_commands __ARGS((mparm_T *parmp));
120static void source_startup_scripts __ARGS((mparm_T *parmp));
121static void main_start_gui __ARGS((void));
122#if defined(HAS_SWAP_EXISTS_ACTION)
123static void check_swap_exists_action __ARGS((void));
124#endif
125#ifdef FEAT_CLIENTSERVER
126static void exec_on_server __ARGS((mparm_T *parmp));
127static void prepare_server __ARGS((mparm_T *parmp));
128static void cmdsrv_main __ARGS((int *argc, char **argv, char_u *serverName_arg, char_u **serverStr));
129static char_u *serverMakeName __ARGS((char_u *arg, char *cmd));
130#endif
131
132
133#ifdef __APPLE__
134#include <get_compat.h>
135#else
136#define COMPAT_MODE(a,b) (1)
137#endif /* __APPLE__ */
138
139/*
140 * Different types of error messages.
141 */
142static char *(main_errors[]) =
143{
144    N_("Unknown option argument"),
145#define ME_UNKNOWN_OPTION	0
146    N_("Too many edit arguments"),
147#define ME_TOO_MANY_ARGS	1
148    N_("Argument missing after"),
149#define ME_ARG_MISSING		2
150    N_("Garbage after option argument"),
151#define ME_GARBAGE		3
152    N_("Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"),
153#define ME_EXTRA_CMD		4
154    N_("Invalid argument for"),
155#define ME_INVALID_ARG		5
156};
157
158#ifndef PROTO	    /* don't want a prototype for main() */
159    int
160# ifdef VIMDLL
161_export
162# endif
163# ifdef FEAT_GUI_MSWIN
164#  ifdef __BORLANDC__
165_cdecl
166#  endif
167VimMain
168# else
169main
170# endif
171(argc, argv)
172    int		argc;
173    char	**argv;
174{
175    char_u	*fname = NULL;		/* file name from command line */
176    mparm_T	params;			/* various parameters passed between
177					 * main() and other functions. */
178#ifdef STARTUPTIME
179    int		i;
180#endif
181
182    {
183	char *base = strrchr(argv[0], '/');
184	if (base) base++; /* skip over slash */
185	else base = argv[0];
186	Unix2003_compat = 0;
187	if (strcmp(base,"vi")==0) {
188	    Unix2003_compat = COMPAT_MODE("bin/vi", "Unix2003");
189	} else if (strcmp(base,"ex")==0) {
190	    Unix2003_compat = COMPAT_MODE("bin/ex", "Unix2003");
191	}
192    }
193
194    /*
195     * Do any system-specific initialisations.  These can NOT use IObuff or
196     * NameBuff.  Thus emsg2() cannot be called!
197     */
198    mch_early_init();
199
200    /* Many variables are in "params" so that we can pass them to invoked
201     * functions without a lot of arguments.  "argc" and "argv" are also
202     * copied, so that they can be changed. */
203    vim_memset(&params, 0, sizeof(params));
204    params.argc = argc;
205    params.argv = argv;
206    params.want_full_screen = TRUE;
207#ifdef FEAT_EVAL
208    params.use_debug_break_level = -1;
209#endif
210#ifdef FEAT_WINDOWS
211    params.window_count = -1;
212#endif
213
214#ifdef FEAT_TCL
215    vim_tcl_init(params.argv[0]);
216#endif
217
218#ifdef MEM_PROFILE
219    atexit(vim_mem_profile_dump);
220#endif
221
222#ifdef STARTUPTIME
223    for (i = 1; i < argc; ++i)
224    {
225	if (STRICMP(argv[i], "--startuptime") == 0 && i + 1 < argc)
226	{
227	    time_fd = mch_fopen(argv[i + 1], "a");
228	    TIME_MSG("--- VIM STARTING ---");
229	    break;
230	}
231    }
232#endif
233    starttime = time(NULL);
234
235#ifdef __EMX__
236    _wildcard(&params.argc, &params.argv);
237#endif
238
239#ifdef FEAT_MBYTE
240    (void)mb_init();	/* init mb_bytelen_tab[] to ones */
241#endif
242#ifdef FEAT_EVAL
243    eval_init();	/* init global variables */
244#endif
245
246#ifdef __QNXNTO__
247    qnx_init();		/* PhAttach() for clipboard, (and gui) */
248#endif
249
250#ifdef MAC_OS_CLASSIC
251    /* Prepare for possibly starting GUI sometime */
252    /* Macintosh needs this before any memory is allocated. */
253    gui_prepare(&params.argc, params.argv);
254    TIME_MSG("GUI prepared");
255#endif
256
257    /* Init the table of Normal mode commands. */
258    init_normal_cmds();
259
260#if defined(HAVE_DATE_TIME) && defined(VMS) && defined(VAXC)
261    make_version();	/* Construct the long version string. */
262#endif
263
264    /*
265     * Allocate space for the generic buffers (needed for set_init_1() and
266     * EMSG2()).
267     */
268    if ((IObuff = alloc(IOSIZE)) == NULL
269	    || (NameBuff = alloc(MAXPATHL)) == NULL)
270	mch_exit(0);
271    TIME_MSG("Allocated generic buffers");
272
273#ifdef NBDEBUG
274    /* Wait a moment for debugging NetBeans.  Must be after allocating
275     * NameBuff. */
276    nbdebug_log_init("SPRO_GVIM_DEBUG", "SPRO_GVIM_DLEVEL");
277    nbdebug_wait(WT_ENV | WT_WAIT | WT_STOP, "SPRO_GVIM_WAIT", 20);
278    TIME_MSG("NetBeans debug wait");
279#endif
280
281#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
282    /*
283     * Setup to use the current locale (for ctype() and many other things).
284     * NOTE: Translated messages with encodings other than latin1 will not
285     * work until set_init_1() has been called!
286     */
287    init_locale();
288    TIME_MSG("locale set");
289#endif
290
291#ifdef FEAT_GUI
292    gui.dofork = TRUE;		    /* default is to use fork() */
293#endif
294
295    /*
296     * Do a first scan of the arguments in "argv[]":
297     *   -display or --display
298     *   --server...
299     *   --socketid
300     *   --windowid
301     */
302    early_arg_scan(&params);
303
304#ifdef FEAT_SUN_WORKSHOP
305    findYourself(params.argv[0]);
306#endif
307#if defined(FEAT_GUI) && !defined(MAC_OS_CLASSIC)
308    /* Prepare for possibly starting GUI sometime */
309    gui_prepare(&params.argc, params.argv);
310    TIME_MSG("GUI prepared");
311#endif
312
313#ifdef FEAT_CLIPBOARD
314    clip_init(FALSE);		/* Initialise clipboard stuff */
315    TIME_MSG("clipboard setup");
316#endif
317
318    /*
319     * Check if we have an interactive window.
320     * On the Amiga: If there is no window, we open one with a newcli command
321     * (needed for :! to * work). mch_check_win() will also handle the -d or
322     * -dev argument.
323     */
324    params.stdout_isatty = (mch_check_win(params.argc, params.argv) != FAIL);
325    TIME_MSG("window checked");
326
327    /*
328     * Allocate the first window and buffer.
329     * Can't do anything without it, exit when it fails.
330     */
331    if (win_alloc_first() == FAIL)
332	mch_exit(0);
333
334    init_yank();		/* init yank buffers */
335
336    alist_init(&global_alist);	/* Init the argument list to empty. */
337
338    /*
339     * Set the default values for the options.
340     * NOTE: Non-latin1 translated messages are working only after this,
341     * because this is where "has_mbyte" will be set, which is used by
342     * msg_outtrans_len_attr().
343     * First find out the home directory, needed to expand "~" in options.
344     */
345    init_homedir();		/* find real value of $HOME */
346    set_init_1();
347    TIME_MSG("inits 1");
348
349#ifdef FEAT_EVAL
350    set_lang_var();		/* set v:lang and v:ctype */
351#endif
352
353#ifdef FEAT_CLIENTSERVER
354    /*
355     * Do the client-server stuff, unless "--servername ''" was used.
356     * This may exit Vim if the command was sent to the server.
357     */
358    exec_on_server(&params);
359#endif
360
361    /*
362     * Figure out the way to work from the command name argv[0].
363     * "vimdiff" starts diff mode, "rvim" sets "restricted", etc.
364     */
365    parse_command_name(&params);
366
367    /*
368     * Process the command line arguments.  File names are put in the global
369     * argument list "global_alist".
370     */
371    command_line_scan(&params);
372    TIME_MSG("parsing arguments");
373
374    /*
375     * On some systems, when we compile with the GUI, we always use it.  On Mac
376     * there is no terminal version, and on Windows we can't fork one off with
377     * :gui.
378     */
379#ifdef ALWAYS_USE_GUI
380    gui.starting = TRUE;
381#else
382# if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
383    /*
384     * Check if the GUI can be started.  Reset gui.starting if not.
385     * Don't know about other systems, stay on the safe side and don't check.
386     */
387    if (gui.starting)
388    {
389	if (gui_init_check() == FAIL)
390	{
391	    gui.starting = FALSE;
392
393	    /* When running "evim" or "gvim -y" we need the menus, exit if we
394	     * don't have them. */
395	    if (params.evim_mode)
396		mch_exit(1);
397	}
398    }
399# endif
400#endif
401
402    if (GARGCOUNT > 0)
403    {
404#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE)
405	/*
406	 * Expand wildcards in file names.
407	 */
408	if (!params.literal)
409	{
410	    /* Temporarily add '(' and ')' to 'isfname'.  These are valid
411	     * filename characters but are excluded from 'isfname' to make
412	     * "gf" work on a file name in parenthesis (e.g.: see vim.h). */
413	    do_cmdline_cmd((char_u *)":set isf+=(,)");
414	    alist_expand(NULL, 0);
415	    do_cmdline_cmd((char_u *)":set isf&");
416	}
417#endif
418	fname = alist_name(&GARGLIST[0]);
419    }
420
421#if defined(WIN32) && defined(FEAT_MBYTE)
422    {
423	extern void set_alist_count(void);
424
425	/* Remember the number of entries in the argument list.  If it changes
426	 * we don't react on setting 'encoding'. */
427	set_alist_count();
428    }
429#endif
430
431#ifdef MSWIN
432    if (GARGCOUNT == 1 && params.full_path)
433    {
434	/*
435	 * If there is one filename, fully qualified, we have very probably
436	 * been invoked from explorer, so change to the file's directory.
437	 * Hint: to avoid this when typing a command use a forward slash.
438	 * If the cd fails, it doesn't matter.
439	 */
440	(void)vim_chdirfile(fname);
441    }
442#endif
443    TIME_MSG("expanding arguments");
444
445#ifdef FEAT_DIFF
446    if (params.diff_mode && params.window_count == -1)
447	params.window_count = 0;	/* open up to 3 windows */
448#endif
449
450    /* Don't redraw until much later. */
451    ++RedrawingDisabled;
452
453    /*
454     * When listing swap file names, don't do cursor positioning et. al.
455     */
456    if (recoverymode && fname == NULL)
457	params.want_full_screen = FALSE;
458
459    /*
460     * When certain to start the GUI, don't check capabilities of terminal.
461     * For GTK we can't be sure, but when started from the desktop it doesn't
462     * make sense to try using a terminal.
463     */
464#if defined(ALWAYS_USE_GUI) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
465    if (gui.starting
466# ifdef FEAT_GUI_GTK
467	    && !isatty(2)
468# endif
469	    )
470	params.want_full_screen = FALSE;
471#endif
472
473#if defined(FEAT_GUI_MAC) && defined(MACOS_X_UNIX)
474    /* When the GUI is started from Finder, need to display messages in a
475     * message box.  isatty(2) returns TRUE anyway, thus we need to check the
476     * name to know we're not started from a terminal. */
477    if (gui.starting && (!isatty(2) || strcmp("/dev/console", ttyname(2)) == 0))
478    {
479	params.want_full_screen = FALSE;
480
481	/* Avoid always using "/" as the current directory.  Note that when
482	 * started from Finder the arglist will be filled later in
483	 * HandleODocAE() and "fname" will be NULL. */
484	if (getcwd((char *)NameBuff, MAXPATHL) != NULL
485						&& STRCMP(NameBuff, "/") == 0)
486	{
487	    if (fname != NULL)
488		(void)vim_chdirfile(fname);
489	    else
490	    {
491		expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
492		vim_chdir(NameBuff);
493	    }
494	}
495    }
496#endif
497
498    /*
499     * mch_init() sets up the terminal (window) for use.  This must be
500     * done after resetting full_screen, otherwise it may move the cursor
501     * (MSDOS).
502     * Note that we may use mch_exit() before mch_init()!
503     */
504    mch_init();
505    TIME_MSG("shell init");
506
507#ifdef USE_XSMP
508    /*
509     * For want of anywhere else to do it, try to connect to xsmp here.
510     * Fitting it in after gui_mch_init, but before gui_init (via termcapinit).
511     * Hijacking -X 'no X connection' to also disable XSMP connection as that
512     * has a similar delay upon failure.
513     * Only try if SESSION_MANAGER is set to something non-null.
514     */
515    if (!x_no_connect)
516    {
517	char *p = getenv("SESSION_MANAGER");
518
519	if (p != NULL && *p != NUL)
520	{
521	    xsmp_init();
522	    TIME_MSG("xsmp init");
523	}
524    }
525#endif
526
527    /*
528     * Print a warning if stdout is not a terminal.
529     */
530    check_tty(&params);
531
532    /* This message comes before term inits, but after setting "silent_mode"
533     * when the input is not a tty. */
534    if (GARGCOUNT > 1 && !silent_mode)
535	printf(_("%d files to edit\n"), GARGCOUNT);
536
537    if (params.want_full_screen && !silent_mode)
538    {
539	termcapinit(params.term);	/* set terminal name and get terminal
540				   capabilities (will set full_screen) */
541	screen_start();		/* don't know where cursor is now */
542	TIME_MSG("Termcap init");
543    }
544
545    /*
546     * Set the default values for the options that use Rows and Columns.
547     */
548    ui_get_shellsize();		/* inits Rows and Columns */
549    win_init_size();
550#ifdef FEAT_DIFF
551    /* Set the 'diff' option now, so that it can be checked for in a .vimrc
552     * file.  There is no buffer yet though. */
553    if (params.diff_mode)
554	diff_win_options(firstwin, FALSE);
555#endif
556
557    cmdline_row = Rows - p_ch;
558    msg_row = cmdline_row;
559    screenalloc(FALSE);		/* allocate screen buffers */
560    set_init_2();
561    TIME_MSG("inits 2");
562
563    msg_scroll = TRUE;
564    no_wait_return = TRUE;
565
566    init_mappings();		/* set up initial mappings */
567
568    init_highlight(TRUE, FALSE); /* set the default highlight groups */
569    TIME_MSG("init highlight");
570
571#ifdef FEAT_EVAL
572    /* Set the break level after the terminal is initialized. */
573    debug_break_level = params.use_debug_break_level;
574#endif
575
576    /* Execute --cmd arguments. */
577    exe_pre_commands(&params);
578
579    /* Source startup scripts. */
580    source_startup_scripts(&params);
581
582#ifdef FEAT_EVAL
583    /*
584     * Read all the plugin files.
585     * Only when compiled with +eval, since most plugins need it.
586     */
587    if (p_lpl)
588    {
589# ifdef VMS	/* Somehow VMS doesn't handle the "**". */
590	source_runtime((char_u *)"plugin/*.vim", TRUE);
591# else
592	source_runtime((char_u *)"plugin/**/*.vim", TRUE);
593# endif
594	TIME_MSG("loading plugins");
595    }
596#endif
597
598#ifdef FEAT_DIFF
599    /* Decide about window layout for diff mode after reading vimrc. */
600    if (params.diff_mode && params.window_layout == 0)
601    {
602	if (diffopt_horizontal())
603	    params.window_layout = WIN_HOR;	/* use horizontal split */
604	else
605	    params.window_layout = WIN_VER;	/* use vertical split */
606    }
607#endif
608
609    /*
610     * Recovery mode without a file name: List swap files.
611     * This uses the 'dir' option, therefore it must be after the
612     * initializations.
613     */
614    if (recoverymode && fname == NULL)
615    {
616	recover_names(NULL, TRUE, 0, NULL);
617	mch_exit(0);
618    }
619
620    /*
621     * Set a few option defaults after reading .vimrc files:
622     * 'title' and 'icon', Unix: 'shellpipe' and 'shellredir'.
623     */
624    set_init_3();
625    TIME_MSG("inits 3");
626
627    /*
628     * "-n" argument: Disable swap file by setting 'updatecount' to 0.
629     * Note that this overrides anything from a vimrc file.
630     */
631    if (params.no_swap_file)
632	p_uc = 0;
633
634#ifdef FEAT_FKMAP
635    if (curwin->w_p_rl && p_altkeymap)
636    {
637	p_hkmap = FALSE;	/* Reset the Hebrew keymap mode */
638# ifdef FEAT_ARABIC
639	curwin->w_p_arab = FALSE; /* Reset the Arabic keymap mode */
640# endif
641	p_fkmap = TRUE;		/* Set the Farsi keymap mode */
642    }
643#endif
644
645#ifdef FEAT_GUI
646    if (gui.starting)
647    {
648#if defined(UNIX) || defined(VMS)
649	/* When something caused a message from a vimrc script, need to output
650	 * an extra newline before the shell prompt. */
651	if (did_emsg || msg_didout)
652	    putchar('\n');
653#endif
654
655	gui_start();		/* will set full_screen to TRUE */
656	TIME_MSG("starting GUI");
657
658	/* When running "evim" or "gvim -y" we need the menus, exit if we
659	 * don't have them. */
660	if (!gui.in_use && params.evim_mode)
661	    mch_exit(1);
662    }
663#endif
664
665#ifdef SPAWNO		/* special MSDOS swapping library */
666    init_SPAWNO("", SWAP_ANY);
667#endif
668
669#ifdef FEAT_VIMINFO
670    /*
671     * Read in registers, history etc, but not marks, from the viminfo file.
672     * This is where v:oldfiles gets filled.
673     */
674    if (*p_viminfo != NUL)
675    {
676	read_viminfo(NULL, VIF_WANT_INFO | VIF_GET_OLDFILES);
677	TIME_MSG("reading viminfo");
678    }
679#endif
680
681#ifdef FEAT_QUICKFIX
682    /*
683     * "-q errorfile": Load the error file now.
684     * If the error file can't be read, exit before doing anything else.
685     */
686    if (params.edit_type == EDIT_QF)
687    {
688	if (params.use_ef != NULL)
689	    set_string_option_direct((char_u *)"ef", -1,
690					   params.use_ef, OPT_FREE, SID_CARG);
691	vim_snprintf((char *)IObuff, IOSIZE, "cfile %s", p_ef);
692	if (qf_init(NULL, p_ef, p_efm, TRUE, IObuff) < 0)
693	{
694	    out_char('\n');
695	    mch_exit(3);
696	}
697	TIME_MSG("reading errorfile");
698    }
699#endif
700
701    /*
702     * Start putting things on the screen.
703     * Scroll screen down before drawing over it
704     * Clear screen now, so file message will not be cleared.
705     */
706    starting = NO_BUFFERS;
707    no_wait_return = FALSE;
708    if (!exmode_active)
709	msg_scroll = FALSE;
710
711#ifdef FEAT_GUI
712    /*
713     * This seems to be required to make callbacks to be called now, instead
714     * of after things have been put on the screen, which then may be deleted
715     * when getting a resize callback.
716     * For the Mac this handles putting files dropped on the Vim icon to
717     * global_alist.
718     */
719    if (gui.in_use)
720    {
721# ifdef FEAT_SUN_WORKSHOP
722	if (!usingSunWorkShop)
723# endif
724	    gui_wait_for_chars(50L);
725	TIME_MSG("GUI delay");
726    }
727#endif
728
729#if defined(FEAT_GUI_PHOTON) && defined(FEAT_CLIPBOARD)
730    qnx_clip_init();
731#endif
732
733#if defined(MACOS_X) && defined(FEAT_CLIPBOARD)
734    clip_init(TRUE);
735#endif
736
737#ifdef FEAT_XCLIPBOARD
738    /* Start using the X clipboard, unless the GUI was started. */
739# ifdef FEAT_GUI
740    if (!gui.in_use)
741# endif
742    {
743	setup_term_clip();
744	TIME_MSG("setup clipboard");
745    }
746#endif
747
748#ifdef FEAT_CLIENTSERVER
749    /* Prepare for being a Vim server. */
750    prepare_server(&params);
751#endif
752
753    /*
754     * If "-" argument given: Read file from stdin.
755     * Do this before starting Raw mode, because it may change things that the
756     * writing end of the pipe doesn't like, e.g., in case stdin and stderr
757     * are the same terminal: "cat | vim -".
758     * Using autocommands here may cause trouble...
759     */
760    if (params.edit_type == EDIT_STDIN && !recoverymode)
761	read_stdin();
762
763#if defined(UNIX) || defined(VMS)
764    /* When switching screens and something caused a message from a vimrc
765     * script, need to output an extra newline on exit. */
766    if ((did_emsg || msg_didout) && *T_TI != NUL)
767	newline_on_exit = TRUE;
768#endif
769
770    /*
771     * When done something that is not allowed or error message call
772     * wait_return.  This must be done before starttermcap(), because it may
773     * switch to another screen. It must be done after settmode(TMODE_RAW),
774     * because we want to react on a single key stroke.
775     * Call settmode and starttermcap here, so the T_KS and T_TI may be
776     * defined by termcapinit and redefined in .exrc.
777     */
778    settmode(TMODE_RAW);
779    TIME_MSG("setting raw mode");
780
781    if (need_wait_return || msg_didany)
782    {
783	wait_return(TRUE);
784	TIME_MSG("waiting for return");
785    }
786
787    starttermcap();	    /* start termcap if not done by wait_return() */
788    TIME_MSG("start termcap");
789
790#ifdef FEAT_MOUSE
791    setmouse();				/* may start using the mouse */
792#endif
793    if (scroll_region)
794	scroll_region_reset();		/* In case Rows changed */
795    scroll_start();	/* may scroll the screen to the right position */
796
797    /*
798     * Don't clear the screen when starting in Ex mode, unless using the GUI.
799     */
800    if (exmode_active
801#ifdef FEAT_GUI
802			&& !gui.in_use
803#endif
804					)
805	must_redraw = CLEAR;
806    else
807    {
808	screenclear();			/* clear screen */
809	TIME_MSG("clearing screen");
810    }
811
812#ifdef FEAT_CRYPT
813    if (params.ask_for_key)
814    {
815	(void)blowfish_self_test();
816	(void)get_crypt_key(TRUE, TRUE);
817	TIME_MSG("getting crypt key");
818    }
819#endif
820
821    no_wait_return = TRUE;
822
823    /*
824     * Create the requested number of windows and edit buffers in them.
825     * Also does recovery if "recoverymode" set.
826     */
827    create_windows(&params);
828    TIME_MSG("opening buffers");
829
830#ifdef FEAT_EVAL
831    /* clear v:swapcommand */
832    set_vim_var_string(VV_SWAPCOMMAND, NULL, -1);
833#endif
834
835    /* Ex starts at last line of the file */
836    if (exmode_active)
837	curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
838
839#ifdef FEAT_AUTOCMD
840    apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
841    TIME_MSG("BufEnter autocommands");
842#endif
843    setpcmark();
844
845#ifdef FEAT_QUICKFIX
846    /*
847     * When started with "-q errorfile" jump to first error now.
848     */
849    if (params.edit_type == EDIT_QF)
850    {
851	qf_jump(NULL, 0, 0, FALSE);
852	TIME_MSG("jump to first error");
853    }
854#endif
855
856#ifdef FEAT_WINDOWS
857    /*
858     * If opened more than one window, start editing files in the other
859     * windows.
860     */
861    edit_buffers(&params);
862#endif
863
864#ifdef FEAT_DIFF
865    if (params.diff_mode)
866    {
867	win_T	*wp;
868
869	/* set options in each window for "vimdiff". */
870	for (wp = firstwin; wp != NULL; wp = wp->w_next)
871	    diff_win_options(wp, TRUE);
872    }
873#endif
874
875    /*
876     * Shorten any of the filenames, but only when absolute.
877     */
878    shorten_fnames(FALSE);
879
880    /*
881     * Need to jump to the tag before executing the '-c command'.
882     * Makes "vim -c '/return' -t main" work.
883     */
884    if (params.tagname != NULL)
885    {
886#if defined(HAS_SWAP_EXISTS_ACTION)
887	swap_exists_did_quit = FALSE;
888#endif
889
890	vim_snprintf((char *)IObuff, IOSIZE, "ta %s", params.tagname);
891	do_cmdline_cmd(IObuff);
892	TIME_MSG("jumping to tag");
893
894#if defined(HAS_SWAP_EXISTS_ACTION)
895	/* If the user doesn't want to edit the file then we quit here. */
896	if (swap_exists_did_quit)
897	    getout(1);
898#endif
899    }
900
901    /* Execute any "+", "-c" and "-S" arguments. */
902    if (params.n_commands > 0)
903	exe_commands(&params);
904
905    RedrawingDisabled = 0;
906    redraw_all_later(NOT_VALID);
907    no_wait_return = FALSE;
908    starting = 0;
909
910#ifdef FEAT_TERMRESPONSE
911    /* Requesting the termresponse is postponed until here, so that a "-c q"
912     * argument doesn't make it appear in the shell Vim was started from. */
913    may_req_termresponse();
914#endif
915
916    /* start in insert mode */
917    if (p_im)
918	need_start_insertmode = TRUE;
919
920#ifdef FEAT_AUTOCMD
921    apply_autocmds(EVENT_VIMENTER, NULL, NULL, FALSE, curbuf);
922    TIME_MSG("VimEnter autocommands");
923#endif
924
925#if defined(FEAT_DIFF) && defined(FEAT_SCROLLBIND)
926    /* When a startup script or session file setup for diff'ing and
927     * scrollbind, sync the scrollbind now. */
928    if (curwin->w_p_diff && curwin->w_p_scb)
929    {
930	update_topline();
931	check_scrollbind((linenr_T)0, 0L);
932	TIME_MSG("diff scrollbinding");
933    }
934#endif
935
936#if defined(WIN3264) && !defined(FEAT_GUI_W32)
937    mch_set_winsize_now();	    /* Allow winsize changes from now on */
938#endif
939
940#if defined(FEAT_GUI) && defined(FEAT_WINDOWS)
941    /* When tab pages were created, may need to update the tab pages line and
942     * scrollbars.  This is skipped while creating them. */
943    if (first_tabpage->tp_next != NULL)
944    {
945	out_flush();
946	gui_init_which_components(NULL);
947	gui_update_scrollbars(TRUE);
948    }
949    need_mouse_correct = TRUE;
950#endif
951
952    /* If ":startinsert" command used, stuff a dummy command to be able to
953     * call normal_cmd(), which will then start Insert mode. */
954    if (restart_edit != 0)
955	stuffcharReadbuff(K_NOP);
956
957#ifdef FEAT_NETBEANS_INTG
958    if (netbeansArg != NULL && strncmp("-nb", netbeansArg, 3) == 0)
959    {
960# ifdef FEAT_GUI
961#  if !defined(FEAT_GUI_MOTIF) && !defined(FEAT_GUI_GTK)  \
962		&& !defined(FEAT_GUI_W32)
963	if (gui.in_use)
964	{
965	    mch_errmsg(_("netbeans is not supported with this GUI\n"));
966	    mch_exit(2);
967	}
968#  endif
969# endif
970	/* Tell the client that it can start sending commands. */
971	netbeans_open(netbeansArg + 3, TRUE);
972    }
973#endif
974
975    TIME_MSG("before starting main loop");
976
977    /*
978     * Call the main command loop.  This never returns.
979     * For embedded MzScheme the main_loop will be called by Scheme
980     * for proper stack tracking
981     */
982#ifndef FEAT_MZSCHEME
983    main_loop(FALSE, FALSE);
984#else
985    mzscheme_main();
986#endif
987
988    return 0;
989}
990#endif /* PROTO */
991
992/*
993 * Main loop: Execute Normal mode commands until exiting Vim.
994 * Also used to handle commands in the command-line window, until the window
995 * is closed.
996 * Also used to handle ":visual" command after ":global": execute Normal mode
997 * commands, return when entering Ex mode.  "noexmode" is TRUE then.
998 */
999    void
1000main_loop(cmdwin, noexmode)
1001    int		cmdwin;	    /* TRUE when working in the command-line window */
1002    int		noexmode;   /* TRUE when return on entering Ex mode */
1003{
1004    oparg_T	oa;				/* operator arguments */
1005    int		previous_got_int = FALSE;	/* "got_int" was TRUE */
1006#ifdef FEAT_CONCEAL
1007    linenr_T	conceal_old_cursor_line = 0;
1008    linenr_T	conceal_new_cursor_line = 0;
1009    int		conceal_update_lines = FALSE;
1010#endif
1011
1012#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1013    /* Setup to catch a terminating error from the X server.  Just ignore
1014     * it, restore the state and continue.  This might not always work
1015     * properly, but at least we don't exit unexpectedly when the X server
1016     * exists while Vim is running in a console. */
1017    if (!cmdwin && !noexmode && SETJMP(x_jump_env))
1018    {
1019	State = NORMAL;
1020# ifdef FEAT_VISUAL
1021	VIsual_active = FALSE;
1022# endif
1023	got_int = TRUE;
1024	need_wait_return = FALSE;
1025	global_busy = FALSE;
1026	exmode_active = 0;
1027	skip_redraw = FALSE;
1028	RedrawingDisabled = 0;
1029	no_wait_return = 0;
1030# ifdef FEAT_EVAL
1031	emsg_skip = 0;
1032# endif
1033	emsg_off = 0;
1034# ifdef FEAT_MOUSE
1035	setmouse();
1036# endif
1037	settmode(TMODE_RAW);
1038	starttermcap();
1039	scroll_start();
1040	redraw_later_clear();
1041    }
1042#endif
1043
1044    clear_oparg(&oa);
1045    while (!cmdwin
1046#ifdef FEAT_CMDWIN
1047	    || cmdwin_result == 0
1048#endif
1049	    )
1050    {
1051	if (stuff_empty())
1052	{
1053	    did_check_timestamps = FALSE;
1054	    if (need_check_timestamps)
1055		check_timestamps(FALSE);
1056	    if (need_wait_return)	/* if wait_return still needed ... */
1057		wait_return(FALSE);	/* ... call it now */
1058	    if (need_start_insertmode && goto_im()
1059#ifdef FEAT_VISUAL
1060		    && !VIsual_active
1061#endif
1062		    )
1063	    {
1064		need_start_insertmode = FALSE;
1065		stuffReadbuff((char_u *)"i");	/* start insert mode next */
1066		/* skip the fileinfo message now, because it would be shown
1067		 * after insert mode finishes! */
1068		need_fileinfo = FALSE;
1069	    }
1070	}
1071
1072	/* Reset "got_int" now that we got back to the main loop.  Except when
1073	 * inside a ":g/pat/cmd" command, then the "got_int" needs to abort
1074	 * the ":g" command.
1075	 * For ":g/pat/vi" we reset "got_int" when used once.  When used
1076	 * a second time we go back to Ex mode and abort the ":g" command. */
1077	if (got_int)
1078	{
1079	    if (noexmode && global_busy && !exmode_active && previous_got_int)
1080	    {
1081		/* Typed two CTRL-C in a row: go back to ex mode as if "Q" was
1082		 * used and keep "got_int" set, so that it aborts ":g". */
1083		exmode_active = EXMODE_NORMAL;
1084		State = NORMAL;
1085	    }
1086	    else if (!global_busy || !exmode_active)
1087	    {
1088		if (!quit_more)
1089		    (void)vgetc();		/* flush all buffers */
1090		got_int = FALSE;
1091	    }
1092	    previous_got_int = TRUE;
1093	}
1094	else
1095	    previous_got_int = FALSE;
1096
1097	if (!exmode_active)
1098	    msg_scroll = FALSE;
1099	quit_more = FALSE;
1100
1101	/*
1102	 * If skip redraw is set (for ":" in wait_return()), don't redraw now.
1103	 * If there is nothing in the stuff_buffer or do_redraw is TRUE,
1104	 * update cursor and redraw.
1105	 */
1106	if (skip_redraw || exmode_active)
1107	    skip_redraw = FALSE;
1108	else if (do_redraw || stuff_empty())
1109	{
1110#if defined(FEAT_AUTOCMD) || defined(FEAT_CONCEAL)
1111	    /* Trigger CursorMoved if the cursor moved. */
1112	    if (!finish_op && (
1113# ifdef FEAT_AUTOCMD
1114			has_cursormoved()
1115# endif
1116# if defined(FEAT_AUTOCMD) && defined(FEAT_CONCEAL)
1117			||
1118# endif
1119# ifdef FEAT_CONCEAL
1120			curwin->w_p_cole > 0
1121# endif
1122			)
1123		 && !equalpos(last_cursormoved, curwin->w_cursor))
1124	    {
1125# ifdef FEAT_AUTOCMD
1126		if (has_cursormoved())
1127		    apply_autocmds(EVENT_CURSORMOVED, NULL, NULL,
1128							       FALSE, curbuf);
1129# endif
1130# ifdef FEAT_CONCEAL
1131		if (curwin->w_p_cole > 0)
1132		{
1133		    conceal_old_cursor_line = last_cursormoved.lnum;
1134		    conceal_new_cursor_line = curwin->w_cursor.lnum;
1135		    conceal_update_lines = TRUE;
1136		}
1137# endif
1138		last_cursormoved = curwin->w_cursor;
1139	    }
1140#endif
1141
1142#if defined(FEAT_DIFF) && defined(FEAT_SCROLLBIND)
1143	    /* Scroll-binding for diff mode may have been postponed until
1144	     * here.  Avoids doing it for every change. */
1145	    if (diff_need_scrollbind)
1146	    {
1147		check_scrollbind((linenr_T)0, 0L);
1148		diff_need_scrollbind = FALSE;
1149	    }
1150#endif
1151#if defined(FEAT_FOLDING) && defined(FEAT_VISUAL)
1152	    /* Include a closed fold completely in the Visual area. */
1153	    foldAdjustVisual();
1154#endif
1155#ifdef FEAT_FOLDING
1156	    /*
1157	     * When 'foldclose' is set, apply 'foldlevel' to folds that don't
1158	     * contain the cursor.
1159	     * When 'foldopen' is "all", open the fold(s) under the cursor.
1160	     * This may mark the window for redrawing.
1161	     */
1162	    if (hasAnyFolding(curwin) && !char_avail())
1163	    {
1164		foldCheckClose();
1165		if (fdo_flags & FDO_ALL)
1166		    foldOpenCursor();
1167	    }
1168#endif
1169
1170	    /*
1171	     * Before redrawing, make sure w_topline is correct, and w_leftcol
1172	     * if lines don't wrap, and w_skipcol if lines wrap.
1173	     */
1174	    update_topline();
1175	    validate_cursor();
1176
1177#ifdef FEAT_VISUAL
1178	    if (VIsual_active)
1179		update_curbuf(INVERTED);/* update inverted part */
1180	    else
1181#endif
1182		if (must_redraw)
1183		update_screen(0);
1184	    else if (redraw_cmdline || clear_cmdline)
1185		showmode();
1186#ifdef FEAT_WINDOWS
1187	    redraw_statuslines();
1188#endif
1189#ifdef FEAT_TITLE
1190	    if (need_maketitle)
1191		maketitle();
1192#endif
1193	    /* display message after redraw */
1194	    if (keep_msg != NULL)
1195	    {
1196		char_u *p;
1197
1198		/* msg_attr_keep() will set keep_msg to NULL, must free the
1199		 * string here. */
1200		p = keep_msg;
1201		keep_msg = NULL;
1202		msg_attr(p, keep_msg_attr);
1203		vim_free(p);
1204	    }
1205	    if (need_fileinfo)		/* show file info after redraw */
1206	    {
1207		fileinfo(FALSE, TRUE, FALSE);
1208		need_fileinfo = FALSE;
1209	    }
1210
1211	    emsg_on_display = FALSE;	/* can delete error message now */
1212	    did_emsg = FALSE;
1213	    msg_didany = FALSE;		/* reset lines_left in msg_start() */
1214	    may_clear_sb_text();	/* clear scroll-back text on next msg */
1215	    showruler(FALSE);
1216
1217# if defined(FEAT_CONCEAL)
1218	    if (conceal_update_lines
1219		    && (conceal_old_cursor_line != conceal_new_cursor_line
1220			|| conceal_cursor_line(curwin)
1221			|| need_cursor_line_redraw))
1222	    {
1223		if (conceal_old_cursor_line != conceal_new_cursor_line)
1224		    update_single_line(curwin, conceal_old_cursor_line);
1225		update_single_line(curwin, conceal_new_cursor_line);
1226		curwin->w_valid &= ~VALID_CROW;
1227	    }
1228# endif
1229	    setcursor();
1230	    cursor_on();
1231
1232	    do_redraw = FALSE;
1233
1234#ifdef STARTUPTIME
1235	    /* Now that we have drawn the first screen all the startup stuff
1236	     * has been done, close any file for startup messages. */
1237	    if (time_fd != NULL)
1238	    {
1239		TIME_MSG("first screen update");
1240		TIME_MSG("--- VIM STARTED ---");
1241		fclose(time_fd);
1242		time_fd = NULL;
1243	    }
1244#endif
1245	}
1246#ifdef FEAT_GUI
1247	if (need_mouse_correct)
1248	    gui_mouse_correct();
1249#endif
1250
1251	/*
1252	 * Update w_curswant if w_set_curswant has been set.
1253	 * Postponed until here to avoid computing w_virtcol too often.
1254	 */
1255	update_curswant();
1256
1257#ifdef FEAT_EVAL
1258	/*
1259	 * May perform garbage collection when waiting for a character, but
1260	 * only at the very toplevel.  Otherwise we may be using a List or
1261	 * Dict internally somewhere.
1262	 * "may_garbage_collect" is reset in vgetc() which is invoked through
1263	 * do_exmode() and normal_cmd().
1264	 */
1265	may_garbage_collect = (!cmdwin && !noexmode);
1266#endif
1267	/*
1268	 * If we're invoked as ex, do a round of ex commands.
1269	 * Otherwise, get and execute a normal mode command.
1270	 */
1271	if (exmode_active)
1272	{
1273	    if (noexmode)   /* End of ":global/path/visual" commands */
1274		return;
1275	    do_exmode(exmode_active == EXMODE_VIM);
1276	}
1277	else
1278	    normal_cmd(&oa, TRUE);
1279    }
1280}
1281
1282
1283#if defined(USE_XSMP) || defined(FEAT_GUI_MSWIN) || defined(PROTO)
1284/*
1285 * Exit, but leave behind swap files for modified buffers.
1286 */
1287    void
1288getout_preserve_modified(exitval)
1289    int		exitval;
1290{
1291# if defined(SIGHUP) && defined(SIG_IGN)
1292    /* Ignore SIGHUP, because a dropped connection causes a read error, which
1293     * makes Vim exit and then handling SIGHUP causes various reentrance
1294     * problems. */
1295    signal(SIGHUP, SIG_IGN);
1296# endif
1297
1298    ml_close_notmod();		    /* close all not-modified buffers */
1299    ml_sync_all(FALSE, FALSE);	    /* preserve all swap files */
1300    ml_close_all(FALSE);	    /* close all memfiles, without deleting */
1301    getout(exitval);		    /* exit Vim properly */
1302}
1303#endif
1304
1305
1306/* Exit properly */
1307    void
1308getout(exitval)
1309    int		exitval;
1310{
1311#ifdef FEAT_AUTOCMD
1312    buf_T	*buf;
1313    win_T	*wp;
1314    tabpage_T	*tp, *next_tp;
1315#endif
1316
1317    exiting = TRUE;
1318
1319    /* When running in Ex mode an error causes us to exit with a non-zero exit
1320     * code.  POSIX requires this, although it's not 100% clear from the
1321     * standard. */
1322    if (exmode_active || Unix2003_compat )
1323	exitval += ex_exitval;
1324
1325    /* Position the cursor on the last screen line, below all the text */
1326#ifdef FEAT_GUI
1327    if (!gui.in_use)
1328#endif
1329	windgoto((int)Rows - 1, 0);
1330
1331#if defined(FEAT_EVAL) || defined(FEAT_SYN_HL)
1332    /* Optionally print hashtable efficiency. */
1333    hash_debug_results();
1334#endif
1335
1336#ifdef FEAT_GUI
1337    msg_didany = FALSE;
1338#endif
1339
1340#ifdef FEAT_AUTOCMD
1341    if (get_vim_var_nr(VV_DYING) <= 1)
1342    {
1343	/* Trigger BufWinLeave for all windows, but only once per buffer. */
1344# if defined FEAT_WINDOWS
1345	for (tp = first_tabpage; tp != NULL; tp = next_tp)
1346	{
1347	    next_tp = tp->tp_next;
1348	    for (wp = (tp == curtab)
1349		    ? firstwin : tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1350	    {
1351		buf = wp->w_buffer;
1352		if (buf->b_changedtick != -1)
1353		{
1354		    apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname,
1355						    buf->b_fname, FALSE, buf);
1356		    buf->b_changedtick = -1;    /* note that we did it already */
1357		    /* start all over, autocommands may mess up the lists */
1358		    next_tp = first_tabpage;
1359		    break;
1360		}
1361	    }
1362	}
1363# else
1364	apply_autocmds(EVENT_BUFWINLEAVE, curbuf, curbuf->b_fname,
1365							       FALSE, curbuf);
1366# endif
1367
1368	/* Trigger BufUnload for buffers that are loaded */
1369	for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1370	    if (buf->b_ml.ml_mfp != NULL)
1371	    {
1372		apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname,
1373								  FALSE, buf);
1374		if (!buf_valid(buf))	/* autocmd may delete the buffer */
1375		    break;
1376	    }
1377	apply_autocmds(EVENT_VIMLEAVEPRE, NULL, NULL, FALSE, curbuf);
1378    }
1379#endif
1380
1381#ifdef FEAT_VIMINFO
1382    if (*p_viminfo != NUL)
1383	/* Write out the registers, history, marks etc, to the viminfo file */
1384	write_viminfo(NULL, FALSE);
1385#endif
1386
1387#ifdef FEAT_AUTOCMD
1388    if (get_vim_var_nr(VV_DYING) <= 1)
1389	apply_autocmds(EVENT_VIMLEAVE, NULL, NULL, FALSE, curbuf);
1390#endif
1391
1392#ifdef FEAT_PROFILE
1393    profile_dump();
1394#endif
1395
1396    if (did_emsg
1397#ifdef FEAT_GUI
1398	    || (gui.in_use && msg_didany && p_verbose > 0)
1399#endif
1400	    )
1401    {
1402	/* give the user a chance to read the (error) message */
1403	no_wait_return = FALSE;
1404	wait_return(FALSE);
1405    }
1406
1407#ifdef FEAT_AUTOCMD
1408    /* Position the cursor again, the autocommands may have moved it */
1409# ifdef FEAT_GUI
1410    if (!gui.in_use)
1411# endif
1412	windgoto((int)Rows - 1, 0);
1413#endif
1414
1415#ifdef FEAT_LUA
1416    lua_end();
1417#endif
1418#ifdef FEAT_MZSCHEME
1419    mzscheme_end();
1420#endif
1421#ifdef FEAT_TCL
1422    tcl_end();
1423#endif
1424#ifdef FEAT_RUBY
1425    ruby_end();
1426#endif
1427#ifdef FEAT_PYTHON
1428    python_end();
1429#endif
1430#ifdef FEAT_PYTHON3
1431    python3_end();
1432#endif
1433#ifdef FEAT_PERL
1434    perl_end();
1435#endif
1436#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
1437    iconv_end();
1438#endif
1439#ifdef FEAT_NETBEANS_INTG
1440    netbeans_end();
1441#endif
1442#ifdef FEAT_CSCOPE
1443    cs_end();
1444#endif
1445#ifdef FEAT_EVAL
1446    if (garbage_collect_at_exit)
1447	garbage_collect();
1448#endif
1449
1450    mch_exit(exitval);
1451}
1452
1453/*
1454 * Get a (optional) count for a Vim argument.
1455 */
1456    static int
1457get_number_arg(p, idx, def)
1458    char_u	*p;	    /* pointer to argument */
1459    int		*idx;	    /* index in argument, is incremented */
1460    int		def;	    /* default value */
1461{
1462    if (vim_isdigit(p[*idx]))
1463    {
1464	def = atoi((char *)&(p[*idx]));
1465	while (vim_isdigit(p[*idx]))
1466	    *idx = *idx + 1;
1467    }
1468    return def;
1469}
1470
1471#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
1472/*
1473 * Setup to use the current locale (for ctype() and many other things).
1474 */
1475    static void
1476init_locale()
1477{
1478    setlocale(LC_ALL, "");
1479
1480# ifdef FEAT_GUI_GTK
1481    /* Tell Gtk not to change our locale settings. */
1482    gtk_disable_setlocale();
1483# endif
1484# if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
1485    /* Make sure strtod() uses a decimal point, not a comma. */
1486    setlocale(LC_NUMERIC, "C");
1487# endif
1488
1489# ifdef WIN32
1490    /* Apparently MS-Windows printf() may cause a crash when we give it 8-bit
1491     * text while it's expecting text in the current locale.  This call avoids
1492     * that. */
1493    setlocale(LC_CTYPE, "C");
1494# endif
1495
1496# ifdef FEAT_GETTEXT
1497    {
1498	int	mustfree = FALSE;
1499	char_u	*p;
1500
1501#  ifdef DYNAMIC_GETTEXT
1502	/* Initialize the gettext library */
1503	dyn_libintl_init(NULL);
1504#  endif
1505	/* expand_env() doesn't work yet, because chartab[] is not initialized
1506	 * yet, call vim_getenv() directly */
1507	p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
1508	if (p != NULL && *p != NUL)
1509	{
1510	    vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
1511	    bindtextdomain(VIMPACKAGE, (char *)NameBuff);
1512	}
1513	if (mustfree)
1514	    vim_free(p);
1515	textdomain(VIMPACKAGE);
1516    }
1517# endif
1518}
1519#endif
1520
1521/*
1522 * Check for: [r][e][g][vi|vim|view][diff][ex[im]]
1523 * If the executable name starts with "r" we disable shell commands.
1524 * If the next character is "e" we run in Easy mode.
1525 * If the next character is "g" we run the GUI version.
1526 * If the next characters are "view" we start in readonly mode.
1527 * If the next characters are "diff" or "vimdiff" we start in diff mode.
1528 * If the next characters are "ex" we start in Ex mode.  If it's followed
1529 * by "im" use improved Ex mode.
1530 */
1531    static void
1532parse_command_name(parmp)
1533    mparm_T	*parmp;
1534{
1535    char_u	*initstr;
1536
1537    initstr = gettail((char_u *)parmp->argv[0]);
1538
1539#ifdef MACOS_X_UNIX
1540    /* An issue has been seen when launching Vim in such a way that
1541     * $PWD/$ARGV[0] or $ARGV[0] is not the absolute path to the
1542     * executable or a symbolic link of it. Until this issue is resolved
1543     * we prohibit the GUI from being used.
1544     */
1545    if (STRCMP(initstr, parmp->argv[0]) == 0)
1546	disallow_gui = TRUE;
1547
1548    /* TODO: On MacOS X default to gui if argv[0] ends in:
1549     *       /Vim.app/Contents/MacOS/Vim */
1550#endif
1551
1552#ifdef FEAT_EVAL
1553    set_vim_var_string(VV_PROGNAME, initstr, -1);
1554#endif
1555
1556    if (TOLOWER_ASC(initstr[0]) == 'r')
1557    {
1558	restricted = TRUE;
1559	++initstr;
1560    }
1561
1562    /* Use evim mode for "evim" and "egvim", not for "editor". */
1563    if (TOLOWER_ASC(initstr[0]) == 'e'
1564	    && (TOLOWER_ASC(initstr[1]) == 'v'
1565		|| TOLOWER_ASC(initstr[1]) == 'g'))
1566    {
1567#ifdef FEAT_GUI
1568	gui.starting = TRUE;
1569#endif
1570	parmp->evim_mode = TRUE;
1571	++initstr;
1572    }
1573
1574    /* "gvim" starts the GUI.  Also accept "Gvim" for MS-Windows. */
1575    if (TOLOWER_ASC(initstr[0]) == 'g')
1576    {
1577	main_start_gui();
1578#ifdef FEAT_GUI
1579	++initstr;
1580#endif
1581    }
1582
1583    if (STRNICMP(initstr, "view", 4) == 0)
1584    {
1585	readonlymode = TRUE;
1586	curbuf->b_p_ro = TRUE;
1587	p_uc = 10000;			/* don't update very often */
1588	initstr += 4;
1589    }
1590    else if (STRNICMP(initstr, "vim", 3) == 0)
1591	initstr += 3;
1592
1593    /* Catch "[r][g]vimdiff" and "[r][g]viewdiff". */
1594    if (STRICMP(initstr, "diff") == 0)
1595    {
1596#ifdef FEAT_DIFF
1597	parmp->diff_mode = TRUE;
1598#else
1599	mch_errmsg(_("This Vim was not compiled with the diff feature."));
1600	mch_errmsg("\n");
1601	mch_exit(2);
1602#endif
1603    }
1604
1605    if (STRNICMP(initstr, "ex", 2) == 0)
1606    {
1607	if (STRNICMP(initstr + 2, "im", 2) == 0)
1608	    exmode_active = EXMODE_VIM;
1609	else
1610	    exmode_active = EXMODE_NORMAL;
1611	change_compatible(TRUE);	/* set 'compatible' */
1612    }
1613}
1614
1615/*
1616 * Get the name of the display, before gui_prepare() removes it from
1617 * argv[].  Used for the xterm-clipboard display.
1618 *
1619 * Also find the --server... arguments and --socketid and --windowid
1620 */
1621    static void
1622early_arg_scan(parmp)
1623    mparm_T	*parmp UNUSED;
1624{
1625#if defined(FEAT_XCLIPBOARD) || defined(FEAT_CLIENTSERVER) \
1626	|| !defined(FEAT_NETBEANS_INTG)
1627    int		argc = parmp->argc;
1628    char	**argv = parmp->argv;
1629    int		i;
1630
1631    for (i = 1; i < argc; i++)
1632    {
1633	if (STRCMP(argv[i], "--") == 0)
1634	    break;
1635# ifdef FEAT_XCLIPBOARD
1636	else if (STRICMP(argv[i], "-display") == 0
1637#  if defined(FEAT_GUI_GTK)
1638		|| STRICMP(argv[i], "--display") == 0
1639#  endif
1640		)
1641	{
1642	    if (i == argc - 1)
1643		mainerr_arg_missing((char_u *)argv[i]);
1644	    xterm_display = argv[++i];
1645	}
1646# endif
1647# ifdef FEAT_CLIENTSERVER
1648	else if (STRICMP(argv[i], "--servername") == 0)
1649	{
1650	    if (i == argc - 1)
1651		mainerr_arg_missing((char_u *)argv[i]);
1652	    parmp->serverName_arg = (char_u *)argv[++i];
1653	}
1654	else if (STRICMP(argv[i], "--serverlist") == 0)
1655	    parmp->serverArg = TRUE;
1656	else if (STRNICMP(argv[i], "--remote", 8) == 0)
1657	{
1658	    parmp->serverArg = TRUE;
1659#  ifdef FEAT_GUI
1660	    if (strstr(argv[i], "-wait") != 0)
1661		/* don't fork() when starting the GUI to edit files ourself */
1662		gui.dofork = FALSE;
1663#  endif
1664	}
1665# endif
1666
1667# if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_W32)
1668#  ifdef FEAT_GUI_W32
1669	else if (STRICMP(argv[i], "--windowid") == 0)
1670#  else
1671	else if (STRICMP(argv[i], "--socketid") == 0)
1672#  endif
1673	{
1674	    long_u	id;
1675	    int		count;
1676
1677	    if (i == argc - 1)
1678		mainerr_arg_missing((char_u *)argv[i]);
1679	    if (STRNICMP(argv[i+1], "0x", 2) == 0)
1680		count = sscanf(&(argv[i + 1][2]), SCANF_HEX_LONG_U, &id);
1681	    else
1682		count = sscanf(argv[i + 1], SCANF_DECIMAL_LONG_U, &id);
1683	    if (count != 1)
1684		mainerr(ME_INVALID_ARG, (char_u *)argv[i]);
1685	    else
1686#  ifdef FEAT_GUI_W32
1687		win_socket_id = id;
1688#  else
1689		gtk_socket_id = id;
1690#  endif
1691	    i++;
1692	}
1693# endif
1694# ifdef FEAT_GUI_GTK
1695	else if (STRICMP(argv[i], "--echo-wid") == 0)
1696	    echo_wid_arg = TRUE;
1697# endif
1698# ifndef FEAT_NETBEANS_INTG
1699	else if (strncmp(argv[i], "-nb", (size_t)3) == 0)
1700	{
1701	    mch_errmsg(_("'-nb' cannot be used: not enabled at compile time\n"));
1702	    mch_exit(2);
1703	}
1704# endif
1705
1706    }
1707#endif
1708}
1709
1710/*
1711 * Scan the command line arguments.
1712 */
1713    static void
1714command_line_scan(parmp)
1715    mparm_T	*parmp;
1716{
1717    int		argc = parmp->argc;
1718    char	**argv = parmp->argv;
1719    int		argv_idx;		/* index in argv[n][] */
1720    int		had_minmin = FALSE;	/* found "--" argument */
1721    int		want_argument;		/* option argument with argument */
1722    int		c;
1723    char_u	*p = NULL;
1724    long	n;
1725
1726    --argc;
1727    ++argv;
1728    argv_idx = 1;	    /* active option letter is argv[0][argv_idx] */
1729    while (argc > 0)
1730    {
1731	/*
1732	 * "+" or "+{number}" or "+/{pat}" or "+{command}" argument.
1733	 */
1734	if (argv[0][0] == '+' && !had_minmin)
1735	{
1736	    if (parmp->n_commands >= MAX_ARG_CMDS)
1737		mainerr(ME_EXTRA_CMD, NULL);
1738	    argv_idx = -1;	    /* skip to next argument */
1739	    if (argv[0][1] == NUL)
1740		parmp->commands[parmp->n_commands++] = (char_u *)"$";
1741	    else
1742		parmp->commands[parmp->n_commands++] = (char_u *)&(argv[0][1]);
1743	}
1744
1745	/*
1746	 * Optional argument.
1747	 */
1748	else if (argv[0][0] == '-' && !had_minmin)
1749	{
1750	    want_argument = FALSE;
1751	    c = argv[0][argv_idx++];
1752#ifdef VMS
1753	    /*
1754	     * VMS only uses upper case command lines.  Interpret "-X" as "-x"
1755	     * and "-/X" as "-X".
1756	     */
1757	    if (c == '/')
1758	    {
1759		c = argv[0][argv_idx++];
1760		c = TOUPPER_ASC(c);
1761	    }
1762	    else
1763		c = TOLOWER_ASC(c);
1764#endif
1765	    switch (c)
1766	    {
1767	    case NUL:		/* "vim -"  read from stdin */
1768				/* "ex -" silent mode */
1769		if (exmode_active)
1770		    silent_mode = TRUE;
1771		else
1772		{
1773		    if (parmp->edit_type != EDIT_NONE)
1774			mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]);
1775		    parmp->edit_type = EDIT_STDIN;
1776		    read_cmd_fd = 2;	/* read from stderr instead of stdin */
1777		}
1778		argv_idx = -1;		/* skip to next argument */
1779		break;
1780
1781	    case '-':		/* "--" don't take any more option arguments */
1782				/* "--help" give help message */
1783				/* "--version" give version message */
1784				/* "--literal" take files literally */
1785				/* "--nofork" don't fork */
1786				/* "--noplugin[s]" skip plugins */
1787				/* "--cmd <cmd>" execute cmd before vimrc */
1788		if (STRICMP(argv[0] + argv_idx, "help") == 0)
1789		    usage();
1790		else if (STRICMP(argv[0] + argv_idx, "version") == 0)
1791		{
1792		    Columns = 80;	/* need to init Columns */
1793		    info_message = TRUE; /* use mch_msg(), not mch_errmsg() */
1794		    list_version();
1795		    msg_putchar('\n');
1796		    msg_didout = FALSE;
1797		    mch_exit(0);
1798		}
1799		else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0)
1800		{
1801#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE)
1802		    parmp->literal = TRUE;
1803#endif
1804		}
1805		else if (STRNICMP(argv[0] + argv_idx, "nofork", 6) == 0)
1806		{
1807#ifdef FEAT_GUI
1808		    gui.dofork = FALSE;	/* don't fork() when starting GUI */
1809#endif
1810		}
1811		else if (STRNICMP(argv[0] + argv_idx, "noplugin", 8) == 0)
1812		    p_lpl = FALSE;
1813		else if (STRNICMP(argv[0] + argv_idx, "cmd", 3) == 0)
1814		{
1815		    want_argument = TRUE;
1816		    argv_idx += 3;
1817		}
1818		else if (STRNICMP(argv[0] + argv_idx, "startuptime", 11) == 0)
1819		{
1820		    want_argument = TRUE;
1821		    argv_idx += 11;
1822		}
1823#ifdef FEAT_CLIENTSERVER
1824		else if (STRNICMP(argv[0] + argv_idx, "serverlist", 10) == 0)
1825		    ; /* already processed -- no arg */
1826		else if (STRNICMP(argv[0] + argv_idx, "servername", 10) == 0
1827		       || STRNICMP(argv[0] + argv_idx, "serversend", 10) == 0)
1828		{
1829		    /* already processed -- snatch the following arg */
1830		    if (argc > 1)
1831		    {
1832			--argc;
1833			++argv;
1834		    }
1835		}
1836#endif
1837#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_W32)
1838# ifdef FEAT_GUI_GTK
1839		else if (STRNICMP(argv[0] + argv_idx, "socketid", 8) == 0)
1840# else
1841		else if (STRNICMP(argv[0] + argv_idx, "windowid", 8) == 0)
1842# endif
1843		{
1844		    /* already processed -- snatch the following arg */
1845		    if (argc > 1)
1846		    {
1847			--argc;
1848			++argv;
1849		    }
1850		}
1851#endif
1852#ifdef FEAT_GUI_GTK
1853		else if (STRNICMP(argv[0] + argv_idx, "echo-wid", 8) == 0)
1854		{
1855		    /* already processed, skip */
1856		}
1857#endif
1858		else
1859		{
1860		    if (argv[0][argv_idx])
1861			mainerr(ME_UNKNOWN_OPTION, (char_u *)argv[0]);
1862		    had_minmin = TRUE;
1863		}
1864		if (!want_argument)
1865		    argv_idx = -1;	/* skip to next argument */
1866		break;
1867
1868	    case 'A':		/* "-A" start in Arabic mode */
1869#ifdef FEAT_ARABIC
1870		set_option_value((char_u *)"arabic", 1L, NULL, 0);
1871#else
1872		mch_errmsg(_(e_noarabic));
1873		mch_exit(2);
1874#endif
1875		break;
1876
1877	    case 'b':		/* "-b" binary mode */
1878		/* Needs to be effective before expanding file names, because
1879		 * for Win32 this makes us edit a shortcut file itself,
1880		 * instead of the file it links to. */
1881		set_options_bin(curbuf->b_p_bin, 1, 0);
1882		curbuf->b_p_bin = 1;	    /* binary file I/O */
1883		break;
1884
1885	    case 'C':		/* "-C"  Compatible */
1886		change_compatible(TRUE);
1887		break;
1888
1889	    case 'e':		/* "-e" Ex mode */
1890		exmode_active = EXMODE_NORMAL;
1891		break;
1892
1893	    case 'E':		/* "-E" Improved Ex mode */
1894		exmode_active = EXMODE_VIM;
1895		break;
1896
1897	    case 'f':		/* "-f"  GUI: run in foreground.  Amiga: open
1898				window directly, not with newcli */
1899#ifdef FEAT_GUI
1900		gui.dofork = FALSE;	/* don't fork() when starting GUI */
1901#endif
1902		break;
1903
1904	    case 'g':		/* "-g" start GUI */
1905		main_start_gui();
1906		break;
1907
1908	    case 'F':		/* "-F" start in Farsi mode: rl + fkmap set */
1909#ifdef FEAT_FKMAP
1910		p_fkmap = TRUE;
1911		set_option_value((char_u *)"rl", 1L, NULL, 0);
1912#else
1913		mch_errmsg(_(e_nofarsi));
1914		mch_exit(2);
1915#endif
1916		break;
1917
1918	    case 'h':		/* "-h" give help message */
1919#ifdef FEAT_GUI_GNOME
1920		/* Tell usage() to exit for "gvim". */
1921		gui.starting = FALSE;
1922#endif
1923		usage();
1924		break;
1925
1926	    case 'H':		/* "-H" start in Hebrew mode: rl + hkmap set */
1927#ifdef FEAT_RIGHTLEFT
1928		p_hkmap = TRUE;
1929		set_option_value((char_u *)"rl", 1L, NULL, 0);
1930#else
1931		mch_errmsg(_(e_nohebrew));
1932		mch_exit(2);
1933#endif
1934		break;
1935
1936	    case 'l':		/* "-l" lisp mode, 'lisp' and 'showmatch' on */
1937#ifdef FEAT_LISP
1938		set_option_value((char_u *)"lisp", 1L, NULL, 0);
1939		p_sm = TRUE;
1940#endif
1941		break;
1942
1943	    case 'M':		/* "-M"  no changes or writing of files */
1944		reset_modifiable();
1945		/* FALLTHROUGH */
1946
1947	    case 'm':		/* "-m"  no writing of files */
1948		p_write = FALSE;
1949		break;
1950
1951	    case 'y':		/* "-y"  easy mode */
1952#ifdef FEAT_GUI
1953		gui.starting = TRUE;	/* start GUI a bit later */
1954#endif
1955		parmp->evim_mode = TRUE;
1956		break;
1957
1958	    case 'N':		/* "-N"  Nocompatible */
1959		change_compatible(FALSE);
1960		break;
1961
1962	    case 'n':		/* "-n" no swap file */
1963#ifdef FEAT_NETBEANS_INTG
1964		/* checking for "-nb", netbeans parameters */
1965		if (argv[0][argv_idx] == 'b')
1966		{
1967		    netbeansArg = argv[0];
1968		    argv_idx = -1;	    /* skip to next argument */
1969		}
1970		else
1971#endif
1972		parmp->no_swap_file = TRUE;
1973		break;
1974
1975	    case 'p':		/* "-p[N]" open N tab pages */
1976#ifdef TARGET_API_MAC_OSX
1977		/* For some reason on MacOS X, an argument like:
1978		   -psn_0_10223617 is passed in when invoke from Finder
1979		   or with the 'open' command */
1980		if (argv[0][argv_idx] == 's')
1981		{
1982		    argv_idx = -1; /* bypass full -psn */
1983		    main_start_gui();
1984		    break;
1985		}
1986#endif
1987#ifdef FEAT_WINDOWS
1988		/* default is 0: open window for each file */
1989		parmp->window_count = get_number_arg((char_u *)argv[0],
1990								&argv_idx, 0);
1991		parmp->window_layout = WIN_TABS;
1992#endif
1993		break;
1994
1995	    case 'o':		/* "-o[N]" open N horizontal split windows */
1996#ifdef FEAT_WINDOWS
1997		/* default is 0: open window for each file */
1998		parmp->window_count = get_number_arg((char_u *)argv[0],
1999								&argv_idx, 0);
2000		parmp->window_layout = WIN_HOR;
2001#endif
2002		break;
2003
2004		case 'O':	/* "-O[N]" open N vertical split windows */
2005#if defined(FEAT_VERTSPLIT) && defined(FEAT_WINDOWS)
2006		/* default is 0: open window for each file */
2007		parmp->window_count = get_number_arg((char_u *)argv[0],
2008								&argv_idx, 0);
2009		parmp->window_layout = WIN_VER;
2010#endif
2011		break;
2012
2013#ifdef FEAT_QUICKFIX
2014	    case 'q':		/* "-q" QuickFix mode */
2015		if (parmp->edit_type != EDIT_NONE)
2016		    mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]);
2017		parmp->edit_type = EDIT_QF;
2018		if (argv[0][argv_idx])		/* "-q{errorfile}" */
2019		{
2020		    parmp->use_ef = (char_u *)argv[0] + argv_idx;
2021		    argv_idx = -1;
2022		}
2023		else if (argc > 1)		/* "-q {errorfile}" */
2024		    want_argument = TRUE;
2025		break;
2026#endif
2027
2028	    case 'R':		/* "-R" readonly mode */
2029		readonlymode = TRUE;
2030		curbuf->b_p_ro = TRUE;
2031		p_uc = 10000;			/* don't update very often */
2032		break;
2033
2034	    case 'r':		/* "-r" recovery mode */
2035	    case 'L':		/* "-L" recovery mode */
2036		recoverymode = 1;
2037		break;
2038
2039	    case 's':
2040		if (exmode_active)	/* "-s" silent (batch) mode */
2041		    silent_mode = TRUE;
2042		else		/* "-s {scriptin}" read from script file */
2043		    want_argument = TRUE;
2044		break;
2045
2046	    case 't':		/* "-t {tag}" or "-t{tag}" jump to tag */
2047		if (parmp->edit_type != EDIT_NONE)
2048		    mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]);
2049		parmp->edit_type = EDIT_TAG;
2050		if (argv[0][argv_idx])		/* "-t{tag}" */
2051		{
2052		    parmp->tagname = (char_u *)argv[0] + argv_idx;
2053		    argv_idx = -1;
2054		}
2055		else				/* "-t {tag}" */
2056		    want_argument = TRUE;
2057		break;
2058
2059#ifdef FEAT_EVAL
2060	    case 'D':		/* "-D"		Debugging */
2061		parmp->use_debug_break_level = 9999;
2062		break;
2063#endif
2064#ifdef FEAT_DIFF
2065	    case 'd':		/* "-d"		'diff' */
2066# ifdef AMIGA
2067		/* check for "-dev {device}" */
2068		if (argv[0][argv_idx] == 'e' && argv[0][argv_idx + 1] == 'v')
2069		    want_argument = TRUE;
2070		else
2071# endif
2072		    parmp->diff_mode = TRUE;
2073		break;
2074#endif
2075	    case 'V':		/* "-V{N}"	Verbose level */
2076		/* default is 10: a little bit verbose */
2077		p_verbose = get_number_arg((char_u *)argv[0], &argv_idx, 10);
2078		if (argv[0][argv_idx] != NUL)
2079		{
2080		    set_option_value((char_u *)"verbosefile", 0L,
2081					     (char_u *)argv[0] + argv_idx, 0);
2082		    argv_idx = (int)STRLEN(argv[0]);
2083		}
2084		break;
2085
2086	    case 'v':		/* "-v"  Vi-mode (as if called "vi") */
2087		exmode_active = 0;
2088#ifdef FEAT_GUI
2089		gui.starting = FALSE;	/* don't start GUI */
2090#endif
2091		break;
2092
2093	    case 'w':		/* "-w{number}"	set window height */
2094				/* "-w {scriptout}"	write to script */
2095		if (vim_isdigit(((char_u *)argv[0])[argv_idx]))
2096		{
2097		    n = get_number_arg((char_u *)argv[0], &argv_idx, 10);
2098		    set_option_value((char_u *)"window", n, NULL, 0);
2099		    p_window = p_window_unix2003;
2100		    break;
2101		}
2102		want_argument = TRUE;
2103		break;
2104
2105#ifdef FEAT_CRYPT
2106	    case 'x':		/* "-x"  encrypted reading/writing of files */
2107		parmp->ask_for_key = TRUE;
2108		break;
2109#endif
2110
2111	    case 'X':		/* "-X"  don't connect to X server */
2112#if (defined(UNIX) || defined(VMS)) && defined(FEAT_X11)
2113		x_no_connect = TRUE;
2114#endif
2115		break;
2116
2117	    case 'Z':		/* "-Z"  restricted mode */
2118		restricted = TRUE;
2119		break;
2120
2121	    case 'c':		/* "-c{command}" or "-c {command}" execute
2122				   command */
2123		if (argv[0][argv_idx] != NUL)
2124		{
2125		    if (parmp->n_commands >= MAX_ARG_CMDS)
2126			mainerr(ME_EXTRA_CMD, NULL);
2127		    parmp->commands[parmp->n_commands++] = (char_u *)argv[0]
2128								   + argv_idx;
2129		    argv_idx = -1;
2130		    break;
2131		}
2132		/*FALLTHROUGH*/
2133	    case 'S':		/* "-S {file}" execute Vim script */
2134	    case 'i':		/* "-i {viminfo}" use for viminfo */
2135#ifndef FEAT_DIFF
2136	    case 'd':		/* "-d {device}" device (for Amiga) */
2137#endif
2138	    case 'T':		/* "-T {terminal}" terminal name */
2139	    case 'u':		/* "-u {vimrc}" vim inits file */
2140	    case 'U':		/* "-U {gvimrc}" gvim inits file */
2141	    case 'W':		/* "-W {scriptout}" overwrite */
2142#ifdef FEAT_GUI_W32
2143	    case 'P':		/* "-P {parent title}" MDI parent */
2144#endif
2145		want_argument = TRUE;
2146		break;
2147
2148	    default:
2149		mainerr(ME_UNKNOWN_OPTION, (char_u *)argv[0]);
2150	    }
2151
2152	    /*
2153	     * Handle option arguments with argument.
2154	     */
2155	    if (want_argument)
2156	    {
2157		/*
2158		 * Check for garbage immediately after the option letter.
2159		 */
2160		if (argv[0][argv_idx] != NUL)
2161		    mainerr(ME_GARBAGE, (char_u *)argv[0]);
2162
2163		--argc;
2164		if (argc < 1 && c != 'S')  /* -S has an optional argument */
2165		    mainerr_arg_missing((char_u *)argv[0]);
2166		++argv;
2167		argv_idx = -1;
2168
2169		switch (c)
2170		{
2171		case 'c':	/* "-c {command}" execute command */
2172		case 'S':	/* "-S {file}" execute Vim script */
2173		    if (parmp->n_commands >= MAX_ARG_CMDS)
2174			mainerr(ME_EXTRA_CMD, NULL);
2175		    if (c == 'S')
2176		    {
2177			char	*a;
2178
2179			if (argc < 1)
2180			    /* "-S" without argument: use default session file
2181			     * name. */
2182			    a = SESSION_FILE;
2183			else if (argv[0][0] == '-')
2184			{
2185			    /* "-S" followed by another option: use default
2186			     * session file name. */
2187			    a = SESSION_FILE;
2188			    ++argc;
2189			    --argv;
2190			}
2191			else
2192			    a = argv[0];
2193			p = alloc((unsigned)(STRLEN(a) + 4));
2194			if (p == NULL)
2195			    mch_exit(2);
2196			sprintf((char *)p, "so %s", a);
2197			parmp->cmds_tofree[parmp->n_commands] = TRUE;
2198			parmp->commands[parmp->n_commands++] = p;
2199		    }
2200		    else
2201			parmp->commands[parmp->n_commands++] =
2202							    (char_u *)argv[0];
2203		    break;
2204
2205		case '-':
2206		    if (argv[-1][2] == 'c')
2207		    {
2208			/* "--cmd {command}" execute command */
2209			if (parmp->n_pre_commands >= MAX_ARG_CMDS)
2210			    mainerr(ME_EXTRA_CMD, NULL);
2211			parmp->pre_commands[parmp->n_pre_commands++] =
2212							    (char_u *)argv[0];
2213		    }
2214		    /* "--startuptime <file>" already handled */
2215		    break;
2216
2217	    /*	case 'd':   -d {device} is handled in mch_check_win() for the
2218	     *		    Amiga */
2219
2220#ifdef FEAT_QUICKFIX
2221		case 'q':	/* "-q {errorfile}" QuickFix mode */
2222		    parmp->use_ef = (char_u *)argv[0];
2223		    break;
2224#endif
2225
2226		case 'i':	/* "-i {viminfo}" use for viminfo */
2227		    use_viminfo = (char_u *)argv[0];
2228		    break;
2229
2230		case 's':	/* "-s {scriptin}" read from script file */
2231		    if (scriptin[0] != NULL)
2232		    {
2233scripterror:
2234			mch_errmsg(_("Attempt to open script file again: \""));
2235			mch_errmsg(argv[-1]);
2236			mch_errmsg(" ");
2237			mch_errmsg(argv[0]);
2238			mch_errmsg("\"\n");
2239			mch_exit(2);
2240		    }
2241		    if ((scriptin[0] = mch_fopen(argv[0], READBIN)) == NULL)
2242		    {
2243			mch_errmsg(_("Cannot open for reading: \""));
2244			mch_errmsg(argv[0]);
2245			mch_errmsg("\"\n");
2246			mch_exit(2);
2247		    }
2248		    if (save_typebuf() == FAIL)
2249			mch_exit(2);	/* out of memory */
2250		    break;
2251
2252		case 't':	/* "-t {tag}" */
2253		    parmp->tagname = (char_u *)argv[0];
2254		    break;
2255
2256		case 'T':	/* "-T {terminal}" terminal name */
2257		    /*
2258		     * The -T term argument is always available and when
2259		     * HAVE_TERMLIB is supported it overrides the environment
2260		     * variable TERM.
2261		     */
2262#ifdef FEAT_GUI
2263		    if (term_is_gui((char_u *)argv[0]))
2264			gui.starting = TRUE;	/* start GUI a bit later */
2265		    else
2266#endif
2267			parmp->term = (char_u *)argv[0];
2268		    break;
2269
2270		case 'u':	/* "-u {vimrc}" vim inits file */
2271		    parmp->use_vimrc = (char_u *)argv[0];
2272		    break;
2273
2274		case 'U':	/* "-U {gvimrc}" gvim inits file */
2275#ifdef FEAT_GUI
2276		    use_gvimrc = (char_u *)argv[0];
2277#endif
2278		    break;
2279
2280		case 'w':	/* "-w {nr}" 'window' value */
2281				/* "-w {scriptout}" append to script file */
2282		    if (vim_isdigit(*((char_u *)argv[0])))
2283		    {
2284			argv_idx = 0;
2285			n = get_number_arg((char_u *)argv[0], &argv_idx, 10);
2286			set_option_value((char_u *)"window", n, NULL, 0);
2287			p_window = p_window_unix2003;
2288			argv_idx = -1;
2289			break;
2290		    }
2291		    /*FALLTHROUGH*/
2292		case 'W':	/* "-W {scriptout}" overwrite script file */
2293		    if (scriptout != NULL)
2294			goto scripterror;
2295		    if ((scriptout = mch_fopen(argv[0],
2296				    c == 'w' ? APPENDBIN : WRITEBIN)) == NULL)
2297		    {
2298			mch_errmsg(_("Cannot open for script output: \""));
2299			mch_errmsg(argv[0]);
2300			mch_errmsg("\"\n");
2301			mch_exit(2);
2302		    }
2303		    break;
2304
2305#ifdef FEAT_GUI_W32
2306		case 'P':		/* "-P {parent title}" MDI parent */
2307		    gui_mch_set_parent(argv[0]);
2308		    break;
2309#endif
2310		}
2311	    }
2312	}
2313
2314	/*
2315	 * File name argument.
2316	 */
2317	else
2318	{
2319	    argv_idx = -1;	    /* skip to next argument */
2320
2321	    /* Check for only one type of editing. */
2322	    if (parmp->edit_type != EDIT_NONE && parmp->edit_type != EDIT_FILE)
2323		mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]);
2324	    parmp->edit_type = EDIT_FILE;
2325
2326#ifdef MSWIN
2327	    /* Remember if the argument was a full path before changing
2328	     * slashes to backslashes. */
2329	    if (argv[0][0] != NUL && argv[0][1] == ':' && argv[0][2] == '\\')
2330		parmp->full_path = TRUE;
2331#endif
2332
2333	    /* Add the file to the global argument list. */
2334	    if (ga_grow(&global_alist.al_ga, 1) == FAIL
2335		    || (p = vim_strsave((char_u *)argv[0])) == NULL)
2336		mch_exit(2);
2337#ifdef FEAT_DIFF
2338	    if (parmp->diff_mode && mch_isdir(p) && GARGCOUNT > 0
2339				      && !mch_isdir(alist_name(&GARGLIST[0])))
2340	    {
2341		char_u	    *r;
2342
2343		r = concat_fnames(p, gettail(alist_name(&GARGLIST[0])), TRUE);
2344		if (r != NULL)
2345		{
2346		    vim_free(p);
2347		    p = r;
2348		}
2349	    }
2350#endif
2351#if defined(__CYGWIN32__) && !defined(WIN32)
2352	    /*
2353	     * If vim is invoked by non-Cygwin tools, convert away any
2354	     * DOS paths, so things like .swp files are created correctly.
2355	     * Look for evidence of non-Cygwin paths before we bother.
2356	     * This is only for when using the Unix files.
2357	     */
2358	    if (strpbrk(p, "\\:") != NULL && !path_with_url(p))
2359	    {
2360		char posix_path[PATH_MAX];
2361
2362# if CYGWIN_VERSION_DLL_MAJOR >= 1007
2363		cygwin_conv_path(CCP_WIN_A_TO_POSIX, p, posix_path, PATH_MAX);
2364# else
2365		cygwin_conv_to_posix_path(p, posix_path);
2366# endif
2367		vim_free(p);
2368		p = vim_strsave(posix_path);
2369		if (p == NULL)
2370		    mch_exit(2);
2371	    }
2372#endif
2373
2374#ifdef USE_FNAME_CASE
2375	    /* Make the case of the file name match the actual file. */
2376	    fname_case(p, 0);
2377#endif
2378
2379	    alist_add(&global_alist, p,
2380#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE)
2381		    parmp->literal ? 2 : 0	/* add buffer nr after exp. */
2382#else
2383		    2		/* add buffer number now and use curbuf */
2384#endif
2385		    );
2386
2387#if defined(FEAT_MBYTE) && defined(WIN32)
2388	    {
2389		/* Remember this argument has been added to the argument list.
2390		 * Needed when 'encoding' is changed. */
2391		used_file_arg(argv[0], parmp->literal, parmp->full_path,
2392# ifdef FEAT_DIFF
2393							    parmp->diff_mode
2394# else
2395							    FALSE
2396# endif
2397							    );
2398	    }
2399#endif
2400	}
2401
2402	/*
2403	 * If there are no more letters after the current "-", go to next
2404	 * argument.  argv_idx is set to -1 when the current argument is to be
2405	 * skipped.
2406	 */
2407	if (argv_idx <= 0 || argv[0][argv_idx] == NUL)
2408	{
2409	    --argc;
2410	    ++argv;
2411	    argv_idx = 1;
2412	}
2413    }
2414
2415#ifdef FEAT_EVAL
2416    /* If there is a "+123" or "-c" command, set v:swapcommand to the first
2417     * one. */
2418    if (parmp->n_commands > 0)
2419    {
2420	p = alloc((unsigned)STRLEN(parmp->commands[0]) + 3);
2421	if (p != NULL)
2422	{
2423	    sprintf((char *)p, ":%s\r", parmp->commands[0]);
2424	    set_vim_var_string(VV_SWAPCOMMAND, p, -1);
2425	    vim_free(p);
2426	}
2427    }
2428#endif
2429}
2430
2431/*
2432 * Print a warning if stdout is not a terminal.
2433 * When starting in Ex mode and commands come from a file, set Silent mode.
2434 */
2435    static void
2436check_tty(parmp)
2437    mparm_T	*parmp;
2438{
2439    int		input_isatty;		/* is active input a terminal? */
2440
2441    input_isatty = mch_input_isatty();
2442    if (exmode_active)
2443    {
2444	if (!input_isatty)
2445	    silent_mode = TRUE;
2446    }
2447    else if (parmp->want_full_screen && (!parmp->stdout_isatty || !input_isatty)
2448#ifdef FEAT_GUI
2449	    /* don't want the delay when started from the desktop */
2450	    && !gui.starting
2451#endif
2452	    )
2453    {
2454#ifdef NBDEBUG
2455	/*
2456	 * This shouldn't be necessary. But if I run netbeans with the log
2457	 * output coming to the console and XOpenDisplay fails, I get vim
2458	 * trying to start with input/output to my console tty.  This fills my
2459	 * input buffer so fast I can't even kill the process in under 2
2460	 * minutes (and it beeps continuously the whole time :-)
2461	 */
2462	if (netbeans_active() && (!parmp->stdout_isatty || !input_isatty))
2463	{
2464	    mch_errmsg(_("Vim: Error: Failure to start gvim from NetBeans\n"));
2465	    exit(1);
2466	}
2467#endif
2468	if (!parmp->stdout_isatty)
2469	    mch_errmsg(_("Vim: Warning: Output is not to a terminal\n"));
2470	if (!input_isatty)
2471	    mch_errmsg(_("Vim: Warning: Input is not from a terminal\n"));
2472	out_flush();
2473	if (scriptin[0] == NULL)
2474	    ui_delay(2000L, TRUE);
2475	TIME_MSG("Warning delay");
2476    }
2477}
2478
2479/*
2480 * Read text from stdin.
2481 */
2482    static void
2483read_stdin()
2484{
2485    int	    i;
2486
2487#if defined(HAS_SWAP_EXISTS_ACTION)
2488    /* When getting the ATTENTION prompt here, use a dialog */
2489    swap_exists_action = SEA_DIALOG;
2490#endif
2491    no_wait_return = TRUE;
2492    i = msg_didany;
2493    set_buflisted(TRUE);
2494    (void)open_buffer(TRUE, NULL, 0);	/* create memfile and read file */
2495    no_wait_return = FALSE;
2496    msg_didany = i;
2497    TIME_MSG("reading stdin");
2498#if defined(HAS_SWAP_EXISTS_ACTION)
2499    check_swap_exists_action();
2500#endif
2501#if !(defined(AMIGA) || defined(MACOS))
2502    /*
2503     * Close stdin and dup it from stderr.  Required for GPM to work
2504     * properly, and for running external commands.
2505     * Is there any other system that cannot do this?
2506     */
2507    close(0);
2508    ignored = dup(2);
2509#endif
2510}
2511
2512/*
2513 * Create the requested number of windows and edit buffers in them.
2514 * Also does recovery if "recoverymode" set.
2515 */
2516    static void
2517create_windows(parmp)
2518    mparm_T	*parmp UNUSED;
2519{
2520#ifdef FEAT_WINDOWS
2521    int		dorewind;
2522    int		done = 0;
2523
2524    /*
2525     * Create the number of windows that was requested.
2526     */
2527    if (parmp->window_count == -1)	/* was not set */
2528	parmp->window_count = 1;
2529    if (parmp->window_count == 0)
2530	parmp->window_count = GARGCOUNT;
2531    if (parmp->window_count > 1)
2532    {
2533	/* Don't change the windows if there was a command in .vimrc that
2534	 * already split some windows */
2535	if (parmp->window_layout == 0)
2536	    parmp->window_layout = WIN_HOR;
2537	if (parmp->window_layout == WIN_TABS)
2538	{
2539	    parmp->window_count = make_tabpages(parmp->window_count);
2540	    TIME_MSG("making tab pages");
2541	}
2542	else if (firstwin->w_next == NULL)
2543	{
2544	    parmp->window_count = make_windows(parmp->window_count,
2545					     parmp->window_layout == WIN_VER);
2546	    TIME_MSG("making windows");
2547	}
2548	else
2549	    parmp->window_count = win_count();
2550    }
2551    else
2552	parmp->window_count = 1;
2553#endif
2554
2555    if (recoverymode)			/* do recover */
2556    {
2557	msg_scroll = TRUE;		/* scroll message up */
2558	ml_recover();
2559	if (curbuf->b_ml.ml_mfp == NULL) /* failed */
2560	    getout(1);
2561	do_modelines(0);		/* do modelines */
2562    }
2563    else
2564    {
2565	/*
2566	 * Open a buffer for windows that don't have one yet.
2567	 * Commands in the .vimrc might have loaded a file or split the window.
2568	 * Watch out for autocommands that delete a window.
2569	 */
2570#ifdef FEAT_AUTOCMD
2571	/*
2572	 * Don't execute Win/Buf Enter/Leave autocommands here
2573	 */
2574	++autocmd_no_enter;
2575	++autocmd_no_leave;
2576#endif
2577#ifdef FEAT_WINDOWS
2578	dorewind = TRUE;
2579	while (done++ < 1000)
2580	{
2581	    if (dorewind)
2582	    {
2583		if (parmp->window_layout == WIN_TABS)
2584		    goto_tabpage(1);
2585		else
2586		    curwin = firstwin;
2587	    }
2588	    else if (parmp->window_layout == WIN_TABS)
2589	    {
2590		if (curtab->tp_next == NULL)
2591		    break;
2592		goto_tabpage(0);
2593	    }
2594	    else
2595	    {
2596		if (curwin->w_next == NULL)
2597		    break;
2598		curwin = curwin->w_next;
2599	    }
2600	    dorewind = FALSE;
2601#endif
2602	    curbuf = curwin->w_buffer;
2603	    if (curbuf->b_ml.ml_mfp == NULL)
2604	    {
2605#ifdef FEAT_FOLDING
2606		/* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */
2607		if (p_fdls >= 0)
2608		    curwin->w_p_fdl = p_fdls;
2609#endif
2610#if defined(HAS_SWAP_EXISTS_ACTION)
2611		/* When getting the ATTENTION prompt here, use a dialog */
2612		swap_exists_action = SEA_DIALOG;
2613#endif
2614		set_buflisted(TRUE);
2615
2616		/* create memfile, read file */
2617		(void)open_buffer(FALSE, NULL, 0);
2618
2619#if defined(HAS_SWAP_EXISTS_ACTION)
2620		if (swap_exists_action == SEA_QUIT)
2621		{
2622		    if (got_int || only_one_window())
2623		    {
2624			/* abort selected or quit and only one window */
2625			did_emsg = FALSE;   /* avoid hit-enter prompt */
2626			getout(1);
2627		    }
2628		    /* We can't close the window, it would disturb what
2629		     * happens next.  Clear the file name and set the arg
2630		     * index to -1 to delete it later. */
2631		    setfname(curbuf, NULL, NULL, FALSE);
2632		    curwin->w_arg_idx = -1;
2633		    swap_exists_action = SEA_NONE;
2634		}
2635		else
2636		    handle_swap_exists(NULL);
2637#endif
2638#ifdef FEAT_AUTOCMD
2639		dorewind = TRUE;		/* start again */
2640#endif
2641	    }
2642#ifdef FEAT_WINDOWS
2643	    ui_breakcheck();
2644	    if (got_int)
2645	    {
2646		(void)vgetc();	/* only break the file loading, not the rest */
2647		break;
2648	    }
2649	}
2650#endif
2651#ifdef FEAT_WINDOWS
2652	if (parmp->window_layout == WIN_TABS)
2653	    goto_tabpage(1);
2654	else
2655	    curwin = firstwin;
2656	curbuf = curwin->w_buffer;
2657#endif
2658#ifdef FEAT_AUTOCMD
2659	--autocmd_no_enter;
2660	--autocmd_no_leave;
2661#endif
2662    }
2663}
2664
2665#ifdef FEAT_WINDOWS
2666    /*
2667     * If opened more than one window, start editing files in the other
2668     * windows.  make_windows() has already opened the windows.
2669     */
2670    static void
2671edit_buffers(parmp)
2672    mparm_T	*parmp;
2673{
2674    int		arg_idx;		/* index in argument list */
2675    int		i;
2676    int		advance = TRUE;
2677
2678# ifdef FEAT_AUTOCMD
2679    /*
2680     * Don't execute Win/Buf Enter/Leave autocommands here
2681     */
2682    ++autocmd_no_enter;
2683    ++autocmd_no_leave;
2684# endif
2685
2686    /* When w_arg_idx is -1 remove the window (see create_windows()). */
2687    if (curwin->w_arg_idx == -1)
2688    {
2689	win_close(curwin, TRUE);
2690	advance = FALSE;
2691    }
2692
2693    arg_idx = 1;
2694    for (i = 1; i < parmp->window_count; ++i)
2695    {
2696	/* When w_arg_idx is -1 remove the window (see create_windows()). */
2697	if (curwin->w_arg_idx == -1)
2698	{
2699	    ++arg_idx;
2700	    win_close(curwin, TRUE);
2701	    advance = FALSE;
2702	    continue;
2703	}
2704
2705	if (advance)
2706	{
2707	    if (parmp->window_layout == WIN_TABS)
2708	    {
2709		if (curtab->tp_next == NULL)	/* just checking */
2710		    break;
2711		goto_tabpage(0);
2712	    }
2713	    else
2714	    {
2715		if (curwin->w_next == NULL)	/* just checking */
2716		    break;
2717		win_enter(curwin->w_next, FALSE);
2718	    }
2719	}
2720	advance = TRUE;
2721
2722	/* Only open the file if there is no file in this window yet (that can
2723	 * happen when .vimrc contains ":sall"). */
2724	if (curbuf == firstwin->w_buffer || curbuf->b_ffname == NULL)
2725	{
2726	    curwin->w_arg_idx = arg_idx;
2727	    /* Edit file from arg list, if there is one.  When "Quit" selected
2728	     * at the ATTENTION prompt close the window. */
2729# ifdef HAS_SWAP_EXISTS_ACTION
2730	    swap_exists_did_quit = FALSE;
2731# endif
2732	    (void)do_ecmd(0, arg_idx < GARGCOUNT
2733			  ? alist_name(&GARGLIST[arg_idx]) : NULL,
2734			  NULL, NULL, ECMD_LASTL, ECMD_HIDE, curwin);
2735# ifdef HAS_SWAP_EXISTS_ACTION
2736	    if (swap_exists_did_quit)
2737	    {
2738		/* abort or quit selected */
2739		if (got_int || only_one_window())
2740		{
2741		    /* abort selected and only one window */
2742		    did_emsg = FALSE;   /* avoid hit-enter prompt */
2743		    getout(1);
2744		}
2745		win_close(curwin, TRUE);
2746		advance = FALSE;
2747	    }
2748# endif
2749	    if (arg_idx == GARGCOUNT - 1)
2750		arg_had_last = TRUE;
2751	    ++arg_idx;
2752	}
2753	ui_breakcheck();
2754	if (got_int)
2755	{
2756	    (void)vgetc();	/* only break the file loading, not the rest */
2757	    break;
2758	}
2759    }
2760
2761    if (parmp->window_layout == WIN_TABS)
2762	goto_tabpage(1);
2763# ifdef FEAT_AUTOCMD
2764    --autocmd_no_enter;
2765# endif
2766    win_enter(firstwin, FALSE);		/* back to first window */
2767# ifdef FEAT_AUTOCMD
2768    --autocmd_no_leave;
2769# endif
2770    TIME_MSG("editing files in windows");
2771    if (parmp->window_count > 1 && parmp->window_layout != WIN_TABS)
2772	win_equal(curwin, FALSE, 'b');	/* adjust heights */
2773}
2774#endif /* FEAT_WINDOWS */
2775
2776/*
2777 * Execute the commands from --cmd arguments "cmds[cnt]".
2778 */
2779    static void
2780exe_pre_commands(parmp)
2781    mparm_T	*parmp;
2782{
2783    char_u	**cmds = parmp->pre_commands;
2784    int		cnt = parmp->n_pre_commands;
2785    int		i;
2786
2787    if (cnt > 0)
2788    {
2789	curwin->w_cursor.lnum = 0; /* just in case.. */
2790	sourcing_name = (char_u *)_("pre-vimrc command line");
2791# ifdef FEAT_EVAL
2792	current_SID = SID_CMDARG;
2793# endif
2794	for (i = 0; i < cnt; ++i)
2795	    do_cmdline_cmd(cmds[i]);
2796	sourcing_name = NULL;
2797# ifdef FEAT_EVAL
2798	current_SID = 0;
2799# endif
2800	TIME_MSG("--cmd commands");
2801    }
2802}
2803
2804/*
2805 * Execute "+", "-c" and "-S" arguments.
2806 */
2807    static void
2808exe_commands(parmp)
2809    mparm_T	*parmp;
2810{
2811    int		i;
2812
2813    /*
2814     * We start commands on line 0, make "vim +/pat file" match a
2815     * pattern on line 1.  But don't move the cursor when an autocommand
2816     * with g`" was used.
2817     */
2818    msg_scroll = TRUE;
2819    if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1)
2820	curwin->w_cursor.lnum = 0;
2821    sourcing_name = (char_u *)"command line";
2822#ifdef FEAT_EVAL
2823    current_SID = SID_CARG;
2824#endif
2825    for (i = 0; i < parmp->n_commands; ++i)
2826    {
2827	do_cmdline_cmd(parmp->commands[i]);
2828	if (parmp->cmds_tofree[i])
2829	    vim_free(parmp->commands[i]);
2830    }
2831    sourcing_name = NULL;
2832#ifdef FEAT_EVAL
2833    current_SID = 0;
2834#endif
2835    if (curwin->w_cursor.lnum == 0)
2836	curwin->w_cursor.lnum = 1;
2837
2838    if (!exmode_active)
2839	msg_scroll = FALSE;
2840
2841#ifdef FEAT_QUICKFIX
2842    /* When started with "-q errorfile" jump to first error again. */
2843    if (parmp->edit_type == EDIT_QF)
2844	qf_jump(NULL, 0, 0, FALSE);
2845#endif
2846    TIME_MSG("executing command arguments");
2847}
2848
2849/*
2850 * Source startup scripts.
2851 */
2852    static void
2853source_startup_scripts(parmp)
2854    mparm_T	*parmp;
2855{
2856    int		i;
2857
2858    /*
2859     * For "evim" source evim.vim first of all, so that the user can overrule
2860     * any things he doesn't like.
2861     */
2862    if (parmp->evim_mode)
2863    {
2864	(void)do_source((char_u *)EVIM_FILE, FALSE, DOSO_NONE);
2865	TIME_MSG("source evim file");
2866    }
2867
2868    /*
2869     * If -u argument given, use only the initializations from that file and
2870     * nothing else.
2871     */
2872    if (parmp->use_vimrc != NULL)
2873    {
2874	if (STRCMP(parmp->use_vimrc, "NONE") == 0
2875				     || STRCMP(parmp->use_vimrc, "NORC") == 0)
2876	{
2877#ifdef FEAT_GUI
2878	    if (use_gvimrc == NULL)	    /* don't load gvimrc either */
2879		use_gvimrc = parmp->use_vimrc;
2880#endif
2881	    if (parmp->use_vimrc[2] == 'N')
2882		p_lpl = FALSE;		    /* don't load plugins either */
2883	}
2884	else
2885	{
2886	    if (do_source(parmp->use_vimrc, FALSE, DOSO_NONE) != OK)
2887		EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc);
2888	}
2889    }
2890    else if (!silent_mode)
2891    {
2892#ifdef AMIGA
2893	struct Process	*proc = (struct Process *)FindTask(0L);
2894	APTR		save_winptr = proc->pr_WindowPtr;
2895
2896	/* Avoid a requester here for a volume that doesn't exist. */
2897	proc->pr_WindowPtr = (APTR)-1L;
2898#endif
2899
2900	/*
2901	 * Get system wide defaults, if the file name is defined.
2902	 */
2903#ifdef SYS_VIMRC_FILE
2904	(void)do_source((char_u *)SYS_VIMRC_FILE, FALSE, DOSO_NONE);
2905#endif
2906#ifdef MACOS_X
2907	(void)do_source((char_u *)"$VIMRUNTIME/macmap.vim", FALSE, DOSO_NONE);
2908#endif
2909
2910	/*
2911	 * Try to read initialization commands from the following places:
2912	 * - environment variable VIMINIT
2913	 * - user vimrc file (s:.vimrc for Amiga, ~/.vimrc otherwise)
2914	 * - second user vimrc file ($VIM/.vimrc for Dos)
2915	 * - environment variable EXINIT
2916	 * - user exrc file (s:.exrc for Amiga, ~/.exrc otherwise)
2917	 * - second user exrc file ($VIM/.exrc for Dos)
2918	 * The first that exists is used, the rest is ignored.
2919	 */
2920	if (process_env((char_u *)"VIMINIT", TRUE) != OK)
2921	{
2922	    if (do_source((char_u *)USR_VIMRC_FILE, TRUE, DOSO_VIMRC) == FAIL
2923#ifdef USR_VIMRC_FILE2
2924		&& do_source((char_u *)USR_VIMRC_FILE2, TRUE,
2925							   DOSO_VIMRC) == FAIL
2926#endif
2927#ifdef USR_VIMRC_FILE3
2928		&& do_source((char_u *)USR_VIMRC_FILE3, TRUE,
2929							   DOSO_VIMRC) == FAIL
2930#endif
2931		&& process_env((char_u *)"EXINIT", FALSE) == FAIL
2932		&& do_source((char_u *)USR_EXRC_FILE, FALSE, DOSO_NONE) == FAIL)
2933	    {
2934#ifdef USR_EXRC_FILE2
2935		(void)do_source((char_u *)USR_EXRC_FILE2, FALSE, DOSO_NONE);
2936#endif
2937	    }
2938	}
2939
2940	/*
2941	 * Read initialization commands from ".vimrc" or ".exrc" in current
2942	 * directory.  This is only done if the 'exrc' option is set.
2943	 * Because of security reasons we disallow shell and write commands
2944	 * now, except for unix if the file is owned by the user or 'secure'
2945	 * option has been reset in environment of global ".exrc" or ".vimrc".
2946	 * Only do this if VIMRC_FILE is not the same as USR_VIMRC_FILE or
2947	 * SYS_VIMRC_FILE.
2948	 */
2949	if (p_exrc)
2950	{
2951#if defined(UNIX) || defined(VMS)
2952	    /* If ".vimrc" file is not owned by user, set 'secure' mode. */
2953	    if (!file_owned(VIMRC_FILE))
2954#endif
2955		secure = p_secure;
2956
2957	    i = FAIL;
2958	    if (fullpathcmp((char_u *)USR_VIMRC_FILE,
2959				      (char_u *)VIMRC_FILE, FALSE) != FPC_SAME
2960#ifdef USR_VIMRC_FILE2
2961		    && fullpathcmp((char_u *)USR_VIMRC_FILE2,
2962				      (char_u *)VIMRC_FILE, FALSE) != FPC_SAME
2963#endif
2964#ifdef USR_VIMRC_FILE3
2965		    && fullpathcmp((char_u *)USR_VIMRC_FILE3,
2966				      (char_u *)VIMRC_FILE, FALSE) != FPC_SAME
2967#endif
2968#ifdef SYS_VIMRC_FILE
2969		    && fullpathcmp((char_u *)SYS_VIMRC_FILE,
2970				      (char_u *)VIMRC_FILE, FALSE) != FPC_SAME
2971#endif
2972				)
2973		i = do_source((char_u *)VIMRC_FILE, TRUE, DOSO_VIMRC);
2974
2975	    if (i == FAIL)
2976	    {
2977#if defined(UNIX) || defined(VMS)
2978		/* if ".exrc" is not owned by user set 'secure' mode */
2979		if (!file_owned(EXRC_FILE))
2980		    secure = p_secure;
2981		else
2982		    secure = 0;
2983#endif
2984		if (	   fullpathcmp((char_u *)USR_EXRC_FILE,
2985				      (char_u *)EXRC_FILE, FALSE) != FPC_SAME
2986#ifdef USR_EXRC_FILE2
2987			&& fullpathcmp((char_u *)USR_EXRC_FILE2,
2988				      (char_u *)EXRC_FILE, FALSE) != FPC_SAME
2989#endif
2990				)
2991		    (void)do_source((char_u *)EXRC_FILE, FALSE, DOSO_NONE);
2992	    }
2993	}
2994	if (secure == 2)
2995	    need_wait_return = TRUE;
2996	secure = 0;
2997#ifdef AMIGA
2998	proc->pr_WindowPtr = save_winptr;
2999#endif
3000    }
3001    TIME_MSG("sourcing vimrc file(s)");
3002}
3003
3004/*
3005 * Setup to start using the GUI.  Exit with an error when not available.
3006 */
3007    static void
3008main_start_gui()
3009{
3010#ifdef FEAT_GUI
3011    gui.starting = TRUE;	/* start GUI a bit later */
3012#else
3013    mch_errmsg(_(e_nogvim));
3014    mch_errmsg("\n");
3015    mch_exit(2);
3016#endif
3017}
3018
3019/*
3020 * Get an environment variable, and execute it as Ex commands.
3021 * Returns FAIL if the environment variable was not executed, OK otherwise.
3022 */
3023    int
3024process_env(env, is_viminit)
3025    char_u	*env;
3026    int		is_viminit; /* when TRUE, called for VIMINIT */
3027{
3028    char_u	*initstr;
3029    char_u	*save_sourcing_name;
3030    linenr_T	save_sourcing_lnum;
3031#ifdef FEAT_EVAL
3032    scid_T	save_sid;
3033#endif
3034
3035    if ((initstr = mch_getenv(env)) != NULL && *initstr != NUL)
3036    {
3037	if (is_viminit)
3038	    vimrc_found(NULL, NULL);
3039	save_sourcing_name = sourcing_name;
3040	save_sourcing_lnum = sourcing_lnum;
3041	sourcing_name = env;
3042	sourcing_lnum = 0;
3043#ifdef FEAT_EVAL
3044	save_sid = current_SID;
3045	current_SID = SID_ENV;
3046#endif
3047	do_cmdline_cmd(initstr);
3048	sourcing_name = save_sourcing_name;
3049	sourcing_lnum = save_sourcing_lnum;
3050#ifdef FEAT_EVAL
3051	current_SID = save_sid;;
3052#endif
3053	return OK;
3054    }
3055    return FAIL;
3056}
3057
3058#if defined(UNIX) || defined(VMS)
3059/*
3060 * Return TRUE if we are certain the user owns the file "fname".
3061 * Used for ".vimrc" and ".exrc".
3062 * Use both stat() and lstat() for extra security.
3063 */
3064    static int
3065file_owned(fname)
3066    char	*fname;
3067{
3068    struct stat s;
3069# ifdef UNIX
3070    uid_t	uid = getuid();
3071# else	 /* VMS */
3072    uid_t	uid = ((getgid() << 16) | getuid());
3073# endif
3074
3075    return !(mch_stat(fname, &s) != 0 || s.st_uid != uid
3076# ifdef HAVE_LSTAT
3077	    || mch_lstat(fname, &s) != 0 || s.st_uid != uid
3078# endif
3079	    );
3080}
3081#endif
3082
3083/*
3084 * Give an error message main_errors["n"] and exit.
3085 */
3086    static void
3087mainerr(n, str)
3088    int		n;	/* one of the ME_ defines */
3089    char_u	*str;	/* extra argument or NULL */
3090{
3091#if defined(UNIX) || defined(__EMX__) || defined(VMS)
3092    reset_signals();		/* kill us with CTRL-C here, if you like */
3093#endif
3094
3095    mch_errmsg(longVersion);
3096    mch_errmsg("\n");
3097    mch_errmsg(_(main_errors[n]));
3098    if (str != NULL)
3099    {
3100	mch_errmsg(": \"");
3101	mch_errmsg((char *)str);
3102	mch_errmsg("\"");
3103    }
3104    mch_errmsg(_("\nMore info with: \"vim -h\"\n"));
3105
3106    mch_exit(1);
3107}
3108
3109    void
3110mainerr_arg_missing(str)
3111    char_u	*str;
3112{
3113    mainerr(ME_ARG_MISSING, str);
3114}
3115
3116/*
3117 * print a message with three spaces prepended and '\n' appended.
3118 */
3119    static void
3120main_msg(s)
3121    char *s;
3122{
3123    mch_msg("   ");
3124    mch_msg(s);
3125    mch_msg("\n");
3126}
3127
3128/*
3129 * Print messages for "vim -h" or "vim --help" and exit.
3130 */
3131    static void
3132usage()
3133{
3134    int		i;
3135    static char	*(use[]) =
3136    {
3137	N_("[file ..]       edit specified file(s)"),
3138	N_("-               read text from stdin"),
3139	N_("-t tag          edit file where tag is defined"),
3140#ifdef FEAT_QUICKFIX
3141	N_("-q [errorfile]  edit file with first error")
3142#endif
3143    };
3144
3145#if defined(UNIX) || defined(__EMX__) || defined(VMS)
3146    reset_signals();		/* kill us with CTRL-C here, if you like */
3147#endif
3148
3149    mch_msg(longVersion);
3150    mch_msg(_("\n\nusage:"));
3151    for (i = 0; ; ++i)
3152    {
3153	mch_msg(_(" vim [arguments] "));
3154	mch_msg(_(use[i]));
3155	if (i == (sizeof(use) / sizeof(char_u *)) - 1)
3156	    break;
3157	mch_msg(_("\n   or:"));
3158    }
3159#ifdef VMS
3160    mch_msg(_("\nWhere case is ignored prepend / to make flag upper case"));
3161#endif
3162
3163    mch_msg(_("\n\nArguments:\n"));
3164    main_msg(_("--\t\t\tOnly file names after this"));
3165#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE)
3166    main_msg(_("--literal\t\tDon't expand wildcards"));
3167#endif
3168#ifdef FEAT_OLE
3169    main_msg(_("-register\t\tRegister this gvim for OLE"));
3170    main_msg(_("-unregister\t\tUnregister gvim for OLE"));
3171#endif
3172#ifdef FEAT_GUI
3173    main_msg(_("-g\t\t\tRun using GUI (like \"gvim\")"));
3174    main_msg(_("-f  or  --nofork\tForeground: Don't fork when starting GUI"));
3175#endif
3176    main_msg(_("-v\t\t\tVi mode (like \"vi\")"));
3177    main_msg(_("-e\t\t\tEx mode (like \"ex\")"));
3178    main_msg(_("-s\t\t\tSilent (batch) mode (only for \"ex\")"));
3179#ifdef FEAT_DIFF
3180    main_msg(_("-d\t\t\tDiff mode (like \"vimdiff\")"));
3181#endif
3182    main_msg(_("-y\t\t\tEasy mode (like \"evim\", modeless)"));
3183    main_msg(_("-R\t\t\tReadonly mode (like \"view\")"));
3184    main_msg(_("-Z\t\t\tRestricted mode (like \"rvim\")"));
3185    main_msg(_("-m\t\t\tModifications (writing files) not allowed"));
3186    main_msg(_("-M\t\t\tModifications in text not allowed"));
3187    main_msg(_("-b\t\t\tBinary mode"));
3188#ifdef FEAT_LISP
3189    main_msg(_("-l\t\t\tLisp mode"));
3190#endif
3191    main_msg(_("-C\t\t\tCompatible with Vi: 'compatible'"));
3192    main_msg(_("-N\t\t\tNot fully Vi compatible: 'nocompatible'"));
3193    main_msg(_("-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"));
3194#ifdef FEAT_EVAL
3195    main_msg(_("-D\t\t\tDebugging mode"));
3196#endif
3197    main_msg(_("-n\t\t\tNo swap file, use memory only"));
3198    main_msg(_("-r\t\t\tList swap files and exit"));
3199    main_msg(_("-r (with file name)\tRecover crashed session"));
3200    main_msg(_("-L\t\t\tSame as -r"));
3201#ifdef AMIGA
3202    main_msg(_("-f\t\t\tDon't use newcli to open window"));
3203    main_msg(_("-dev <device>\t\tUse <device> for I/O"));
3204#endif
3205#ifdef FEAT_ARABIC
3206    main_msg(_("-A\t\t\tstart in Arabic mode"));
3207#endif
3208#ifdef FEAT_RIGHTLEFT
3209    main_msg(_("-H\t\t\tStart in Hebrew mode"));
3210#endif
3211#ifdef FEAT_FKMAP
3212    main_msg(_("-F\t\t\tStart in Farsi mode"));
3213#endif
3214    main_msg(_("-T <terminal>\tSet terminal type to <terminal>"));
3215    main_msg(_("-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"));
3216#ifdef FEAT_GUI
3217    main_msg(_("-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"));
3218#endif
3219    main_msg(_("--noplugin\t\tDon't load plugin scripts"));
3220#ifdef FEAT_WINDOWS
3221    main_msg(_("-p[N]\t\tOpen N tab pages (default: one for each file)"));
3222    main_msg(_("-o[N]\t\tOpen N windows (default: one for each file)"));
3223    main_msg(_("-O[N]\t\tLike -o but split vertically"));
3224#endif
3225    main_msg(_("+\t\t\tStart at end of file"));
3226    main_msg(_("+<lnum>\t\tStart at line <lnum>"));
3227    main_msg(_("--cmd <command>\tExecute <command> before loading any vimrc file"));
3228    main_msg(_("-c <command>\t\tExecute <command> after loading the first file"));
3229    main_msg(_("-S <session>\t\tSource file <session> after loading the first file"));
3230    main_msg(_("-s <scriptin>\tRead Normal mode commands from file <scriptin>"));
3231    main_msg(_("-w <scriptout>\tAppend all typed commands to file <scriptout>"));
3232    main_msg(_("-W <scriptout>\tWrite all typed commands to file <scriptout>"));
3233#ifdef FEAT_CRYPT
3234    main_msg(_("-x\t\t\tEdit encrypted files"));
3235#endif
3236#if (defined(UNIX) || defined(VMS)) && defined(FEAT_X11)
3237# if defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK)
3238    main_msg(_("-display <display>\tConnect vim to this particular X-server"));
3239# endif
3240    main_msg(_("-X\t\t\tDo not connect to X server"));
3241#endif
3242#ifdef FEAT_CLIENTSERVER
3243    main_msg(_("--remote <files>\tEdit <files> in a Vim server if possible"));
3244    main_msg(_("--remote-silent <files>  Same, don't complain if there is no server"));
3245    main_msg(_("--remote-wait <files>  As --remote but wait for files to have been edited"));
3246    main_msg(_("--remote-wait-silent <files>  Same, don't complain if there is no server"));
3247# ifdef FEAT_WINDOWS
3248    main_msg(_("--remote-tab[-wait][-silent] <files>  As --remote but use tab page per file"));
3249# endif
3250    main_msg(_("--remote-send <keys>\tSend <keys> to a Vim server and exit"));
3251    main_msg(_("--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"));
3252    main_msg(_("--serverlist\t\tList available Vim server names and exit"));
3253    main_msg(_("--servername <name>\tSend to/become the Vim server <name>"));
3254#endif
3255#ifdef STARTUPTIME
3256    main_msg(_("--startuptime <file>\tWrite startup timing messages to <file>"));
3257#endif
3258#ifdef FEAT_VIMINFO
3259    main_msg(_("-i <viminfo>\t\tUse <viminfo> instead of .viminfo"));
3260#endif
3261    main_msg(_("-h  or  --help\tPrint Help (this message) and exit"));
3262    main_msg(_("--version\t\tPrint version information and exit"));
3263
3264#ifdef FEAT_GUI_X11
3265# ifdef FEAT_GUI_MOTIF
3266    mch_msg(_("\nArguments recognised by gvim (Motif version):\n"));
3267# else
3268#  ifdef FEAT_GUI_ATHENA
3269#   ifdef FEAT_GUI_NEXTAW
3270    mch_msg(_("\nArguments recognised by gvim (neXtaw version):\n"));
3271#   else
3272    mch_msg(_("\nArguments recognised by gvim (Athena version):\n"));
3273#   endif
3274#  endif
3275# endif
3276    main_msg(_("-display <display>\tRun vim on <display>"));
3277    main_msg(_("-iconic\t\tStart vim iconified"));
3278    main_msg(_("-background <color>\tUse <color> for the background (also: -bg)"));
3279    main_msg(_("-foreground <color>\tUse <color> for normal text (also: -fg)"));
3280    main_msg(_("-font <font>\t\tUse <font> for normal text (also: -fn)"));
3281    main_msg(_("-boldfont <font>\tUse <font> for bold text"));
3282    main_msg(_("-italicfont <font>\tUse <font> for italic text"));
3283    main_msg(_("-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"));
3284    main_msg(_("-borderwidth <width>\tUse a border width of <width> (also: -bw)"));
3285    main_msg(_("-scrollbarwidth <width>  Use a scrollbar width of <width> (also: -sw)"));
3286# ifdef FEAT_GUI_ATHENA
3287    main_msg(_("-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"));
3288# endif
3289    main_msg(_("-reverse\t\tUse reverse video (also: -rv)"));
3290    main_msg(_("+reverse\t\tDon't use reverse video (also: +rv)"));
3291    main_msg(_("-xrm <resource>\tSet the specified resource"));
3292#endif /* FEAT_GUI_X11 */
3293#if defined(FEAT_GUI) && defined(RISCOS)
3294    mch_msg(_("\nArguments recognised by gvim (RISC OS version):\n"));
3295    main_msg(_("--columns <number>\tInitial width of window in columns"));
3296    main_msg(_("--rows <number>\tInitial height of window in rows"));
3297#endif
3298#ifdef FEAT_GUI_GTK
3299    mch_msg(_("\nArguments recognised by gvim (GTK+ version):\n"));
3300    main_msg(_("-font <font>\t\tUse <font> for normal text (also: -fn)"));
3301    main_msg(_("-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"));
3302    main_msg(_("-reverse\t\tUse reverse video (also: -rv)"));
3303    main_msg(_("-display <display>\tRun vim on <display> (also: --display)"));
3304    main_msg(_("--role <role>\tSet a unique role to identify the main window"));
3305    main_msg(_("--socketid <xid>\tOpen Vim inside another GTK widget"));
3306#endif
3307#ifdef FEAT_GUI_W32
3308    main_msg(_("-P <parent title>\tOpen Vim inside parent application"));
3309    main_msg(_("--windowid <HWND>\tOpen Vim inside another win32 widget"));
3310#endif
3311
3312#ifdef FEAT_GUI_GNOME
3313    /* Gnome gives extra messages for --help if we continue, but not for -h. */
3314    if (gui.starting)
3315	mch_msg("\n");
3316    else
3317#endif
3318	mch_exit(0);
3319}
3320
3321#if defined(HAS_SWAP_EXISTS_ACTION)
3322/*
3323 * Check the result of the ATTENTION dialog:
3324 * When "Quit" selected, exit Vim.
3325 * When "Recover" selected, recover the file.
3326 */
3327    static void
3328check_swap_exists_action()
3329{
3330    did_emsg = FALSE;
3331    if (swap_exists_action == SEA_QUIT)
3332	getout(1);
3333    handle_swap_exists(NULL);
3334}
3335#endif
3336
3337#if defined(STARTUPTIME) || defined(PROTO)
3338static void time_diff __ARGS((struct timeval *then, struct timeval *now));
3339
3340static struct timeval	prev_timeval;
3341
3342# ifdef WIN3264
3343/*
3344 * Windows doesn't have gettimeofday(), although it does have struct timeval.
3345 */
3346    static int
3347gettimeofday(struct timeval *tv, char *dummy)
3348{
3349    long t = clock();
3350    tv->tv_sec = t / CLOCKS_PER_SEC;
3351    tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC;
3352    return 0;
3353}
3354# endif
3355
3356/*
3357 * Save the previous time before doing something that could nest.
3358 * set "*tv_rel" to the time elapsed so far.
3359 */
3360    void
3361time_push(tv_rel, tv_start)
3362    void	*tv_rel, *tv_start;
3363{
3364    *((struct timeval *)tv_rel) = prev_timeval;
3365    gettimeofday(&prev_timeval, NULL);
3366    ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec
3367					- ((struct timeval *)tv_rel)->tv_usec;
3368    ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec
3369					 - ((struct timeval *)tv_rel)->tv_sec;
3370    if (((struct timeval *)tv_rel)->tv_usec < 0)
3371    {
3372	((struct timeval *)tv_rel)->tv_usec += 1000000;
3373	--((struct timeval *)tv_rel)->tv_sec;
3374    }
3375    *(struct timeval *)tv_start = prev_timeval;
3376}
3377
3378/*
3379 * Compute the previous time after doing something that could nest.
3380 * Subtract "*tp" from prev_timeval;
3381 * Note: The arguments are (void *) to avoid trouble with systems that don't
3382 * have struct timeval.
3383 */
3384    void
3385time_pop(tp)
3386    void	*tp;	/* actually (struct timeval *) */
3387{
3388    prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec;
3389    prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec;
3390    if (prev_timeval.tv_usec < 0)
3391    {
3392	prev_timeval.tv_usec += 1000000;
3393	--prev_timeval.tv_sec;
3394    }
3395}
3396
3397    static void
3398time_diff(then, now)
3399    struct timeval	*then;
3400    struct timeval	*now;
3401{
3402    long	usec;
3403    long	msec;
3404
3405    usec = now->tv_usec - then->tv_usec;
3406    msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L,
3407    usec = usec % 1000L;
3408    fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L);
3409}
3410
3411    void
3412time_msg(mesg, tv_start)
3413    char	*mesg;
3414    void	*tv_start;  /* only for do_source: start time; actually
3415			       (struct timeval *) */
3416{
3417    static struct timeval	start;
3418    struct timeval		now;
3419
3420    if (time_fd != NULL)
3421    {
3422	if (strstr(mesg, "STARTING") != NULL)
3423	{
3424	    gettimeofday(&start, NULL);
3425	    prev_timeval = start;
3426	    fprintf(time_fd, "\n\ntimes in msec\n");
3427	    fprintf(time_fd, " clock   self+sourced   self:  sourced script\n");
3428	    fprintf(time_fd, " clock   elapsed:              other lines\n\n");
3429	}
3430	gettimeofday(&now, NULL);
3431	time_diff(&start, &now);
3432	if (((struct timeval *)tv_start) != NULL)
3433	{
3434	    fprintf(time_fd, "  ");
3435	    time_diff(((struct timeval *)tv_start), &now);
3436	}
3437	fprintf(time_fd, "  ");
3438	time_diff(&prev_timeval, &now);
3439	prev_timeval = now;
3440	fprintf(time_fd, ": %s\n", mesg);
3441    }
3442}
3443
3444#endif
3445
3446#if defined(FEAT_CLIENTSERVER) || defined(PROTO)
3447
3448/*
3449 * Common code for the X command server and the Win32 command server.
3450 */
3451
3452static char_u *build_drop_cmd __ARGS((int filec, char **filev, int tabs, int sendReply));
3453
3454/*
3455 * Do the client-server stuff, unless "--servername ''" was used.
3456 */
3457    static void
3458exec_on_server(parmp)
3459    mparm_T	*parmp;
3460{
3461    if (parmp->serverName_arg == NULL || *parmp->serverName_arg != NUL)
3462    {
3463# ifdef WIN32
3464	/* Initialise the client/server messaging infrastructure. */
3465	serverInitMessaging();
3466# endif
3467
3468	/*
3469	 * When a command server argument was found, execute it.  This may
3470	 * exit Vim when it was successful.  Otherwise it's executed further
3471	 * on.  Remember the encoding used here in "serverStrEnc".
3472	 */
3473	if (parmp->serverArg)
3474	{
3475	    cmdsrv_main(&parmp->argc, parmp->argv,
3476				    parmp->serverName_arg, &parmp->serverStr);
3477# ifdef FEAT_MBYTE
3478	    parmp->serverStrEnc = vim_strsave(p_enc);
3479# endif
3480	}
3481
3482	/* If we're still running, get the name to register ourselves.
3483	 * On Win32 can register right now, for X11 need to setup the
3484	 * clipboard first, it's further down. */
3485	parmp->servername = serverMakeName(parmp->serverName_arg,
3486							      parmp->argv[0]);
3487# ifdef WIN32
3488	if (parmp->servername != NULL)
3489	{
3490	    serverSetName(parmp->servername);
3491	    vim_free(parmp->servername);
3492	}
3493# endif
3494    }
3495}
3496
3497/*
3498 * Prepare for running as a Vim server.
3499 */
3500    static void
3501prepare_server(parmp)
3502    mparm_T	*parmp;
3503{
3504# if defined(FEAT_X11)
3505    /*
3506     * Register for remote command execution with :serversend and --remote
3507     * unless there was a -X or a --servername '' on the command line.
3508     * Only register nongui-vim's with an explicit --servername argument.
3509     * When running as root --servername is also required.
3510     */
3511    if (X_DISPLAY != NULL && parmp->servername != NULL && (
3512#  ifdef FEAT_GUI
3513		(gui.in_use
3514#   ifdef UNIX
3515		 && getuid() != ROOT_UID
3516#   endif
3517		) ||
3518#  endif
3519		parmp->serverName_arg != NULL))
3520    {
3521	(void)serverRegisterName(X_DISPLAY, parmp->servername);
3522	vim_free(parmp->servername);
3523	TIME_MSG("register server name");
3524    }
3525    else
3526	serverDelayedStartName = parmp->servername;
3527# endif
3528
3529    /*
3530     * Execute command ourselves if we're here because the send failed (or
3531     * else we would have exited above).
3532     */
3533    if (parmp->serverStr != NULL)
3534    {
3535	char_u *p;
3536
3537	server_to_input_buf(serverConvert(parmp->serverStrEnc,
3538						       parmp->serverStr, &p));
3539	vim_free(p);
3540    }
3541}
3542
3543    static void
3544cmdsrv_main(argc, argv, serverName_arg, serverStr)
3545    int		*argc;
3546    char	**argv;
3547    char_u	*serverName_arg;
3548    char_u	**serverStr;
3549{
3550    char_u	*res;
3551    int		i;
3552    char_u	*sname;
3553    int		ret;
3554    int		didone = FALSE;
3555    int		exiterr = 0;
3556    char	**newArgV = argv + 1;
3557    int		newArgC = 1,
3558		Argc = *argc;
3559    int		argtype;
3560#define ARGTYPE_OTHER		0
3561#define ARGTYPE_EDIT		1
3562#define ARGTYPE_EDIT_WAIT	2
3563#define ARGTYPE_SEND		3
3564    int		silent = FALSE;
3565    int		tabs = FALSE;
3566# ifndef FEAT_X11
3567    HWND	srv;
3568# else
3569    Window	srv;
3570
3571    setup_term_clip();
3572# endif
3573
3574    sname = serverMakeName(serverName_arg, argv[0]);
3575    if (sname == NULL)
3576	return;
3577
3578    /*
3579     * Execute the command server related arguments and remove them
3580     * from the argc/argv array; We may have to return into main()
3581     */
3582    for (i = 1; i < Argc; i++)
3583    {
3584	res = NULL;
3585	if (STRCMP(argv[i], "--") == 0)	/* end of option arguments */
3586	{
3587	    for (; i < *argc; i++)
3588	    {
3589		*newArgV++ = argv[i];
3590		newArgC++;
3591	    }
3592	    break;
3593	}
3594
3595	if (STRICMP(argv[i], "--remote-send") == 0)
3596	    argtype = ARGTYPE_SEND;
3597	else if (STRNICMP(argv[i], "--remote", 8) == 0)
3598	{
3599	    char	*p = argv[i] + 8;
3600
3601	    argtype = ARGTYPE_EDIT;
3602	    while (*p != NUL)
3603	    {
3604		if (STRNICMP(p, "-wait", 5) == 0)
3605		{
3606		    argtype = ARGTYPE_EDIT_WAIT;
3607		    p += 5;
3608		}
3609		else if (STRNICMP(p, "-silent", 7) == 0)
3610		{
3611		    silent = TRUE;
3612		    p += 7;
3613		}
3614		else if (STRNICMP(p, "-tab", 4) == 0)
3615		{
3616		    tabs = TRUE;
3617		    p += 4;
3618		}
3619		else
3620		{
3621		    argtype = ARGTYPE_OTHER;
3622		    break;
3623		}
3624	    }
3625	}
3626	else
3627	    argtype = ARGTYPE_OTHER;
3628
3629	if (argtype != ARGTYPE_OTHER)
3630	{
3631	    if (i == *argc - 1)
3632		mainerr_arg_missing((char_u *)argv[i]);
3633	    if (argtype == ARGTYPE_SEND)
3634	    {
3635		*serverStr = (char_u *)argv[i + 1];
3636		i++;
3637	    }
3638	    else
3639	    {
3640		*serverStr = build_drop_cmd(*argc - i - 1, argv + i + 1,
3641					  tabs, argtype == ARGTYPE_EDIT_WAIT);
3642		if (*serverStr == NULL)
3643		{
3644		    /* Probably out of memory, exit. */
3645		    didone = TRUE;
3646		    exiterr = 1;
3647		    break;
3648		}
3649		Argc = i;
3650	    }
3651# ifdef FEAT_X11
3652	    if (xterm_dpy == NULL)
3653	    {
3654		mch_errmsg(_("No display"));
3655		ret = -1;
3656	    }
3657	    else
3658		ret = serverSendToVim(xterm_dpy, sname, *serverStr,
3659						    NULL, &srv, 0, 0, silent);
3660# else
3661	    /* Win32 always works? */
3662	    ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, silent);
3663# endif
3664	    if (ret < 0)
3665	    {
3666		if (argtype == ARGTYPE_SEND)
3667		{
3668		    /* Failed to send, abort. */
3669		    mch_errmsg(_(": Send failed.\n"));
3670		    didone = TRUE;
3671		    exiterr = 1;
3672		}
3673		else if (!silent)
3674		    /* Let vim start normally.  */
3675		    mch_errmsg(_(": Send failed. Trying to execute locally\n"));
3676		break;
3677	    }
3678
3679# ifdef FEAT_GUI_W32
3680	    /* Guess that when the server name starts with "g" it's a GUI
3681	     * server, which we can bring to the foreground here.
3682	     * Foreground() in the server doesn't work very well. */
3683	    if (argtype != ARGTYPE_SEND && TOUPPER_ASC(*sname) == 'G')
3684		SetForegroundWindow(srv);
3685# endif
3686
3687	    /*
3688	     * For --remote-wait: Wait until the server did edit each
3689	     * file.  Also detect that the server no longer runs.
3690	     */
3691	    if (ret >= 0 && argtype == ARGTYPE_EDIT_WAIT)
3692	    {
3693		int	numFiles = *argc - i - 1;
3694		int	j;
3695		char_u  *done = alloc(numFiles);
3696		char_u  *p;
3697# ifdef FEAT_GUI_W32
3698		NOTIFYICONDATA ni;
3699		int	count = 0;
3700		extern HWND message_window;
3701# endif
3702
3703		if (numFiles > 0 && argv[i + 1][0] == '+')
3704		    /* Skip "+cmd" argument, don't wait for it to be edited. */
3705		    --numFiles;
3706
3707# ifdef FEAT_GUI_W32
3708		ni.cbSize = sizeof(ni);
3709		ni.hWnd = message_window;
3710		ni.uID = 0;
3711		ni.uFlags = NIF_ICON|NIF_TIP;
3712		ni.hIcon = LoadIcon((HINSTANCE)GetModuleHandle(0), "IDR_VIM");
3713		sprintf(ni.szTip, _("%d of %d edited"), count, numFiles);
3714		Shell_NotifyIcon(NIM_ADD, &ni);
3715# endif
3716
3717		/* Wait for all files to unload in remote */
3718		vim_memset(done, 0, numFiles);
3719		while (memchr(done, 0, numFiles) != NULL)
3720		{
3721# ifdef WIN32
3722		    p = serverGetReply(srv, NULL, TRUE, TRUE);
3723		    if (p == NULL)
3724			break;
3725# else
3726		    if (serverReadReply(xterm_dpy, srv, &p, TRUE) < 0)
3727			break;
3728# endif
3729		    j = atoi((char *)p);
3730		    if (j >= 0 && j < numFiles)
3731		    {
3732# ifdef FEAT_GUI_W32
3733			++count;
3734			sprintf(ni.szTip, _("%d of %d edited"),
3735							     count, numFiles);
3736			Shell_NotifyIcon(NIM_MODIFY, &ni);
3737# endif
3738			done[j] = 1;
3739		    }
3740		}
3741# ifdef FEAT_GUI_W32
3742		Shell_NotifyIcon(NIM_DELETE, &ni);
3743# endif
3744	    }
3745	}
3746	else if (STRICMP(argv[i], "--remote-expr") == 0)
3747	{
3748	    if (i == *argc - 1)
3749		mainerr_arg_missing((char_u *)argv[i]);
3750# ifdef WIN32
3751	    /* Win32 always works? */
3752	    if (serverSendToVim(sname, (char_u *)argv[i + 1],
3753						    &res, NULL, 1, FALSE) < 0)
3754# else
3755	    if (xterm_dpy == NULL)
3756		mch_errmsg(_("No display: Send expression failed.\n"));
3757	    else if (serverSendToVim(xterm_dpy, sname, (char_u *)argv[i + 1],
3758						 &res, NULL, 1, 1, FALSE) < 0)
3759# endif
3760	    {
3761		if (res != NULL && *res != NUL)
3762		{
3763		    /* Output error from remote */
3764		    mch_errmsg((char *)res);
3765		    vim_free(res);
3766		    res = NULL;
3767		}
3768		mch_errmsg(_(": Send expression failed.\n"));
3769	    }
3770	}
3771	else if (STRICMP(argv[i], "--serverlist") == 0)
3772	{
3773# ifdef WIN32
3774	    /* Win32 always works? */
3775	    res = serverGetVimNames();
3776# else
3777	    if (xterm_dpy != NULL)
3778		res = serverGetVimNames(xterm_dpy);
3779# endif
3780	    if (called_emsg)
3781		mch_errmsg("\n");
3782	}
3783	else if (STRICMP(argv[i], "--servername") == 0)
3784	{
3785	    /* Already processed. Take it out of the command line */
3786	    i++;
3787	    continue;
3788	}
3789	else
3790	{
3791	    *newArgV++ = argv[i];
3792	    newArgC++;
3793	    continue;
3794	}
3795	didone = TRUE;
3796	if (res != NULL && *res != NUL)
3797	{
3798	    mch_msg((char *)res);
3799	    if (res[STRLEN(res) - 1] != '\n')
3800		mch_msg("\n");
3801	}
3802	vim_free(res);
3803    }
3804
3805    if (didone)
3806    {
3807	display_errors();	/* display any collected messages */
3808	exit(exiterr);	/* Mission accomplished - get out */
3809    }
3810
3811    /* Return back into main() */
3812    *argc = newArgC;
3813    vim_free(sname);
3814}
3815
3816/*
3817 * Build a ":drop" command to send to a Vim server.
3818 */
3819    static char_u *
3820build_drop_cmd(filec, filev, tabs, sendReply)
3821    int		filec;
3822    char	**filev;
3823    int		tabs;		/* Use ":tab drop" instead of ":drop". */
3824    int		sendReply;
3825{
3826    garray_T	ga;
3827    int		i;
3828    char_u	*inicmd = NULL;
3829    char_u	*p;
3830    char_u	cwd[MAXPATHL];
3831
3832    if (filec > 0 && filev[0][0] == '+')
3833    {
3834	inicmd = (char_u *)filev[0] + 1;
3835	filev++;
3836	filec--;
3837    }
3838    /* Check if we have at least one argument. */
3839    if (filec <= 0)
3840	mainerr_arg_missing((char_u *)filev[-1]);
3841    if (mch_dirname(cwd, MAXPATHL) != OK)
3842	return NULL;
3843    if ((p = vim_strsave_escaped_ext(cwd,
3844#ifdef BACKSLASH_IN_FILENAME
3845		    "",  /* rem_backslash() will tell what chars to escape */
3846#else
3847		    PATH_ESC_CHARS,
3848#endif
3849		    '\\', TRUE)) == NULL)
3850	return NULL;
3851    ga_init2(&ga, 1, 100);
3852    ga_concat(&ga, (char_u *)"<C-\\><C-N>:cd ");
3853    ga_concat(&ga, p);
3854    vim_free(p);
3855
3856    /* Call inputsave() so that a prompt for an encryption key works. */
3857    ga_concat(&ga, (char_u *)"<CR>:if exists('*inputsave')|call inputsave()|endif|");
3858    if (tabs)
3859	ga_concat(&ga, (char_u *)"tab ");
3860    ga_concat(&ga, (char_u *)"drop");
3861    for (i = 0; i < filec; i++)
3862    {
3863	/* On Unix the shell has already expanded the wildcards, don't want to
3864	 * do it again in the Vim server.  On MS-Windows only escape
3865	 * non-wildcard characters. */
3866	p = vim_strsave_escaped((char_u *)filev[i],
3867#ifdef UNIX
3868		PATH_ESC_CHARS
3869#else
3870		(char_u *)" \t%#"
3871#endif
3872		);
3873	if (p == NULL)
3874	{
3875	    vim_free(ga.ga_data);
3876	    return NULL;
3877	}
3878	ga_concat(&ga, (char_u *)" ");
3879	ga_concat(&ga, p);
3880	vim_free(p);
3881    }
3882    /* The :drop commands goes to Insert mode when 'insertmode' is set, use
3883     * CTRL-\ CTRL-N again. */
3884    ga_concat(&ga, (char_u *)"|if exists('*inputrestore')|call inputrestore()|endif<CR>");
3885    ga_concat(&ga, (char_u *)"<C-\\><C-N>:cd -");
3886    if (sendReply)
3887	ga_concat(&ga, (char_u *)"<CR>:call SetupRemoteReplies()");
3888    ga_concat(&ga, (char_u *)"<CR>:");
3889    if (inicmd != NULL)
3890    {
3891	/* Can't use <CR> after "inicmd", because an "startinsert" would cause
3892	 * the following commands to be inserted as text.  Use a "|",
3893	 * hopefully "inicmd" does allow this... */
3894	ga_concat(&ga, inicmd);
3895	ga_concat(&ga, (char_u *)"|");
3896    }
3897    /* Bring the window to the foreground, goto Insert mode when 'im' set and
3898     * clear command line. */
3899    ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f<CR>");
3900    ga_append(&ga, NUL);
3901    return ga.ga_data;
3902}
3903
3904/*
3905 * Replace termcodes such as <CR> and insert as key presses if there is room.
3906 */
3907    void
3908server_to_input_buf(str)
3909    char_u	*str;
3910{
3911    char_u      *ptr = NULL;
3912    char_u      *cpo_save = p_cpo;
3913
3914    /* Set 'cpoptions' the way we want it.
3915     *    B set - backslashes are *not* treated specially
3916     *    k set - keycodes are *not* reverse-engineered
3917     *    < unset - <Key> sequences *are* interpreted
3918     *  The last but one parameter of replace_termcodes() is TRUE so that the
3919     *  <lt> sequence is recognised - needed for a real backslash.
3920     */
3921    p_cpo = (char_u *)"Bk";
3922    str = replace_termcodes((char_u *)str, &ptr, FALSE, TRUE, FALSE);
3923    p_cpo = cpo_save;
3924
3925    if (*ptr != NUL)	/* trailing CTRL-V results in nothing */
3926    {
3927	/*
3928	 * Add the string to the input stream.
3929	 * Can't use add_to_input_buf() here, we now have K_SPECIAL bytes.
3930	 *
3931	 * First clear typed characters from the typeahead buffer, there could
3932	 * be half a mapping there.  Then append to the existing string, so
3933	 * that multiple commands from a client are concatenated.
3934	 */
3935	if (typebuf.tb_maplen < typebuf.tb_len)
3936	    del_typebuf(typebuf.tb_len - typebuf.tb_maplen, typebuf.tb_maplen);
3937	(void)ins_typebuf(str, REMAP_NONE, typebuf.tb_len, TRUE, FALSE);
3938
3939	/* Let input_available() know we inserted text in the typeahead
3940	 * buffer. */
3941	typebuf_was_filled = TRUE;
3942    }
3943    vim_free((char_u *)ptr);
3944}
3945
3946/*
3947 * Evaluate an expression that the client sent to a string.
3948 * Handles disabling error messages and disables debugging, otherwise Vim
3949 * hangs, waiting for "cont" to be typed.
3950 */
3951    char_u *
3952eval_client_expr_to_string(expr)
3953    char_u *expr;
3954{
3955    char_u	*res;
3956    int		save_dbl = debug_break_level;
3957    int		save_ro = redir_off;
3958
3959    debug_break_level = -1;
3960    redir_off = 0;
3961    ++emsg_skip;
3962
3963    res = eval_to_string(expr, NULL, TRUE);
3964
3965    debug_break_level = save_dbl;
3966    redir_off = save_ro;
3967    --emsg_skip;
3968
3969    /* A client can tell us to redraw, but not to display the cursor, so do
3970     * that here. */
3971    setcursor();
3972    out_flush();
3973#ifdef FEAT_GUI
3974    if (gui.in_use)
3975	gui_update_cursor(FALSE, FALSE);
3976#endif
3977
3978    return res;
3979}
3980
3981/*
3982 * If conversion is needed, convert "data" from "client_enc" to 'encoding' and
3983 * return an allocated string.  Otherwise return "data".
3984 * "*tofree" is set to the result when it needs to be freed later.
3985 */
3986    char_u *
3987serverConvert(client_enc, data, tofree)
3988    char_u *client_enc UNUSED;
3989    char_u *data;
3990    char_u **tofree;
3991{
3992    char_u	*res = data;
3993
3994    *tofree = NULL;
3995# ifdef FEAT_MBYTE
3996    if (client_enc != NULL && p_enc != NULL)
3997    {
3998	vimconv_T	vimconv;
3999
4000	vimconv.vc_type = CONV_NONE;
4001	if (convert_setup(&vimconv, client_enc, p_enc) != FAIL
4002					      && vimconv.vc_type != CONV_NONE)
4003	{
4004	    res = string_convert(&vimconv, data, NULL);
4005	    if (res == NULL)
4006		res = data;
4007	    else
4008		*tofree = res;
4009	}
4010	convert_setup(&vimconv, NULL, NULL);
4011    }
4012# endif
4013    return res;
4014}
4015
4016
4017/*
4018 * Make our basic server name: use the specified "arg" if given, otherwise use
4019 * the tail of the command "cmd" we were started with.
4020 * Return the name in allocated memory.  This doesn't include a serial number.
4021 */
4022    static char_u *
4023serverMakeName(arg, cmd)
4024    char_u	*arg;
4025    char	*cmd;
4026{
4027    char_u *p;
4028
4029    if (arg != NULL && *arg != NUL)
4030	p = vim_strsave_up(arg);
4031    else
4032    {
4033	p = vim_strsave_up(gettail((char_u *)cmd));
4034	/* Remove .exe or .bat from the name. */
4035	if (p != NULL && vim_strchr(p, '.') != NULL)
4036	    *vim_strchr(p, '.') = NUL;
4037    }
4038    return p;
4039}
4040#endif /* FEAT_CLIENTSERVER */
4041
4042/*
4043 * When FEAT_FKMAP is defined, also compile the Farsi source code.
4044 */
4045#if defined(FEAT_FKMAP) || defined(PROTO)
4046# include "farsi.c"
4047#endif
4048
4049/*
4050 * When FEAT_ARABIC is defined, also compile the Arabic source code.
4051 */
4052#if defined(FEAT_ARABIC) || defined(PROTO)
4053# include "arabic.c"
4054#endif
4055