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