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