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