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