1 /* vi:set ts=8 sts=4 sw=4: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * ex_docmd.c: functions for executing an Ex command line. 12 */ 13 14 #include "vim.h" 15 16 static int quitmore = 0; 17 static int ex_pressedreturn = FALSE; 18 #ifndef FEAT_PRINTER 19 # define ex_hardcopy ex_ni 20 #endif 21 22 #ifdef FEAT_USR_CMDS 23 typedef struct ucmd 24 { 25 char_u *uc_name; /* The command name */ 26 long_u uc_argt; /* The argument type */ 27 char_u *uc_rep; /* The command's replacement string */ 28 long uc_def; /* The default value for a range/count */ 29 int uc_compl; /* completion type */ 30 int uc_addr_type; /* The command's address type */ 31 # ifdef FEAT_EVAL 32 scid_T uc_scriptID; /* SID where the command was defined */ 33 # ifdef FEAT_CMDL_COMPL 34 char_u *uc_compl_arg; /* completion argument if any */ 35 # endif 36 # endif 37 } ucmd_T; 38 39 #define UC_BUFFER 1 /* -buffer: local to current buffer */ 40 41 static garray_T ucmds = {0, 0, sizeof(ucmd_T), 4, NULL}; 42 43 #define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i]) 44 #define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i]) 45 46 static void do_ucmd(exarg_T *eap); 47 static void ex_command(exarg_T *eap); 48 static void ex_delcommand(exarg_T *eap); 49 # ifdef FEAT_CMDL_COMPL 50 static char_u *get_user_command_name(int idx); 51 # endif 52 53 /* Wether a command index indicates a user command. */ 54 # define IS_USER_CMDIDX(idx) ((int)(idx) < 0) 55 56 #else 57 # define ex_command ex_ni 58 # define ex_comclear ex_ni 59 # define ex_delcommand ex_ni 60 /* Wether a command index indicates a user command. */ 61 # define IS_USER_CMDIDX(idx) (FALSE) 62 #endif 63 64 static int compute_buffer_local_count(int addr_type, int lnum, int local); 65 #ifdef FEAT_EVAL 66 static char_u *do_one_cmd(char_u **, int, struct condstack *, char_u *(*fgetline)(int, void *, int), void *cookie); 67 #else 68 static char_u *do_one_cmd(char_u **, int, char_u *(*fgetline)(int, void *, int), void *cookie); 69 static int if_level = 0; /* depth in :if */ 70 #endif 71 static void append_command(char_u *cmd); 72 static char_u *find_command(exarg_T *eap, int *full); 73 74 static void ex_abbreviate(exarg_T *eap); 75 static void ex_map(exarg_T *eap); 76 static void ex_unmap(exarg_T *eap); 77 static void ex_mapclear(exarg_T *eap); 78 static void ex_abclear(exarg_T *eap); 79 #ifndef FEAT_MENU 80 # define ex_emenu ex_ni 81 # define ex_menu ex_ni 82 # define ex_menutranslate ex_ni 83 #endif 84 #ifdef FEAT_AUTOCMD 85 static void ex_autocmd(exarg_T *eap); 86 static void ex_doautocmd(exarg_T *eap); 87 #else 88 # define ex_autocmd ex_ni 89 # define ex_doautocmd ex_ni 90 # define ex_doautoall ex_ni 91 #endif 92 #ifdef FEAT_LISTCMDS 93 static void ex_bunload(exarg_T *eap); 94 static void ex_buffer(exarg_T *eap); 95 static void ex_bmodified(exarg_T *eap); 96 static void ex_bnext(exarg_T *eap); 97 static void ex_bprevious(exarg_T *eap); 98 static void ex_brewind(exarg_T *eap); 99 static void ex_blast(exarg_T *eap); 100 #else 101 # define ex_bunload ex_ni 102 # define ex_buffer ex_ni 103 # define ex_bmodified ex_ni 104 # define ex_bnext ex_ni 105 # define ex_bprevious ex_ni 106 # define ex_brewind ex_ni 107 # define ex_blast ex_ni 108 # define buflist_list ex_ni 109 # define ex_checktime ex_ni 110 #endif 111 #if !defined(FEAT_LISTCMDS) || !defined(FEAT_WINDOWS) 112 # define ex_buffer_all ex_ni 113 #endif 114 static char_u *getargcmd(char_u **); 115 static char_u *skip_cmd_arg(char_u *p, int rembs); 116 static int getargopt(exarg_T *eap); 117 #ifndef FEAT_QUICKFIX 118 # define ex_make ex_ni 119 # define ex_cbuffer ex_ni 120 # define ex_cc ex_ni 121 # define ex_cnext ex_ni 122 # define ex_cfile ex_ni 123 # define qf_list ex_ni 124 # define qf_age ex_ni 125 # define ex_helpgrep ex_ni 126 # define ex_vimgrep ex_ni 127 #endif 128 #if !defined(FEAT_QUICKFIX) || !defined(FEAT_WINDOWS) 129 # define ex_cclose ex_ni 130 # define ex_copen ex_ni 131 # define ex_cwindow ex_ni 132 #endif 133 #if !defined(FEAT_QUICKFIX) || !defined(FEAT_EVAL) 134 # define ex_cexpr ex_ni 135 #endif 136 137 static int check_more(int, int); 138 static linenr_T get_address(exarg_T *, char_u **, int addr_type, int skip, int to_other_file); 139 static void get_flags(exarg_T *eap); 140 #if !defined(FEAT_PERL) \ 141 || !defined(FEAT_PYTHON) || !defined(FEAT_PYTHON3) \ 142 || !defined(FEAT_TCL) \ 143 || !defined(FEAT_RUBY) \ 144 || !defined(FEAT_LUA) \ 145 || !defined(FEAT_MZSCHEME) 146 # define HAVE_EX_SCRIPT_NI 147 static void ex_script_ni(exarg_T *eap); 148 #endif 149 static char_u *invalid_range(exarg_T *eap); 150 static void correct_range(exarg_T *eap); 151 #ifdef FEAT_QUICKFIX 152 static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep); 153 #endif 154 static char_u *repl_cmdline(exarg_T *eap, char_u *src, int srclen, char_u *repl, char_u **cmdlinep); 155 static void ex_highlight(exarg_T *eap); 156 static void ex_colorscheme(exarg_T *eap); 157 static void ex_quit(exarg_T *eap); 158 static void ex_cquit(exarg_T *eap); 159 static void ex_quit_all(exarg_T *eap); 160 #ifdef FEAT_WINDOWS 161 static void ex_close(exarg_T *eap); 162 static void ex_win_close(int forceit, win_T *win, tabpage_T *tp); 163 static void ex_only(exarg_T *eap); 164 static void ex_resize(exarg_T *eap); 165 static void ex_stag(exarg_T *eap); 166 static void ex_tabclose(exarg_T *eap); 167 static void ex_tabonly(exarg_T *eap); 168 static void ex_tabnext(exarg_T *eap); 169 static void ex_tabmove(exarg_T *eap); 170 static void ex_tabs(exarg_T *eap); 171 #else 172 # define ex_close ex_ni 173 # define ex_only ex_ni 174 # define ex_all ex_ni 175 # define ex_resize ex_ni 176 # define ex_splitview ex_ni 177 # define ex_stag ex_ni 178 # define ex_tabnext ex_ni 179 # define ex_tabmove ex_ni 180 # define ex_tabs ex_ni 181 # define ex_tabclose ex_ni 182 # define ex_tabonly ex_ni 183 #endif 184 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 185 static void ex_pclose(exarg_T *eap); 186 static void ex_ptag(exarg_T *eap); 187 static void ex_pedit(exarg_T *eap); 188 #else 189 # define ex_pclose ex_ni 190 # define ex_ptag ex_ni 191 # define ex_pedit ex_ni 192 #endif 193 static void ex_hide(exarg_T *eap); 194 static void ex_stop(exarg_T *eap); 195 static void ex_exit(exarg_T *eap); 196 static void ex_print(exarg_T *eap); 197 #ifdef FEAT_BYTEOFF 198 static void ex_goto(exarg_T *eap); 199 #else 200 # define ex_goto ex_ni 201 #endif 202 static void ex_shell(exarg_T *eap); 203 static void ex_preserve(exarg_T *eap); 204 static void ex_recover(exarg_T *eap); 205 #ifndef FEAT_LISTCMDS 206 # define ex_argedit ex_ni 207 # define ex_argadd ex_ni 208 # define ex_argdelete ex_ni 209 # define ex_listdo ex_ni 210 #endif 211 static void ex_mode(exarg_T *eap); 212 static void ex_wrongmodifier(exarg_T *eap); 213 static void ex_find(exarg_T *eap); 214 static void ex_open(exarg_T *eap); 215 static void ex_edit(exarg_T *eap); 216 #if !defined(FEAT_GUI) && !defined(FEAT_CLIENTSERVER) 217 # define ex_drop ex_ni 218 #endif 219 #ifndef FEAT_GUI 220 # define ex_gui ex_nogui 221 static void ex_nogui(exarg_T *eap); 222 #endif 223 #if defined(FEAT_GUI_W32) && defined(FEAT_MENU) && defined(FEAT_TEAROFF) 224 static void ex_tearoff(exarg_T *eap); 225 #else 226 # define ex_tearoff ex_ni 227 #endif 228 #if (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK)) && defined(FEAT_MENU) 229 static void ex_popup(exarg_T *eap); 230 #else 231 # define ex_popup ex_ni 232 #endif 233 #ifndef FEAT_GUI_MSWIN 234 # define ex_simalt ex_ni 235 #endif 236 #if !defined(FEAT_GUI_MSWIN) && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF) 237 # define gui_mch_find_dialog ex_ni 238 # define gui_mch_replace_dialog ex_ni 239 #endif 240 #if !defined(FEAT_GUI_GTK) 241 # define ex_helpfind ex_ni 242 #endif 243 #ifndef FEAT_CSCOPE 244 # define do_cscope ex_ni 245 # define do_scscope ex_ni 246 # define do_cstag ex_ni 247 #endif 248 #ifndef FEAT_SYN_HL 249 # define ex_syntax ex_ni 250 # define ex_ownsyntax ex_ni 251 #endif 252 #if !defined(FEAT_SYN_HL) || !defined(FEAT_PROFILE) 253 # define ex_syntime ex_ni 254 #endif 255 #ifndef FEAT_SPELL 256 # define ex_spell ex_ni 257 # define ex_mkspell ex_ni 258 # define ex_spelldump ex_ni 259 # define ex_spellinfo ex_ni 260 # define ex_spellrepall ex_ni 261 #endif 262 #ifndef FEAT_PERSISTENT_UNDO 263 # define ex_rundo ex_ni 264 # define ex_wundo ex_ni 265 #endif 266 #ifndef FEAT_LUA 267 # define ex_lua ex_script_ni 268 # define ex_luado ex_ni 269 # define ex_luafile ex_ni 270 #endif 271 #ifndef FEAT_MZSCHEME 272 # define ex_mzscheme ex_script_ni 273 # define ex_mzfile ex_ni 274 #endif 275 #ifndef FEAT_PERL 276 # define ex_perl ex_script_ni 277 # define ex_perldo ex_ni 278 #endif 279 #ifndef FEAT_PYTHON 280 # define ex_python ex_script_ni 281 # define ex_pydo ex_ni 282 # define ex_pyfile ex_ni 283 #endif 284 #ifndef FEAT_PYTHON3 285 # define ex_py3 ex_script_ni 286 # define ex_py3do ex_ni 287 # define ex_py3file ex_ni 288 #endif 289 #ifndef FEAT_TCL 290 # define ex_tcl ex_script_ni 291 # define ex_tcldo ex_ni 292 # define ex_tclfile ex_ni 293 #endif 294 #ifndef FEAT_RUBY 295 # define ex_ruby ex_script_ni 296 # define ex_rubydo ex_ni 297 # define ex_rubyfile ex_ni 298 #endif 299 #ifndef FEAT_KEYMAP 300 # define ex_loadkeymap ex_ni 301 #endif 302 static void ex_swapname(exarg_T *eap); 303 static void ex_syncbind(exarg_T *eap); 304 static void ex_read(exarg_T *eap); 305 static void ex_pwd(exarg_T *eap); 306 static void ex_equal(exarg_T *eap); 307 static void ex_sleep(exarg_T *eap); 308 static void do_exmap(exarg_T *eap, int isabbrev); 309 static void ex_winsize(exarg_T *eap); 310 #ifdef FEAT_WINDOWS 311 static void ex_wincmd(exarg_T *eap); 312 #else 313 # define ex_wincmd ex_ni 314 #endif 315 #if defined(FEAT_GUI) || defined(UNIX) || defined(VMS) || defined(MSWIN) 316 static void ex_winpos(exarg_T *eap); 317 #else 318 # define ex_winpos ex_ni 319 #endif 320 static void ex_operators(exarg_T *eap); 321 static void ex_put(exarg_T *eap); 322 static void ex_copymove(exarg_T *eap); 323 static void ex_submagic(exarg_T *eap); 324 static void ex_join(exarg_T *eap); 325 static void ex_at(exarg_T *eap); 326 static void ex_bang(exarg_T *eap); 327 static void ex_undo(exarg_T *eap); 328 #ifdef FEAT_PERSISTENT_UNDO 329 static void ex_wundo(exarg_T *eap); 330 static void ex_rundo(exarg_T *eap); 331 #endif 332 static void ex_redo(exarg_T *eap); 333 static void ex_later(exarg_T *eap); 334 static void ex_redir(exarg_T *eap); 335 static void ex_redrawstatus(exarg_T *eap); 336 static void close_redir(void); 337 static void ex_mkrc(exarg_T *eap); 338 static void ex_mark(exarg_T *eap); 339 #ifdef FEAT_USR_CMDS 340 static char_u *uc_fun_cmd(void); 341 static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *compl); 342 #endif 343 static void ex_startinsert(exarg_T *eap); 344 static void ex_stopinsert(exarg_T *eap); 345 #ifdef FEAT_FIND_ID 346 static void ex_checkpath(exarg_T *eap); 347 static void ex_findpat(exarg_T *eap); 348 #else 349 # define ex_findpat ex_ni 350 # define ex_checkpath ex_ni 351 #endif 352 #if defined(FEAT_FIND_ID) && defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 353 static void ex_psearch(exarg_T *eap); 354 #else 355 # define ex_psearch ex_ni 356 #endif 357 static void ex_tag(exarg_T *eap); 358 static void ex_tag_cmd(exarg_T *eap, char_u *name); 359 #ifndef FEAT_EVAL 360 # define ex_scriptnames ex_ni 361 # define ex_finish ex_ni 362 # define ex_echo ex_ni 363 # define ex_echohl ex_ni 364 # define ex_execute ex_ni 365 # define ex_call ex_ni 366 # define ex_if ex_ni 367 # define ex_endif ex_ni 368 # define ex_else ex_ni 369 # define ex_while ex_ni 370 # define ex_continue ex_ni 371 # define ex_break ex_ni 372 # define ex_endwhile ex_ni 373 # define ex_throw ex_ni 374 # define ex_try ex_ni 375 # define ex_catch ex_ni 376 # define ex_finally ex_ni 377 # define ex_endtry ex_ni 378 # define ex_endfunction ex_ni 379 # define ex_let ex_ni 380 # define ex_unlet ex_ni 381 # define ex_lockvar ex_ni 382 # define ex_unlockvar ex_ni 383 # define ex_function ex_ni 384 # define ex_delfunction ex_ni 385 # define ex_return ex_ni 386 # define ex_oldfiles ex_ni 387 #endif 388 static char_u *arg_all(void); 389 #ifdef FEAT_SESSION 390 static int makeopens(FILE *fd, char_u *dirnow); 391 static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int current_arg_idx); 392 static void ex_loadview(exarg_T *eap); 393 static char_u *get_view_file(int c); 394 static int did_lcd; /* whether ":lcd" was produced for a session */ 395 #else 396 # define ex_loadview ex_ni 397 #endif 398 #ifndef FEAT_EVAL 399 # define ex_compiler ex_ni 400 #endif 401 #ifdef FEAT_VIMINFO 402 static void ex_viminfo(exarg_T *eap); 403 #else 404 # define ex_viminfo ex_ni 405 #endif 406 static void ex_behave(exarg_T *eap); 407 #ifdef FEAT_AUTOCMD 408 static void ex_filetype(exarg_T *eap); 409 static void ex_setfiletype(exarg_T *eap); 410 #else 411 # define ex_filetype ex_ni 412 # define ex_setfiletype ex_ni 413 #endif 414 #ifndef FEAT_DIFF 415 # define ex_diffoff ex_ni 416 # define ex_diffpatch ex_ni 417 # define ex_diffgetput ex_ni 418 # define ex_diffsplit ex_ni 419 # define ex_diffthis ex_ni 420 # define ex_diffupdate ex_ni 421 #endif 422 static void ex_digraphs(exarg_T *eap); 423 static void ex_set(exarg_T *eap); 424 #if !defined(FEAT_EVAL) || !defined(FEAT_AUTOCMD) 425 # define ex_options ex_ni 426 #endif 427 #ifdef FEAT_SEARCH_EXTRA 428 static void ex_nohlsearch(exarg_T *eap); 429 static void ex_match(exarg_T *eap); 430 #else 431 # define ex_nohlsearch ex_ni 432 # define ex_match ex_ni 433 #endif 434 #ifdef FEAT_CRYPT 435 static void ex_X(exarg_T *eap); 436 #else 437 # define ex_X ex_ni 438 #endif 439 #ifdef FEAT_FOLDING 440 static void ex_fold(exarg_T *eap); 441 static void ex_foldopen(exarg_T *eap); 442 static void ex_folddo(exarg_T *eap); 443 #else 444 # define ex_fold ex_ni 445 # define ex_foldopen ex_ni 446 # define ex_folddo ex_ni 447 #endif 448 #if !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 449 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))) 450 # define ex_language ex_ni 451 #endif 452 #ifndef FEAT_SIGNS 453 # define ex_sign ex_ni 454 #endif 455 #ifndef FEAT_SUN_WORKSHOP 456 # define ex_wsverb ex_ni 457 #endif 458 #ifndef FEAT_NETBEANS_INTG 459 # define ex_nbclose ex_ni 460 # define ex_nbkey ex_ni 461 # define ex_nbstart ex_ni 462 #endif 463 464 #ifndef FEAT_EVAL 465 # define ex_debug ex_ni 466 # define ex_breakadd ex_ni 467 # define ex_debuggreedy ex_ni 468 # define ex_breakdel ex_ni 469 # define ex_breaklist ex_ni 470 #endif 471 472 #ifndef FEAT_CMDHIST 473 # define ex_history ex_ni 474 #endif 475 #ifndef FEAT_JUMPLIST 476 # define ex_jumps ex_ni 477 # define ex_changes ex_ni 478 #endif 479 480 #ifndef FEAT_PROFILE 481 # define ex_profile ex_ni 482 #endif 483 484 /* 485 * Declare cmdnames[]. 486 */ 487 #define DO_DECLARE_EXCMD 488 #include "ex_cmds.h" 489 490 /* 491 * Table used to quickly search for a command, based on its first character. 492 */ 493 static cmdidx_T cmdidxs[27] = 494 { 495 CMD_append, 496 CMD_buffer, 497 CMD_change, 498 CMD_delete, 499 CMD_edit, 500 CMD_file, 501 CMD_global, 502 CMD_help, 503 CMD_insert, 504 CMD_join, 505 CMD_k, 506 CMD_list, 507 CMD_move, 508 CMD_next, 509 CMD_open, 510 CMD_print, 511 CMD_quit, 512 CMD_read, 513 CMD_substitute, 514 CMD_t, 515 CMD_undo, 516 CMD_vglobal, 517 CMD_write, 518 CMD_xit, 519 CMD_yank, 520 CMD_z, 521 CMD_bang 522 }; 523 524 static char_u dollar_command[2] = {'$', 0}; 525 526 527 #ifdef FEAT_EVAL 528 /* Struct for storing a line inside a while/for loop */ 529 typedef struct 530 { 531 char_u *line; /* command line */ 532 linenr_T lnum; /* sourcing_lnum of the line */ 533 } wcmd_T; 534 535 /* 536 * Structure used to store info for line position in a while or for loop. 537 * This is required, because do_one_cmd() may invoke ex_function(), which 538 * reads more lines that may come from the while/for loop. 539 */ 540 struct loop_cookie 541 { 542 garray_T *lines_gap; /* growarray with line info */ 543 int current_line; /* last read line from growarray */ 544 int repeating; /* TRUE when looping a second time */ 545 /* When "repeating" is FALSE use "getline" and "cookie" to get lines */ 546 char_u *(*getline)(int, void *, int); 547 void *cookie; 548 }; 549 550 static char_u *get_loop_line(int c, void *cookie, int indent); 551 static int store_loop_line(garray_T *gap, char_u *line); 552 static void free_cmdlines(garray_T *gap); 553 554 /* Struct to save a few things while debugging. Used in do_cmdline() only. */ 555 struct dbg_stuff 556 { 557 int trylevel; 558 int force_abort; 559 except_T *caught_stack; 560 char_u *vv_exception; 561 char_u *vv_throwpoint; 562 int did_emsg; 563 int got_int; 564 int did_throw; 565 int need_rethrow; 566 int check_cstack; 567 except_T *current_exception; 568 }; 569 570 static void save_dbg_stuff(struct dbg_stuff *dsp); 571 static void restore_dbg_stuff(struct dbg_stuff *dsp); 572 573 static void 574 save_dbg_stuff(struct dbg_stuff *dsp) 575 { 576 dsp->trylevel = trylevel; trylevel = 0; 577 dsp->force_abort = force_abort; force_abort = FALSE; 578 dsp->caught_stack = caught_stack; caught_stack = NULL; 579 dsp->vv_exception = v_exception(NULL); 580 dsp->vv_throwpoint = v_throwpoint(NULL); 581 582 /* Necessary for debugging an inactive ":catch", ":finally", ":endtry" */ 583 dsp->did_emsg = did_emsg; did_emsg = FALSE; 584 dsp->got_int = got_int; got_int = FALSE; 585 dsp->did_throw = did_throw; did_throw = FALSE; 586 dsp->need_rethrow = need_rethrow; need_rethrow = FALSE; 587 dsp->check_cstack = check_cstack; check_cstack = FALSE; 588 dsp->current_exception = current_exception; current_exception = NULL; 589 } 590 591 static void 592 restore_dbg_stuff(struct dbg_stuff *dsp) 593 { 594 suppress_errthrow = FALSE; 595 trylevel = dsp->trylevel; 596 force_abort = dsp->force_abort; 597 caught_stack = dsp->caught_stack; 598 (void)v_exception(dsp->vv_exception); 599 (void)v_throwpoint(dsp->vv_throwpoint); 600 did_emsg = dsp->did_emsg; 601 got_int = dsp->got_int; 602 did_throw = dsp->did_throw; 603 need_rethrow = dsp->need_rethrow; 604 check_cstack = dsp->check_cstack; 605 current_exception = dsp->current_exception; 606 } 607 #endif 608 609 610 /* 611 * do_exmode(): Repeatedly get commands for the "Ex" mode, until the ":vi" 612 * command is given. 613 */ 614 void 615 do_exmode( 616 int improved) /* TRUE for "improved Ex" mode */ 617 { 618 int save_msg_scroll; 619 int prev_msg_row; 620 linenr_T prev_line; 621 int changedtick; 622 623 if (improved) 624 exmode_active = EXMODE_VIM; 625 else 626 exmode_active = EXMODE_NORMAL; 627 State = NORMAL; 628 629 /* When using ":global /pat/ visual" and then "Q" we return to continue 630 * the :global command. */ 631 if (global_busy) 632 return; 633 634 save_msg_scroll = msg_scroll; 635 ++RedrawingDisabled; /* don't redisplay the window */ 636 ++no_wait_return; /* don't wait for return */ 637 #ifdef FEAT_GUI 638 /* Ignore scrollbar and mouse events in Ex mode */ 639 ++hold_gui_events; 640 #endif 641 642 MSG(_("Entering Ex mode. Type \"visual\" to go to Normal mode.")); 643 while (exmode_active) 644 { 645 /* Check for a ":normal" command and no more characters left. */ 646 if (ex_normal_busy > 0 && typebuf.tb_len == 0) 647 { 648 exmode_active = FALSE; 649 break; 650 } 651 msg_scroll = TRUE; 652 need_wait_return = FALSE; 653 ex_pressedreturn = FALSE; 654 ex_no_reprint = FALSE; 655 changedtick = curbuf->b_changedtick; 656 prev_msg_row = msg_row; 657 prev_line = curwin->w_cursor.lnum; 658 if (improved) 659 { 660 cmdline_row = msg_row; 661 do_cmdline(NULL, getexline, NULL, 0); 662 } 663 else 664 do_cmdline(NULL, getexmodeline, NULL, DOCMD_NOWAIT); 665 lines_left = Rows - 1; 666 667 if ((prev_line != curwin->w_cursor.lnum 668 || changedtick != curbuf->b_changedtick) && !ex_no_reprint) 669 { 670 if (curbuf->b_ml.ml_flags & ML_EMPTY) 671 EMSG(_(e_emptybuf)); 672 else 673 { 674 if (ex_pressedreturn) 675 { 676 /* go up one line, to overwrite the ":<CR>" line, so the 677 * output doesn't contain empty lines. */ 678 msg_row = prev_msg_row; 679 if (prev_msg_row == Rows - 1) 680 msg_row--; 681 } 682 msg_col = 0; 683 print_line_no_prefix(curwin->w_cursor.lnum, FALSE, FALSE); 684 msg_clr_eos(); 685 } 686 } 687 else if (ex_pressedreturn && !ex_no_reprint) /* must be at EOF */ 688 { 689 if (curbuf->b_ml.ml_flags & ML_EMPTY) 690 EMSG(_(e_emptybuf)); 691 else 692 EMSG(_("E501: At end-of-file")); 693 } 694 } 695 696 #ifdef FEAT_GUI 697 --hold_gui_events; 698 #endif 699 --RedrawingDisabled; 700 --no_wait_return; 701 update_screen(CLEAR); 702 need_wait_return = FALSE; 703 msg_scroll = save_msg_scroll; 704 } 705 706 /* 707 * Execute a simple command line. Used for translated commands like "*". 708 */ 709 int 710 do_cmdline_cmd(char_u *cmd) 711 { 712 return do_cmdline(cmd, NULL, NULL, 713 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); 714 } 715 716 /* 717 * do_cmdline(): execute one Ex command line 718 * 719 * 1. Execute "cmdline" when it is not NULL. 720 * If "cmdline" is NULL, or more lines are needed, fgetline() is used. 721 * 2. Split up in parts separated with '|'. 722 * 723 * This function can be called recursively! 724 * 725 * flags: 726 * DOCMD_VERBOSE - The command will be included in the error message. 727 * DOCMD_NOWAIT - Don't call wait_return() and friends. 728 * DOCMD_REPEAT - Repeat execution until fgetline() returns NULL. 729 * DOCMD_KEYTYPED - Don't reset KeyTyped. 730 * DOCMD_EXCRESET - Reset the exception environment (used for debugging). 731 * DOCMD_KEEPLINE - Store first typed line (for repeating with "."). 732 * 733 * return FAIL if cmdline could not be executed, OK otherwise 734 */ 735 int 736 do_cmdline( 737 char_u *cmdline, 738 char_u *(*fgetline)(int, void *, int), 739 void *cookie, /* argument for fgetline() */ 740 int flags) 741 { 742 char_u *next_cmdline; /* next cmd to execute */ 743 char_u *cmdline_copy = NULL; /* copy of cmd line */ 744 int used_getline = FALSE; /* used "fgetline" to obtain command */ 745 static int recursive = 0; /* recursive depth */ 746 int msg_didout_before_start = 0; 747 int count = 0; /* line number count */ 748 int did_inc = FALSE; /* incremented RedrawingDisabled */ 749 int retval = OK; 750 #ifdef FEAT_EVAL 751 struct condstack cstack; /* conditional stack */ 752 garray_T lines_ga; /* keep lines for ":while"/":for" */ 753 int current_line = 0; /* active line in lines_ga */ 754 char_u *fname = NULL; /* function or script name */ 755 linenr_T *breakpoint = NULL; /* ptr to breakpoint field in cookie */ 756 int *dbg_tick = NULL; /* ptr to dbg_tick field in cookie */ 757 struct dbg_stuff debug_saved; /* saved things for debug mode */ 758 int initial_trylevel; 759 struct msglist **saved_msg_list = NULL; 760 struct msglist *private_msg_list; 761 762 /* "fgetline" and "cookie" passed to do_one_cmd() */ 763 char_u *(*cmd_getline)(int, void *, int); 764 void *cmd_cookie; 765 struct loop_cookie cmd_loop_cookie; 766 void *real_cookie; 767 int getline_is_func; 768 #else 769 # define cmd_getline fgetline 770 # define cmd_cookie cookie 771 #endif 772 static int call_depth = 0; /* recursiveness */ 773 774 #ifdef FEAT_EVAL 775 /* For every pair of do_cmdline()/do_one_cmd() calls, use an extra memory 776 * location for storing error messages to be converted to an exception. 777 * This ensures that the do_errthrow() call in do_one_cmd() does not 778 * combine the messages stored by an earlier invocation of do_one_cmd() 779 * with the command name of the later one. This would happen when 780 * BufWritePost autocommands are executed after a write error. */ 781 saved_msg_list = msg_list; 782 msg_list = &private_msg_list; 783 private_msg_list = NULL; 784 #endif 785 786 /* It's possible to create an endless loop with ":execute", catch that 787 * here. The value of 200 allows nested function calls, ":source", etc. */ 788 if (call_depth == 200) 789 { 790 EMSG(_("E169: Command too recursive")); 791 #ifdef FEAT_EVAL 792 /* When converting to an exception, we do not include the command name 793 * since this is not an error of the specific command. */ 794 do_errthrow((struct condstack *)NULL, (char_u *)NULL); 795 msg_list = saved_msg_list; 796 #endif 797 return FAIL; 798 } 799 ++call_depth; 800 801 #ifdef FEAT_EVAL 802 cstack.cs_idx = -1; 803 cstack.cs_looplevel = 0; 804 cstack.cs_trylevel = 0; 805 cstack.cs_emsg_silent_list = NULL; 806 cstack.cs_lflags = 0; 807 ga_init2(&lines_ga, (int)sizeof(wcmd_T), 10); 808 809 real_cookie = getline_cookie(fgetline, cookie); 810 811 /* Inside a function use a higher nesting level. */ 812 getline_is_func = getline_equal(fgetline, cookie, get_func_line); 813 if (getline_is_func && ex_nesting_level == func_level(real_cookie)) 814 ++ex_nesting_level; 815 816 /* Get the function or script name and the address where the next breakpoint 817 * line and the debug tick for a function or script are stored. */ 818 if (getline_is_func) 819 { 820 fname = func_name(real_cookie); 821 breakpoint = func_breakpoint(real_cookie); 822 dbg_tick = func_dbg_tick(real_cookie); 823 } 824 else if (getline_equal(fgetline, cookie, getsourceline)) 825 { 826 fname = sourcing_name; 827 breakpoint = source_breakpoint(real_cookie); 828 dbg_tick = source_dbg_tick(real_cookie); 829 } 830 831 /* 832 * Initialize "force_abort" and "suppress_errthrow" at the top level. 833 */ 834 if (!recursive) 835 { 836 force_abort = FALSE; 837 suppress_errthrow = FALSE; 838 } 839 840 /* 841 * If requested, store and reset the global values controlling the 842 * exception handling (used when debugging). Otherwise clear it to avoid 843 * a bogus compiler warning when the optimizer uses inline functions... 844 */ 845 if (flags & DOCMD_EXCRESET) 846 save_dbg_stuff(&debug_saved); 847 else 848 vim_memset(&debug_saved, 0, sizeof(debug_saved)); 849 850 initial_trylevel = trylevel; 851 852 /* 853 * "did_throw" will be set to TRUE when an exception is being thrown. 854 */ 855 did_throw = FALSE; 856 #endif 857 /* 858 * "did_emsg" will be set to TRUE when emsg() is used, in which case we 859 * cancel the whole command line, and any if/endif or loop. 860 * If force_abort is set, we cancel everything. 861 */ 862 did_emsg = FALSE; 863 864 /* 865 * KeyTyped is only set when calling vgetc(). Reset it here when not 866 * calling vgetc() (sourced command lines). 867 */ 868 if (!(flags & DOCMD_KEYTYPED) 869 && !getline_equal(fgetline, cookie, getexline)) 870 KeyTyped = FALSE; 871 872 /* 873 * Continue executing command lines: 874 * - when inside an ":if", ":while" or ":for" 875 * - for multiple commands on one line, separated with '|' 876 * - when repeating until there are no more lines (for ":source") 877 */ 878 next_cmdline = cmdline; 879 do 880 { 881 #ifdef FEAT_EVAL 882 getline_is_func = getline_equal(fgetline, cookie, get_func_line); 883 #endif 884 885 /* stop skipping cmds for an error msg after all endif/while/for */ 886 if (next_cmdline == NULL 887 #ifdef FEAT_EVAL 888 && !force_abort 889 && cstack.cs_idx < 0 890 && !(getline_is_func && func_has_abort(real_cookie)) 891 #endif 892 ) 893 did_emsg = FALSE; 894 895 /* 896 * 1. If repeating a line in a loop, get a line from lines_ga. 897 * 2. If no line given: Get an allocated line with fgetline(). 898 * 3. If a line is given: Make a copy, so we can mess with it. 899 */ 900 901 #ifdef FEAT_EVAL 902 /* 1. If repeating, get a previous line from lines_ga. */ 903 if (cstack.cs_looplevel > 0 && current_line < lines_ga.ga_len) 904 { 905 /* Each '|' separated command is stored separately in lines_ga, to 906 * be able to jump to it. Don't use next_cmdline now. */ 907 vim_free(cmdline_copy); 908 cmdline_copy = NULL; 909 910 /* Check if a function has returned or, unless it has an unclosed 911 * try conditional, aborted. */ 912 if (getline_is_func) 913 { 914 # ifdef FEAT_PROFILE 915 if (do_profiling == PROF_YES) 916 func_line_end(real_cookie); 917 # endif 918 if (func_has_ended(real_cookie)) 919 { 920 retval = FAIL; 921 break; 922 } 923 } 924 #ifdef FEAT_PROFILE 925 else if (do_profiling == PROF_YES 926 && getline_equal(fgetline, cookie, getsourceline)) 927 script_line_end(); 928 #endif 929 930 /* Check if a sourced file hit a ":finish" command. */ 931 if (source_finished(fgetline, cookie)) 932 { 933 retval = FAIL; 934 break; 935 } 936 937 /* If breakpoints have been added/deleted need to check for it. */ 938 if (breakpoint != NULL && dbg_tick != NULL 939 && *dbg_tick != debug_tick) 940 { 941 *breakpoint = dbg_find_breakpoint( 942 getline_equal(fgetline, cookie, getsourceline), 943 fname, sourcing_lnum); 944 *dbg_tick = debug_tick; 945 } 946 947 next_cmdline = ((wcmd_T *)(lines_ga.ga_data))[current_line].line; 948 sourcing_lnum = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum; 949 950 /* Did we encounter a breakpoint? */ 951 if (breakpoint != NULL && *breakpoint != 0 952 && *breakpoint <= sourcing_lnum) 953 { 954 dbg_breakpoint(fname, sourcing_lnum); 955 /* Find next breakpoint. */ 956 *breakpoint = dbg_find_breakpoint( 957 getline_equal(fgetline, cookie, getsourceline), 958 fname, sourcing_lnum); 959 *dbg_tick = debug_tick; 960 } 961 # ifdef FEAT_PROFILE 962 if (do_profiling == PROF_YES) 963 { 964 if (getline_is_func) 965 func_line_start(real_cookie); 966 else if (getline_equal(fgetline, cookie, getsourceline)) 967 script_line_start(); 968 } 969 # endif 970 } 971 972 if (cstack.cs_looplevel > 0) 973 { 974 /* Inside a while/for loop we need to store the lines and use them 975 * again. Pass a different "fgetline" function to do_one_cmd() 976 * below, so that it stores lines in or reads them from 977 * "lines_ga". Makes it possible to define a function inside a 978 * while/for loop. */ 979 cmd_getline = get_loop_line; 980 cmd_cookie = (void *)&cmd_loop_cookie; 981 cmd_loop_cookie.lines_gap = &lines_ga; 982 cmd_loop_cookie.current_line = current_line; 983 cmd_loop_cookie.getline = fgetline; 984 cmd_loop_cookie.cookie = cookie; 985 cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); 986 } 987 else 988 { 989 cmd_getline = fgetline; 990 cmd_cookie = cookie; 991 } 992 #endif 993 994 /* 2. If no line given, get an allocated line with fgetline(). */ 995 if (next_cmdline == NULL) 996 { 997 /* 998 * Need to set msg_didout for the first line after an ":if", 999 * otherwise the ":if" will be overwritten. 1000 */ 1001 if (count == 1 && getline_equal(fgetline, cookie, getexline)) 1002 msg_didout = TRUE; 1003 if (fgetline == NULL || (next_cmdline = fgetline(':', cookie, 1004 #ifdef FEAT_EVAL 1005 cstack.cs_idx < 0 ? 0 : (cstack.cs_idx + 1) * 2 1006 #else 1007 0 1008 #endif 1009 )) == NULL) 1010 { 1011 /* Don't call wait_return for aborted command line. The NULL 1012 * returned for the end of a sourced file or executed function 1013 * doesn't do this. */ 1014 if (KeyTyped && !(flags & DOCMD_REPEAT)) 1015 need_wait_return = FALSE; 1016 retval = FAIL; 1017 break; 1018 } 1019 used_getline = TRUE; 1020 1021 /* 1022 * Keep the first typed line. Clear it when more lines are typed. 1023 */ 1024 if (flags & DOCMD_KEEPLINE) 1025 { 1026 vim_free(repeat_cmdline); 1027 if (count == 0) 1028 repeat_cmdline = vim_strsave(next_cmdline); 1029 else 1030 repeat_cmdline = NULL; 1031 } 1032 } 1033 1034 /* 3. Make a copy of the command so we can mess with it. */ 1035 else if (cmdline_copy == NULL) 1036 { 1037 next_cmdline = vim_strsave(next_cmdline); 1038 if (next_cmdline == NULL) 1039 { 1040 EMSG(_(e_outofmem)); 1041 retval = FAIL; 1042 break; 1043 } 1044 } 1045 cmdline_copy = next_cmdline; 1046 1047 #ifdef FEAT_EVAL 1048 /* 1049 * Save the current line when inside a ":while" or ":for", and when 1050 * the command looks like a ":while" or ":for", because we may need it 1051 * later. When there is a '|' and another command, it is stored 1052 * separately, because we need to be able to jump back to it from an 1053 * :endwhile/:endfor. 1054 */ 1055 if (current_line == lines_ga.ga_len 1056 && (cstack.cs_looplevel || has_loop_cmd(next_cmdline))) 1057 { 1058 if (store_loop_line(&lines_ga, next_cmdline) == FAIL) 1059 { 1060 retval = FAIL; 1061 break; 1062 } 1063 } 1064 did_endif = FALSE; 1065 #endif 1066 1067 if (count++ == 0) 1068 { 1069 /* 1070 * All output from the commands is put below each other, without 1071 * waiting for a return. Don't do this when executing commands 1072 * from a script or when being called recursive (e.g. for ":e 1073 * +command file"). 1074 */ 1075 if (!(flags & DOCMD_NOWAIT) && !recursive) 1076 { 1077 msg_didout_before_start = msg_didout; 1078 msg_didany = FALSE; /* no output yet */ 1079 msg_start(); 1080 msg_scroll = TRUE; /* put messages below each other */ 1081 ++no_wait_return; /* don't wait for return until finished */ 1082 ++RedrawingDisabled; 1083 did_inc = TRUE; 1084 } 1085 } 1086 1087 if (p_verbose >= 15 && sourcing_name != NULL) 1088 { 1089 ++no_wait_return; 1090 verbose_enter_scroll(); 1091 1092 smsg((char_u *)_("line %ld: %s"), 1093 (long)sourcing_lnum, cmdline_copy); 1094 if (msg_silent == 0) 1095 msg_puts((char_u *)"\n"); /* don't overwrite this */ 1096 1097 verbose_leave_scroll(); 1098 --no_wait_return; 1099 } 1100 1101 /* 1102 * 2. Execute one '|' separated command. 1103 * do_one_cmd() will return NULL if there is no trailing '|'. 1104 * "cmdline_copy" can change, e.g. for '%' and '#' expansion. 1105 */ 1106 ++recursive; 1107 next_cmdline = do_one_cmd(&cmdline_copy, flags & DOCMD_VERBOSE, 1108 #ifdef FEAT_EVAL 1109 &cstack, 1110 #endif 1111 cmd_getline, cmd_cookie); 1112 --recursive; 1113 1114 #ifdef FEAT_EVAL 1115 if (cmd_cookie == (void *)&cmd_loop_cookie) 1116 /* Use "current_line" from "cmd_loop_cookie", it may have been 1117 * incremented when defining a function. */ 1118 current_line = cmd_loop_cookie.current_line; 1119 #endif 1120 1121 if (next_cmdline == NULL) 1122 { 1123 vim_free(cmdline_copy); 1124 cmdline_copy = NULL; 1125 #ifdef FEAT_CMDHIST 1126 /* 1127 * If the command was typed, remember it for the ':' register. 1128 * Do this AFTER executing the command to make :@: work. 1129 */ 1130 if (getline_equal(fgetline, cookie, getexline) 1131 && new_last_cmdline != NULL) 1132 { 1133 vim_free(last_cmdline); 1134 last_cmdline = new_last_cmdline; 1135 new_last_cmdline = NULL; 1136 } 1137 #endif 1138 } 1139 else 1140 { 1141 /* need to copy the command after the '|' to cmdline_copy, for the 1142 * next do_one_cmd() */ 1143 STRMOVE(cmdline_copy, next_cmdline); 1144 next_cmdline = cmdline_copy; 1145 } 1146 1147 1148 #ifdef FEAT_EVAL 1149 /* reset did_emsg for a function that is not aborted by an error */ 1150 if (did_emsg && !force_abort 1151 && getline_equal(fgetline, cookie, get_func_line) 1152 && !func_has_abort(real_cookie)) 1153 did_emsg = FALSE; 1154 1155 if (cstack.cs_looplevel > 0) 1156 { 1157 ++current_line; 1158 1159 /* 1160 * An ":endwhile", ":endfor" and ":continue" is handled here. 1161 * If we were executing commands, jump back to the ":while" or 1162 * ":for". 1163 * If we were not executing commands, decrement cs_looplevel. 1164 */ 1165 if (cstack.cs_lflags & (CSL_HAD_CONT | CSL_HAD_ENDLOOP)) 1166 { 1167 cstack.cs_lflags &= ~(CSL_HAD_CONT | CSL_HAD_ENDLOOP); 1168 1169 /* Jump back to the matching ":while" or ":for". Be careful 1170 * not to use a cs_line[] from an entry that isn't a ":while" 1171 * or ":for": It would make "current_line" invalid and can 1172 * cause a crash. */ 1173 if (!did_emsg && !got_int && !did_throw 1174 && cstack.cs_idx >= 0 1175 && (cstack.cs_flags[cstack.cs_idx] 1176 & (CSF_WHILE | CSF_FOR)) 1177 && cstack.cs_line[cstack.cs_idx] >= 0 1178 && (cstack.cs_flags[cstack.cs_idx] & CSF_ACTIVE)) 1179 { 1180 current_line = cstack.cs_line[cstack.cs_idx]; 1181 /* remember we jumped there */ 1182 cstack.cs_lflags |= CSL_HAD_LOOP; 1183 line_breakcheck(); /* check if CTRL-C typed */ 1184 1185 /* Check for the next breakpoint at or after the ":while" 1186 * or ":for". */ 1187 if (breakpoint != NULL) 1188 { 1189 *breakpoint = dbg_find_breakpoint( 1190 getline_equal(fgetline, cookie, getsourceline), 1191 fname, 1192 ((wcmd_T *)lines_ga.ga_data)[current_line].lnum-1); 1193 *dbg_tick = debug_tick; 1194 } 1195 } 1196 else 1197 { 1198 /* can only get here with ":endwhile" or ":endfor" */ 1199 if (cstack.cs_idx >= 0) 1200 rewind_conditionals(&cstack, cstack.cs_idx - 1, 1201 CSF_WHILE | CSF_FOR, &cstack.cs_looplevel); 1202 } 1203 } 1204 1205 /* 1206 * For a ":while" or ":for" we need to remember the line number. 1207 */ 1208 else if (cstack.cs_lflags & CSL_HAD_LOOP) 1209 { 1210 cstack.cs_lflags &= ~CSL_HAD_LOOP; 1211 cstack.cs_line[cstack.cs_idx] = current_line - 1; 1212 } 1213 } 1214 1215 /* 1216 * When not inside any ":while" loop, clear remembered lines. 1217 */ 1218 if (cstack.cs_looplevel == 0) 1219 { 1220 if (lines_ga.ga_len > 0) 1221 { 1222 sourcing_lnum = 1223 ((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum; 1224 free_cmdlines(&lines_ga); 1225 } 1226 current_line = 0; 1227 } 1228 1229 /* 1230 * A ":finally" makes did_emsg, got_int, and did_throw pending for 1231 * being restored at the ":endtry". Reset them here and set the 1232 * ACTIVE and FINALLY flags, so that the finally clause gets executed. 1233 * This includes the case where a missing ":endif", ":endwhile" or 1234 * ":endfor" was detected by the ":finally" itself. 1235 */ 1236 if (cstack.cs_lflags & CSL_HAD_FINA) 1237 { 1238 cstack.cs_lflags &= ~CSL_HAD_FINA; 1239 report_make_pending(cstack.cs_pending[cstack.cs_idx] 1240 & (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW), 1241 did_throw ? (void *)current_exception : NULL); 1242 did_emsg = got_int = did_throw = FALSE; 1243 cstack.cs_flags[cstack.cs_idx] |= CSF_ACTIVE | CSF_FINALLY; 1244 } 1245 1246 /* Update global "trylevel" for recursive calls to do_cmdline() from 1247 * within this loop. */ 1248 trylevel = initial_trylevel + cstack.cs_trylevel; 1249 1250 /* 1251 * If the outermost try conditional (across function calls and sourced 1252 * files) is aborted because of an error, an interrupt, or an uncaught 1253 * exception, cancel everything. If it is left normally, reset 1254 * force_abort to get the non-EH compatible abortion behavior for 1255 * the rest of the script. 1256 */ 1257 if (trylevel == 0 && !did_emsg && !got_int && !did_throw) 1258 force_abort = FALSE; 1259 1260 /* Convert an interrupt to an exception if appropriate. */ 1261 (void)do_intthrow(&cstack); 1262 #endif /* FEAT_EVAL */ 1263 1264 } 1265 /* 1266 * Continue executing command lines when: 1267 * - no CTRL-C typed, no aborting error, no exception thrown or try 1268 * conditionals need to be checked for executing finally clauses or 1269 * catching an interrupt exception 1270 * - didn't get an error message or lines are not typed 1271 * - there is a command after '|', inside a :if, :while, :for or :try, or 1272 * looping for ":source" command or function call. 1273 */ 1274 while (!((got_int 1275 #ifdef FEAT_EVAL 1276 || (did_emsg && force_abort) || did_throw 1277 #endif 1278 ) 1279 #ifdef FEAT_EVAL 1280 && cstack.cs_trylevel == 0 1281 #endif 1282 ) 1283 && !(did_emsg 1284 #ifdef FEAT_EVAL 1285 /* Keep going when inside try/catch, so that the error can be 1286 * deal with, except when it is a syntax error, it may cause 1287 * the :endtry to be missed. */ 1288 && (cstack.cs_trylevel == 0 || did_emsg_syntax) 1289 #endif 1290 && used_getline 1291 && (getline_equal(fgetline, cookie, getexmodeline) 1292 || getline_equal(fgetline, cookie, getexline))) 1293 && (next_cmdline != NULL 1294 #ifdef FEAT_EVAL 1295 || cstack.cs_idx >= 0 1296 #endif 1297 || (flags & DOCMD_REPEAT))); 1298 1299 vim_free(cmdline_copy); 1300 did_emsg_syntax = FALSE; 1301 #ifdef FEAT_EVAL 1302 free_cmdlines(&lines_ga); 1303 ga_clear(&lines_ga); 1304 1305 if (cstack.cs_idx >= 0) 1306 { 1307 /* 1308 * If a sourced file or executed function ran to its end, report the 1309 * unclosed conditional. 1310 */ 1311 if (!got_int && !did_throw 1312 && ((getline_equal(fgetline, cookie, getsourceline) 1313 && !source_finished(fgetline, cookie)) 1314 || (getline_equal(fgetline, cookie, get_func_line) 1315 && !func_has_ended(real_cookie)))) 1316 { 1317 if (cstack.cs_flags[cstack.cs_idx] & CSF_TRY) 1318 EMSG(_(e_endtry)); 1319 else if (cstack.cs_flags[cstack.cs_idx] & CSF_WHILE) 1320 EMSG(_(e_endwhile)); 1321 else if (cstack.cs_flags[cstack.cs_idx] & CSF_FOR) 1322 EMSG(_(e_endfor)); 1323 else 1324 EMSG(_(e_endif)); 1325 } 1326 1327 /* 1328 * Reset "trylevel" in case of a ":finish" or ":return" or a missing 1329 * ":endtry" in a sourced file or executed function. If the try 1330 * conditional is in its finally clause, ignore anything pending. 1331 * If it is in a catch clause, finish the caught exception. 1332 * Also cleanup any "cs_forinfo" structures. 1333 */ 1334 do 1335 { 1336 int idx = cleanup_conditionals(&cstack, 0, TRUE); 1337 1338 if (idx >= 0) 1339 --idx; /* remove try block not in its finally clause */ 1340 rewind_conditionals(&cstack, idx, CSF_WHILE | CSF_FOR, 1341 &cstack.cs_looplevel); 1342 } 1343 while (cstack.cs_idx >= 0); 1344 trylevel = initial_trylevel; 1345 } 1346 1347 /* If a missing ":endtry", ":endwhile", ":endfor", or ":endif" or a memory 1348 * lack was reported above and the error message is to be converted to an 1349 * exception, do this now after rewinding the cstack. */ 1350 do_errthrow(&cstack, getline_equal(fgetline, cookie, get_func_line) 1351 ? (char_u *)"endfunction" : (char_u *)NULL); 1352 1353 if (trylevel == 0) 1354 { 1355 /* 1356 * When an exception is being thrown out of the outermost try 1357 * conditional, discard the uncaught exception, disable the conversion 1358 * of interrupts or errors to exceptions, and ensure that no more 1359 * commands are executed. 1360 */ 1361 if (did_throw) 1362 { 1363 void *p = NULL; 1364 char_u *saved_sourcing_name; 1365 int saved_sourcing_lnum; 1366 struct msglist *messages = NULL, *next; 1367 1368 /* 1369 * If the uncaught exception is a user exception, report it as an 1370 * error. If it is an error exception, display the saved error 1371 * message now. For an interrupt exception, do nothing; the 1372 * interrupt message is given elsewhere. 1373 */ 1374 switch (current_exception->type) 1375 { 1376 case ET_USER: 1377 vim_snprintf((char *)IObuff, IOSIZE, 1378 _("E605: Exception not caught: %s"), 1379 current_exception->value); 1380 p = vim_strsave(IObuff); 1381 break; 1382 case ET_ERROR: 1383 messages = current_exception->messages; 1384 current_exception->messages = NULL; 1385 break; 1386 case ET_INTERRUPT: 1387 break; 1388 default: 1389 p = vim_strsave((char_u *)_(e_internal)); 1390 } 1391 1392 saved_sourcing_name = sourcing_name; 1393 saved_sourcing_lnum = sourcing_lnum; 1394 sourcing_name = current_exception->throw_name; 1395 sourcing_lnum = current_exception->throw_lnum; 1396 current_exception->throw_name = NULL; 1397 1398 discard_current_exception(); /* uses IObuff if 'verbose' */ 1399 suppress_errthrow = TRUE; 1400 force_abort = TRUE; 1401 1402 if (messages != NULL) 1403 { 1404 do 1405 { 1406 next = messages->next; 1407 emsg(messages->msg); 1408 vim_free(messages->msg); 1409 vim_free(messages); 1410 messages = next; 1411 } 1412 while (messages != NULL); 1413 } 1414 else if (p != NULL) 1415 { 1416 emsg(p); 1417 vim_free(p); 1418 } 1419 vim_free(sourcing_name); 1420 sourcing_name = saved_sourcing_name; 1421 sourcing_lnum = saved_sourcing_lnum; 1422 } 1423 1424 /* 1425 * On an interrupt or an aborting error not converted to an exception, 1426 * disable the conversion of errors to exceptions. (Interrupts are not 1427 * converted any more, here.) This enables also the interrupt message 1428 * when force_abort is set and did_emsg unset in case of an interrupt 1429 * from a finally clause after an error. 1430 */ 1431 else if (got_int || (did_emsg && force_abort)) 1432 suppress_errthrow = TRUE; 1433 } 1434 1435 /* 1436 * The current cstack will be freed when do_cmdline() returns. An uncaught 1437 * exception will have to be rethrown in the previous cstack. If a function 1438 * has just returned or a script file was just finished and the previous 1439 * cstack belongs to the same function or, respectively, script file, it 1440 * will have to be checked for finally clauses to be executed due to the 1441 * ":return" or ":finish". This is done in do_one_cmd(). 1442 */ 1443 if (did_throw) 1444 need_rethrow = TRUE; 1445 if ((getline_equal(fgetline, cookie, getsourceline) 1446 && ex_nesting_level > source_level(real_cookie)) 1447 || (getline_equal(fgetline, cookie, get_func_line) 1448 && ex_nesting_level > func_level(real_cookie) + 1)) 1449 { 1450 if (!did_throw) 1451 check_cstack = TRUE; 1452 } 1453 else 1454 { 1455 /* When leaving a function, reduce nesting level. */ 1456 if (getline_equal(fgetline, cookie, get_func_line)) 1457 --ex_nesting_level; 1458 /* 1459 * Go to debug mode when returning from a function in which we are 1460 * single-stepping. 1461 */ 1462 if ((getline_equal(fgetline, cookie, getsourceline) 1463 || getline_equal(fgetline, cookie, get_func_line)) 1464 && ex_nesting_level + 1 <= debug_break_level) 1465 do_debug(getline_equal(fgetline, cookie, getsourceline) 1466 ? (char_u *)_("End of sourced file") 1467 : (char_u *)_("End of function")); 1468 } 1469 1470 /* 1471 * Restore the exception environment (done after returning from the 1472 * debugger). 1473 */ 1474 if (flags & DOCMD_EXCRESET) 1475 restore_dbg_stuff(&debug_saved); 1476 1477 msg_list = saved_msg_list; 1478 #endif /* FEAT_EVAL */ 1479 1480 /* 1481 * If there was too much output to fit on the command line, ask the user to 1482 * hit return before redrawing the screen. With the ":global" command we do 1483 * this only once after the command is finished. 1484 */ 1485 if (did_inc) 1486 { 1487 --RedrawingDisabled; 1488 --no_wait_return; 1489 msg_scroll = FALSE; 1490 1491 /* 1492 * When just finished an ":if"-":else" which was typed, no need to 1493 * wait for hit-return. Also for an error situation. 1494 */ 1495 if (retval == FAIL 1496 #ifdef FEAT_EVAL 1497 || (did_endif && KeyTyped && !did_emsg) 1498 #endif 1499 ) 1500 { 1501 need_wait_return = FALSE; 1502 msg_didany = FALSE; /* don't wait when restarting edit */ 1503 } 1504 else if (need_wait_return) 1505 { 1506 /* 1507 * The msg_start() above clears msg_didout. The wait_return we do 1508 * here should not overwrite the command that may be shown before 1509 * doing that. 1510 */ 1511 msg_didout |= msg_didout_before_start; 1512 wait_return(FALSE); 1513 } 1514 } 1515 1516 #ifdef FEAT_EVAL 1517 did_endif = FALSE; /* in case do_cmdline used recursively */ 1518 #else 1519 /* 1520 * Reset if_level, in case a sourced script file contains more ":if" than 1521 * ":endif" (could be ":if x | foo | endif"). 1522 */ 1523 if_level = 0; 1524 #endif 1525 1526 --call_depth; 1527 return retval; 1528 } 1529 1530 #ifdef FEAT_EVAL 1531 /* 1532 * Obtain a line when inside a ":while" or ":for" loop. 1533 */ 1534 static char_u * 1535 get_loop_line(int c, void *cookie, int indent) 1536 { 1537 struct loop_cookie *cp = (struct loop_cookie *)cookie; 1538 wcmd_T *wp; 1539 char_u *line; 1540 1541 if (cp->current_line + 1 >= cp->lines_gap->ga_len) 1542 { 1543 if (cp->repeating) 1544 return NULL; /* trying to read past ":endwhile"/":endfor" */ 1545 1546 /* First time inside the ":while"/":for": get line normally. */ 1547 if (cp->getline == NULL) 1548 line = getcmdline(c, 0L, indent); 1549 else 1550 line = cp->getline(c, cp->cookie, indent); 1551 if (line != NULL && store_loop_line(cp->lines_gap, line) == OK) 1552 ++cp->current_line; 1553 1554 return line; 1555 } 1556 1557 KeyTyped = FALSE; 1558 ++cp->current_line; 1559 wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line; 1560 sourcing_lnum = wp->lnum; 1561 return vim_strsave(wp->line); 1562 } 1563 1564 /* 1565 * Store a line in "gap" so that a ":while" loop can execute it again. 1566 */ 1567 static int 1568 store_loop_line(garray_T *gap, char_u *line) 1569 { 1570 if (ga_grow(gap, 1) == FAIL) 1571 return FAIL; 1572 ((wcmd_T *)(gap->ga_data))[gap->ga_len].line = vim_strsave(line); 1573 ((wcmd_T *)(gap->ga_data))[gap->ga_len].lnum = sourcing_lnum; 1574 ++gap->ga_len; 1575 return OK; 1576 } 1577 1578 /* 1579 * Free the lines stored for a ":while" or ":for" loop. 1580 */ 1581 static void 1582 free_cmdlines(garray_T *gap) 1583 { 1584 while (gap->ga_len > 0) 1585 { 1586 vim_free(((wcmd_T *)(gap->ga_data))[gap->ga_len - 1].line); 1587 --gap->ga_len; 1588 } 1589 } 1590 #endif 1591 1592 /* 1593 * If "fgetline" is get_loop_line(), return TRUE if the getline it uses equals 1594 * "func". * Otherwise return TRUE when "fgetline" equals "func". 1595 */ 1596 int 1597 getline_equal( 1598 char_u *(*fgetline)(int, void *, int), 1599 void *cookie UNUSED, /* argument for fgetline() */ 1600 char_u *(*func)(int, void *, int)) 1601 { 1602 #ifdef FEAT_EVAL 1603 char_u *(*gp)(int, void *, int); 1604 struct loop_cookie *cp; 1605 1606 /* When "fgetline" is "get_loop_line()" use the "cookie" to find the 1607 * function that's originally used to obtain the lines. This may be 1608 * nested several levels. */ 1609 gp = fgetline; 1610 cp = (struct loop_cookie *)cookie; 1611 while (gp == get_loop_line) 1612 { 1613 gp = cp->getline; 1614 cp = cp->cookie; 1615 } 1616 return gp == func; 1617 #else 1618 return fgetline == func; 1619 #endif 1620 } 1621 1622 #if defined(FEAT_EVAL) || defined(FEAT_MBYTE) || defined(PROTO) 1623 /* 1624 * If "fgetline" is get_loop_line(), return the cookie used by the original 1625 * getline function. Otherwise return "cookie". 1626 */ 1627 void * 1628 getline_cookie( 1629 char_u *(*fgetline)(int, void *, int) UNUSED, 1630 void *cookie) /* argument for fgetline() */ 1631 { 1632 # ifdef FEAT_EVAL 1633 char_u *(*gp)(int, void *, int); 1634 struct loop_cookie *cp; 1635 1636 /* When "fgetline" is "get_loop_line()" use the "cookie" to find the 1637 * cookie that's originally used to obtain the lines. This may be nested 1638 * several levels. */ 1639 gp = fgetline; 1640 cp = (struct loop_cookie *)cookie; 1641 while (gp == get_loop_line) 1642 { 1643 gp = cp->getline; 1644 cp = cp->cookie; 1645 } 1646 return cp; 1647 # else 1648 return cookie; 1649 # endif 1650 } 1651 #endif 1652 1653 1654 /* 1655 * Helper function to apply an offset for buffer commands, i.e. ":bdelete", 1656 * ":bwipeout", etc. 1657 * Returns the buffer number. 1658 */ 1659 static int 1660 compute_buffer_local_count(int addr_type, int lnum, int offset) 1661 { 1662 buf_T *buf; 1663 buf_T *nextbuf; 1664 int count = offset; 1665 1666 buf = firstbuf; 1667 while (buf->b_next != NULL && buf->b_fnum < lnum) 1668 buf = buf->b_next; 1669 while (count != 0) 1670 { 1671 count += (offset < 0) ? 1 : -1; 1672 nextbuf = (offset < 0) ? buf->b_prev : buf->b_next; 1673 if (nextbuf == NULL) 1674 break; 1675 buf = nextbuf; 1676 if (addr_type == ADDR_LOADED_BUFFERS) 1677 /* skip over unloaded buffers */ 1678 while (buf->b_ml.ml_mfp == NULL) 1679 { 1680 nextbuf = (offset < 0) ? buf->b_prev : buf->b_next; 1681 if (nextbuf == NULL) 1682 break; 1683 buf = nextbuf; 1684 } 1685 } 1686 /* we might have gone too far, last buffer is not loadedd */ 1687 if (addr_type == ADDR_LOADED_BUFFERS) 1688 while (buf->b_ml.ml_mfp == NULL) 1689 { 1690 nextbuf = (offset >= 0) ? buf->b_prev : buf->b_next; 1691 if (nextbuf == NULL) 1692 break; 1693 buf = nextbuf; 1694 } 1695 return buf->b_fnum; 1696 } 1697 1698 #ifdef FEAT_WINDOWS 1699 static int current_win_nr(win_T *win); 1700 static int current_tab_nr(tabpage_T *tab); 1701 1702 static int 1703 current_win_nr(win_T *win) 1704 { 1705 win_T *wp; 1706 int nr = 0; 1707 1708 for (wp = firstwin; wp != NULL; wp = wp->w_next) 1709 { 1710 ++nr; 1711 if (wp == win) 1712 break; 1713 } 1714 return nr; 1715 } 1716 1717 static int 1718 current_tab_nr(tabpage_T *tab) 1719 { 1720 tabpage_T *tp; 1721 int nr = 0; 1722 1723 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) 1724 { 1725 ++nr; 1726 if (tp == tab) 1727 break; 1728 } 1729 return nr; 1730 } 1731 1732 # define CURRENT_WIN_NR current_win_nr(curwin) 1733 # define LAST_WIN_NR current_win_nr(NULL) 1734 # define CURRENT_TAB_NR current_tab_nr(curtab) 1735 # define LAST_TAB_NR current_tab_nr(NULL) 1736 #else 1737 # define CURRENT_WIN_NR 1 1738 # define LAST_WIN_NR 1 1739 # define CURRENT_TAB_NR 1 1740 # define LAST_TAB_NR 1 1741 #endif 1742 1743 1744 /* 1745 * Execute one Ex command. 1746 * 1747 * If 'sourcing' is TRUE, the command will be included in the error message. 1748 * 1749 * 1. skip comment lines and leading space 1750 * 2. handle command modifiers 1751 * 3. find the command 1752 * 4. parse range 1753 * 5. Parse the command. 1754 * 6. parse arguments 1755 * 7. switch on command name 1756 * 1757 * Note: "fgetline" can be NULL. 1758 * 1759 * This function may be called recursively! 1760 */ 1761 #if (_MSC_VER == 1200) 1762 /* 1763 * Avoid optimisation bug in VC++ version 6.0 1764 */ 1765 #pragma optimize( "g", off ) 1766 #endif 1767 static char_u * 1768 do_one_cmd( 1769 char_u **cmdlinep, 1770 int sourcing, 1771 #ifdef FEAT_EVAL 1772 struct condstack *cstack, 1773 #endif 1774 char_u *(*fgetline)(int, void *, int), 1775 void *cookie) /* argument for fgetline() */ 1776 { 1777 char_u *p; 1778 linenr_T lnum; 1779 long n; 1780 char_u *errormsg = NULL; /* error message */ 1781 exarg_T ea; /* Ex command arguments */ 1782 long verbose_save = -1; 1783 int save_msg_scroll = msg_scroll; 1784 int save_msg_silent = -1; 1785 int did_esilent = 0; 1786 #ifdef HAVE_SANDBOX 1787 int did_sandbox = FALSE; 1788 #endif 1789 cmdmod_T save_cmdmod; 1790 int ni; /* set when Not Implemented */ 1791 char_u *cmd; 1792 1793 vim_memset(&ea, 0, sizeof(ea)); 1794 ea.line1 = 1; 1795 ea.line2 = 1; 1796 #ifdef FEAT_EVAL 1797 ++ex_nesting_level; 1798 #endif 1799 1800 /* When the last file has not been edited :q has to be typed twice. */ 1801 if (quitmore 1802 #ifdef FEAT_EVAL 1803 /* avoid that a function call in 'statusline' does this */ 1804 && !getline_equal(fgetline, cookie, get_func_line) 1805 #endif 1806 #ifdef FEAT_AUTOCMD 1807 /* avoid that an autocommand, e.g. QuitPre, does this */ 1808 && !getline_equal(fgetline, cookie, getnextac) 1809 #endif 1810 ) 1811 --quitmore; 1812 1813 /* 1814 * Reset browse, confirm, etc.. They are restored when returning, for 1815 * recursive calls. 1816 */ 1817 save_cmdmod = cmdmod; 1818 vim_memset(&cmdmod, 0, sizeof(cmdmod)); 1819 1820 /* "#!anything" is handled like a comment. */ 1821 if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') 1822 goto doend; 1823 1824 /* 1825 * Repeat until no more command modifiers are found. 1826 */ 1827 ea.cmd = *cmdlinep; 1828 for (;;) 1829 { 1830 /* 1831 * 1. Skip comment lines and leading white space and colons. 1832 */ 1833 while (*ea.cmd == ' ' || *ea.cmd == '\t' || *ea.cmd == ':') 1834 ++ea.cmd; 1835 1836 /* in ex mode, an empty line works like :+ */ 1837 if (*ea.cmd == NUL && exmode_active 1838 && (getline_equal(fgetline, cookie, getexmodeline) 1839 || getline_equal(fgetline, cookie, getexline)) 1840 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) 1841 { 1842 ea.cmd = (char_u *)"+"; 1843 ex_pressedreturn = TRUE; 1844 } 1845 1846 /* ignore comment and empty lines */ 1847 if (*ea.cmd == '"') 1848 goto doend; 1849 if (*ea.cmd == NUL) 1850 { 1851 ex_pressedreturn = TRUE; 1852 goto doend; 1853 } 1854 1855 /* 1856 * 2. Handle command modifiers. 1857 */ 1858 p = ea.cmd; 1859 if (VIM_ISDIGIT(*ea.cmd)) 1860 p = skipwhite(skipdigits(ea.cmd)); 1861 switch (*p) 1862 { 1863 /* When adding an entry, also modify cmd_exists(). */ 1864 case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3)) 1865 break; 1866 #ifdef FEAT_WINDOWS 1867 cmdmod.split |= WSP_ABOVE; 1868 #endif 1869 continue; 1870 1871 case 'b': if (checkforcmd(&ea.cmd, "belowright", 3)) 1872 { 1873 #ifdef FEAT_WINDOWS 1874 cmdmod.split |= WSP_BELOW; 1875 #endif 1876 continue; 1877 } 1878 if (checkforcmd(&ea.cmd, "browse", 3)) 1879 { 1880 #ifdef FEAT_BROWSE_CMD 1881 cmdmod.browse = TRUE; 1882 #endif 1883 continue; 1884 } 1885 if (!checkforcmd(&ea.cmd, "botright", 2)) 1886 break; 1887 #ifdef FEAT_WINDOWS 1888 cmdmod.split |= WSP_BOT; 1889 #endif 1890 continue; 1891 1892 case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4)) 1893 break; 1894 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 1895 cmdmod.confirm = TRUE; 1896 #endif 1897 continue; 1898 1899 case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3)) 1900 { 1901 cmdmod.keepmarks = TRUE; 1902 continue; 1903 } 1904 if (checkforcmd(&ea.cmd, "keepalt", 5)) 1905 { 1906 cmdmod.keepalt = TRUE; 1907 continue; 1908 } 1909 if (checkforcmd(&ea.cmd, "keeppatterns", 5)) 1910 { 1911 cmdmod.keeppatterns = TRUE; 1912 continue; 1913 } 1914 if (!checkforcmd(&ea.cmd, "keepjumps", 5)) 1915 break; 1916 cmdmod.keepjumps = TRUE; 1917 continue; 1918 1919 /* ":hide" and ":hide | cmd" are not modifiers */ 1920 case 'h': if (p != ea.cmd || !checkforcmd(&p, "hide", 3) 1921 || *p == NUL || ends_excmd(*p)) 1922 break; 1923 ea.cmd = p; 1924 cmdmod.hide = TRUE; 1925 continue; 1926 1927 case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3)) 1928 { 1929 cmdmod.lockmarks = TRUE; 1930 continue; 1931 } 1932 1933 if (!checkforcmd(&ea.cmd, "leftabove", 5)) 1934 break; 1935 #ifdef FEAT_WINDOWS 1936 cmdmod.split |= WSP_ABOVE; 1937 #endif 1938 continue; 1939 1940 case 'n': if (checkforcmd(&ea.cmd, "noautocmd", 3)) 1941 { 1942 #ifdef FEAT_AUTOCMD 1943 if (cmdmod.save_ei == NULL) 1944 { 1945 /* Set 'eventignore' to "all". Restore the 1946 * existing option value later. */ 1947 cmdmod.save_ei = vim_strsave(p_ei); 1948 set_string_option_direct((char_u *)"ei", -1, 1949 (char_u *)"all", OPT_FREE, SID_NONE); 1950 } 1951 #endif 1952 continue; 1953 } 1954 if (!checkforcmd(&ea.cmd, "noswapfile", 6)) 1955 break; 1956 cmdmod.noswapfile = TRUE; 1957 continue; 1958 1959 case 'r': if (!checkforcmd(&ea.cmd, "rightbelow", 6)) 1960 break; 1961 #ifdef FEAT_WINDOWS 1962 cmdmod.split |= WSP_BELOW; 1963 #endif 1964 continue; 1965 1966 case 's': if (checkforcmd(&ea.cmd, "sandbox", 3)) 1967 { 1968 #ifdef HAVE_SANDBOX 1969 if (!did_sandbox) 1970 ++sandbox; 1971 did_sandbox = TRUE; 1972 #endif 1973 continue; 1974 } 1975 if (!checkforcmd(&ea.cmd, "silent", 3)) 1976 break; 1977 if (save_msg_silent == -1) 1978 save_msg_silent = msg_silent; 1979 ++msg_silent; 1980 if (*ea.cmd == '!' && !vim_iswhite(ea.cmd[-1])) 1981 { 1982 /* ":silent!", but not "silent !cmd" */ 1983 ea.cmd = skipwhite(ea.cmd + 1); 1984 ++emsg_silent; 1985 ++did_esilent; 1986 } 1987 continue; 1988 1989 case 't': if (checkforcmd(&p, "tab", 3)) 1990 { 1991 #ifdef FEAT_WINDOWS 1992 if (vim_isdigit(*ea.cmd)) 1993 cmdmod.tab = atoi((char *)ea.cmd) + 1; 1994 else 1995 cmdmod.tab = tabpage_index(curtab) + 1; 1996 ea.cmd = p; 1997 #endif 1998 continue; 1999 } 2000 if (!checkforcmd(&ea.cmd, "topleft", 2)) 2001 break; 2002 #ifdef FEAT_WINDOWS 2003 cmdmod.split |= WSP_TOP; 2004 #endif 2005 continue; 2006 2007 case 'u': if (!checkforcmd(&ea.cmd, "unsilent", 3)) 2008 break; 2009 if (save_msg_silent == -1) 2010 save_msg_silent = msg_silent; 2011 msg_silent = 0; 2012 continue; 2013 2014 case 'v': if (checkforcmd(&ea.cmd, "vertical", 4)) 2015 { 2016 #ifdef FEAT_WINDOWS 2017 cmdmod.split |= WSP_VERT; 2018 #endif 2019 continue; 2020 } 2021 if (!checkforcmd(&p, "verbose", 4)) 2022 break; 2023 if (verbose_save < 0) 2024 verbose_save = p_verbose; 2025 if (vim_isdigit(*ea.cmd)) 2026 p_verbose = atoi((char *)ea.cmd); 2027 else 2028 p_verbose = 1; 2029 ea.cmd = p; 2030 continue; 2031 } 2032 break; 2033 } 2034 2035 #ifdef FEAT_EVAL 2036 ea.skip = did_emsg || got_int || did_throw || (cstack->cs_idx >= 0 2037 && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE)); 2038 #else 2039 ea.skip = (if_level > 0); 2040 #endif 2041 2042 #ifdef FEAT_EVAL 2043 # ifdef FEAT_PROFILE 2044 /* Count this line for profiling if ea.skip is FALSE. */ 2045 if (do_profiling == PROF_YES && !ea.skip) 2046 { 2047 if (getline_equal(fgetline, cookie, get_func_line)) 2048 func_line_exec(getline_cookie(fgetline, cookie)); 2049 else if (getline_equal(fgetline, cookie, getsourceline)) 2050 script_line_exec(); 2051 } 2052 #endif 2053 2054 /* May go to debug mode. If this happens and the ">quit" debug command is 2055 * used, throw an interrupt exception and skip the next command. */ 2056 dbg_check_breakpoint(&ea); 2057 if (!ea.skip && got_int) 2058 { 2059 ea.skip = TRUE; 2060 (void)do_intthrow(cstack); 2061 } 2062 #endif 2063 2064 /* 2065 * 3. Skip over the range to find the command. Let "p" point to after it. 2066 * 2067 * We need the command to know what kind of range it uses. 2068 */ 2069 cmd = ea.cmd; 2070 ea.cmd = skip_range(ea.cmd, NULL); 2071 if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) 2072 ea.cmd = skipwhite(ea.cmd + 1); 2073 p = find_command(&ea, NULL); 2074 2075 /* 2076 * 4. parse a range specifier of the form: addr [,addr] [;addr] .. 2077 * 2078 * where 'addr' is: 2079 * 2080 * % (entire file) 2081 * $ [+-NUM] 2082 * 'x [+-NUM] (where x denotes a currently defined mark) 2083 * . [+-NUM] 2084 * [+-NUM].. 2085 * NUM 2086 * 2087 * The ea.cmd pointer is updated to point to the first character following the 2088 * range spec. If an initial address is found, but no second, the upper bound 2089 * is equal to the lower. 2090 */ 2091 2092 /* ea.addr_type for user commands is set by find_ucmd */ 2093 if (!IS_USER_CMDIDX(ea.cmdidx)) 2094 { 2095 if (ea.cmdidx != CMD_SIZE) 2096 ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type; 2097 else 2098 ea.addr_type = ADDR_LINES; 2099 2100 #ifdef FEAT_WINDOWS 2101 /* :wincmd range depends on the argument. */ 2102 if (ea.cmdidx == CMD_wincmd && p != NULL) 2103 get_wincmd_addr_type(skipwhite(p), &ea); 2104 #endif 2105 } 2106 2107 /* repeat for all ',' or ';' separated addresses */ 2108 ea.cmd = cmd; 2109 for (;;) 2110 { 2111 ea.line1 = ea.line2; 2112 switch (ea.addr_type) 2113 { 2114 case ADDR_LINES: 2115 /* default is current line number */ 2116 ea.line2 = curwin->w_cursor.lnum; 2117 break; 2118 case ADDR_WINDOWS: 2119 lnum = CURRENT_WIN_NR; 2120 ea.line2 = lnum; 2121 break; 2122 case ADDR_ARGUMENTS: 2123 ea.line2 = curwin->w_arg_idx + 1; 2124 if (ea.line2 > ARGCOUNT) 2125 ea.line2 = ARGCOUNT; 2126 break; 2127 case ADDR_LOADED_BUFFERS: 2128 case ADDR_BUFFERS: 2129 ea.line2 = curbuf->b_fnum; 2130 break; 2131 case ADDR_TABS: 2132 lnum = CURRENT_TAB_NR; 2133 ea.line2 = lnum; 2134 break; 2135 #ifdef FEAT_QUICKFIX 2136 case ADDR_QUICKFIX: 2137 ea.line2 = qf_get_cur_valid_idx(&ea); 2138 break; 2139 #endif 2140 } 2141 ea.cmd = skipwhite(ea.cmd); 2142 lnum = get_address(&ea, &ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0); 2143 if (ea.cmd == NULL) /* error detected */ 2144 goto doend; 2145 if (lnum == MAXLNUM) 2146 { 2147 if (*ea.cmd == '%') /* '%' - all lines */ 2148 { 2149 ++ea.cmd; 2150 switch (ea.addr_type) 2151 { 2152 case ADDR_LINES: 2153 ea.line1 = 1; 2154 ea.line2 = curbuf->b_ml.ml_line_count; 2155 break; 2156 case ADDR_LOADED_BUFFERS: 2157 { 2158 buf_T *buf = firstbuf; 2159 2160 while (buf->b_next != NULL 2161 && buf->b_ml.ml_mfp == NULL) 2162 buf = buf->b_next; 2163 ea.line1 = buf->b_fnum; 2164 buf = lastbuf; 2165 while (buf->b_prev != NULL 2166 && buf->b_ml.ml_mfp == NULL) 2167 buf = buf->b_prev; 2168 ea.line2 = buf->b_fnum; 2169 break; 2170 } 2171 case ADDR_BUFFERS: 2172 ea.line1 = firstbuf->b_fnum; 2173 ea.line2 = lastbuf->b_fnum; 2174 break; 2175 case ADDR_WINDOWS: 2176 case ADDR_TABS: 2177 if (IS_USER_CMDIDX(ea.cmdidx)) 2178 { 2179 ea.line1 = 1; 2180 ea.line2 = ea.addr_type == ADDR_WINDOWS 2181 ? LAST_WIN_NR : LAST_TAB_NR; 2182 } 2183 else 2184 { 2185 /* there is no Vim command which uses '%' and 2186 * ADDR_WINDOWS or ADDR_TABS */ 2187 errormsg = (char_u *)_(e_invrange); 2188 goto doend; 2189 } 2190 break; 2191 case ADDR_ARGUMENTS: 2192 if (ARGCOUNT == 0) 2193 ea.line1 = ea.line2 = 0; 2194 else 2195 { 2196 ea.line1 = 1; 2197 ea.line2 = ARGCOUNT; 2198 } 2199 break; 2200 #ifdef FEAT_QUICKFIX 2201 case ADDR_QUICKFIX: 2202 ea.line1 = 1; 2203 ea.line2 = qf_get_size(&ea); 2204 if (ea.line2 == 0) 2205 ea.line2 = 1; 2206 break; 2207 #endif 2208 } 2209 ++ea.addr_count; 2210 } 2211 /* '*' - visual area */ 2212 else if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) 2213 { 2214 pos_T *fp; 2215 2216 if (ea.addr_type != ADDR_LINES) 2217 { 2218 errormsg = (char_u *)_(e_invrange); 2219 goto doend; 2220 } 2221 2222 ++ea.cmd; 2223 if (!ea.skip) 2224 { 2225 fp = getmark('<', FALSE); 2226 if (check_mark(fp) == FAIL) 2227 goto doend; 2228 ea.line1 = fp->lnum; 2229 fp = getmark('>', FALSE); 2230 if (check_mark(fp) == FAIL) 2231 goto doend; 2232 ea.line2 = fp->lnum; 2233 ++ea.addr_count; 2234 } 2235 } 2236 } 2237 else 2238 ea.line2 = lnum; 2239 ea.addr_count++; 2240 2241 if (*ea.cmd == ';') 2242 { 2243 if (!ea.skip) 2244 curwin->w_cursor.lnum = ea.line2; 2245 } 2246 else if (*ea.cmd != ',') 2247 break; 2248 ++ea.cmd; 2249 } 2250 2251 /* One address given: set start and end lines */ 2252 if (ea.addr_count == 1) 2253 { 2254 ea.line1 = ea.line2; 2255 /* ... but only implicit: really no address given */ 2256 if (lnum == MAXLNUM) 2257 ea.addr_count = 0; 2258 } 2259 2260 /* Don't leave the cursor on an illegal line (caused by ';') */ 2261 check_cursor_lnum(); 2262 2263 /* 2264 * 5. Parse the command. 2265 */ 2266 2267 /* 2268 * Skip ':' and any white space 2269 */ 2270 ea.cmd = skipwhite(ea.cmd); 2271 while (*ea.cmd == ':') 2272 ea.cmd = skipwhite(ea.cmd + 1); 2273 2274 /* 2275 * If we got a line, but no command, then go to the line. 2276 * If we find a '|' or '\n' we set ea.nextcmd. 2277 */ 2278 if (*ea.cmd == NUL || *ea.cmd == '"' 2279 || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) 2280 { 2281 /* 2282 * strange vi behaviour: 2283 * ":3" jumps to line 3 2284 * ":3|..." prints line 3 2285 * ":|" prints current line 2286 */ 2287 if (ea.skip) /* skip this if inside :if */ 2288 goto doend; 2289 if (*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2)) 2290 { 2291 ea.cmdidx = CMD_print; 2292 ea.argt = RANGE+COUNT+TRLBAR; 2293 if ((errormsg = invalid_range(&ea)) == NULL) 2294 { 2295 correct_range(&ea); 2296 ex_print(&ea); 2297 } 2298 } 2299 else if (ea.addr_count != 0) 2300 { 2301 if (ea.line2 > curbuf->b_ml.ml_line_count) 2302 { 2303 /* With '-' in 'cpoptions' a line number past the file is an 2304 * error, otherwise put it at the end of the file. */ 2305 if (vim_strchr(p_cpo, CPO_MINUS) != NULL) 2306 ea.line2 = -1; 2307 else 2308 ea.line2 = curbuf->b_ml.ml_line_count; 2309 } 2310 2311 if (ea.line2 < 0) 2312 errormsg = (char_u *)_(e_invrange); 2313 else 2314 { 2315 if (ea.line2 == 0) 2316 curwin->w_cursor.lnum = 1; 2317 else 2318 curwin->w_cursor.lnum = ea.line2; 2319 beginline(BL_SOL | BL_FIX); 2320 } 2321 } 2322 goto doend; 2323 } 2324 2325 #ifdef FEAT_AUTOCMD 2326 /* If this looks like an undefined user command and there are CmdUndefined 2327 * autocommands defined, trigger the matching autocommands. */ 2328 if (p != NULL && ea.cmdidx == CMD_SIZE && !ea.skip 2329 && ASCII_ISUPPER(*ea.cmd) 2330 && has_cmdundefined()) 2331 { 2332 int ret; 2333 2334 p = ea.cmd; 2335 while (ASCII_ISALNUM(*p)) 2336 ++p; 2337 p = vim_strnsave(ea.cmd, (int)(p - ea.cmd)); 2338 ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, TRUE, NULL); 2339 vim_free(p); 2340 /* If the autocommands did something and didn't cause an error, try 2341 * finding the command again. */ 2342 p = (ret && !aborting()) ? find_command(&ea, NULL) : NULL; 2343 } 2344 #endif 2345 2346 #ifdef FEAT_USR_CMDS 2347 if (p == NULL) 2348 { 2349 if (!ea.skip) 2350 errormsg = (char_u *)_("E464: Ambiguous use of user-defined command"); 2351 goto doend; 2352 } 2353 /* Check for wrong commands. */ 2354 if (*p == '!' && ea.cmd[1] == 0151 && ea.cmd[0] == 78) 2355 { 2356 errormsg = uc_fun_cmd(); 2357 goto doend; 2358 } 2359 #endif 2360 if (ea.cmdidx == CMD_SIZE) 2361 { 2362 if (!ea.skip) 2363 { 2364 STRCPY(IObuff, _("E492: Not an editor command")); 2365 if (!sourcing) 2366 append_command(*cmdlinep); 2367 errormsg = IObuff; 2368 did_emsg_syntax = TRUE; 2369 } 2370 goto doend; 2371 } 2372 2373 ni = (!IS_USER_CMDIDX(ea.cmdidx) 2374 && (cmdnames[ea.cmdidx].cmd_func == ex_ni 2375 #ifdef HAVE_EX_SCRIPT_NI 2376 || cmdnames[ea.cmdidx].cmd_func == ex_script_ni 2377 #endif 2378 )); 2379 2380 #ifndef FEAT_EVAL 2381 /* 2382 * When the expression evaluation is disabled, recognize the ":if" and 2383 * ":endif" commands and ignore everything in between it. 2384 */ 2385 if (ea.cmdidx == CMD_if) 2386 ++if_level; 2387 if (if_level) 2388 { 2389 if (ea.cmdidx == CMD_endif) 2390 --if_level; 2391 goto doend; 2392 } 2393 2394 #endif 2395 2396 /* forced commands */ 2397 if (*p == '!' && ea.cmdidx != CMD_substitute 2398 && ea.cmdidx != CMD_smagic && ea.cmdidx != CMD_snomagic) 2399 { 2400 ++p; 2401 ea.forceit = TRUE; 2402 } 2403 else 2404 ea.forceit = FALSE; 2405 2406 /* 2407 * 6. Parse arguments. 2408 */ 2409 if (!IS_USER_CMDIDX(ea.cmdidx)) 2410 ea.argt = (long)cmdnames[(int)ea.cmdidx].cmd_argt; 2411 2412 if (!ea.skip) 2413 { 2414 #ifdef HAVE_SANDBOX 2415 if (sandbox != 0 && !(ea.argt & SBOXOK)) 2416 { 2417 /* Command not allowed in sandbox. */ 2418 errormsg = (char_u *)_(e_sandbox); 2419 goto doend; 2420 } 2421 #endif 2422 if (!curbuf->b_p_ma && (ea.argt & MODIFY)) 2423 { 2424 /* Command not allowed in non-'modifiable' buffer */ 2425 errormsg = (char_u *)_(e_modifiable); 2426 goto doend; 2427 } 2428 2429 if (text_locked() && !(ea.argt & CMDWIN) 2430 && !IS_USER_CMDIDX(ea.cmdidx)) 2431 { 2432 /* Command not allowed when editing the command line. */ 2433 #ifdef FEAT_CMDWIN 2434 if (cmdwin_type != 0) 2435 errormsg = (char_u *)_(e_cmdwin); 2436 else 2437 #endif 2438 errormsg = (char_u *)_(e_secure); 2439 goto doend; 2440 } 2441 #ifdef FEAT_AUTOCMD 2442 /* Disallow editing another buffer when "curbuf_lock" is set. 2443 * Do allow ":edit" (check for argument later). 2444 * Do allow ":checktime" (it's postponed). */ 2445 if (!(ea.argt & CMDWIN) 2446 && ea.cmdidx != CMD_edit 2447 && ea.cmdidx != CMD_checktime 2448 && !IS_USER_CMDIDX(ea.cmdidx) 2449 && curbuf_locked()) 2450 goto doend; 2451 #endif 2452 2453 if (!ni && !(ea.argt & RANGE) && ea.addr_count > 0) 2454 { 2455 /* no range allowed */ 2456 errormsg = (char_u *)_(e_norange); 2457 goto doend; 2458 } 2459 } 2460 2461 if (!ni && !(ea.argt & BANG) && ea.forceit) /* no <!> allowed */ 2462 { 2463 errormsg = (char_u *)_(e_nobang); 2464 goto doend; 2465 } 2466 2467 /* 2468 * Don't complain about the range if it is not used 2469 * (could happen if line_count is accidentally set to 0). 2470 */ 2471 if (!ea.skip && !ni) 2472 { 2473 /* 2474 * If the range is backwards, ask for confirmation and, if given, swap 2475 * ea.line1 & ea.line2 so it's forwards again. 2476 * When global command is busy, don't ask, will fail below. 2477 */ 2478 if (!global_busy && ea.line1 > ea.line2) 2479 { 2480 if (msg_silent == 0) 2481 { 2482 if (sourcing || exmode_active) 2483 { 2484 errormsg = (char_u *)_("E493: Backwards range given"); 2485 goto doend; 2486 } 2487 if (ask_yesno((char_u *) 2488 _("Backwards range given, OK to swap"), FALSE) != 'y') 2489 goto doend; 2490 } 2491 lnum = ea.line1; 2492 ea.line1 = ea.line2; 2493 ea.line2 = lnum; 2494 } 2495 if ((errormsg = invalid_range(&ea)) != NULL) 2496 goto doend; 2497 } 2498 2499 if ((ea.argt & NOTADR) && ea.addr_count == 0) /* default is 1, not cursor */ 2500 ea.line2 = 1; 2501 2502 correct_range(&ea); 2503 2504 #ifdef FEAT_FOLDING 2505 if (((ea.argt & WHOLEFOLD) || ea.addr_count >= 2) && !global_busy 2506 && ea.addr_type == ADDR_LINES) 2507 { 2508 /* Put the first line at the start of a closed fold, put the last line 2509 * at the end of a closed fold. */ 2510 (void)hasFolding(ea.line1, &ea.line1, NULL); 2511 (void)hasFolding(ea.line2, NULL, &ea.line2); 2512 } 2513 #endif 2514 2515 #ifdef FEAT_QUICKFIX 2516 /* 2517 * For the ":make" and ":grep" commands we insert the 'makeprg'/'grepprg' 2518 * option here, so things like % get expanded. 2519 */ 2520 p = replace_makeprg(&ea, p, cmdlinep); 2521 if (p == NULL) 2522 goto doend; 2523 #endif 2524 2525 /* 2526 * Skip to start of argument. 2527 * Don't do this for the ":!" command, because ":!! -l" needs the space. 2528 */ 2529 if (ea.cmdidx == CMD_bang) 2530 ea.arg = p; 2531 else 2532 ea.arg = skipwhite(p); 2533 2534 /* 2535 * Check for "++opt=val" argument. 2536 * Must be first, allow ":w ++enc=utf8 !cmd" 2537 */ 2538 if (ea.argt & ARGOPT) 2539 while (ea.arg[0] == '+' && ea.arg[1] == '+') 2540 if (getargopt(&ea) == FAIL && !ni) 2541 { 2542 errormsg = (char_u *)_(e_invarg); 2543 goto doend; 2544 } 2545 2546 if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) 2547 { 2548 if (*ea.arg == '>') /* append */ 2549 { 2550 if (*++ea.arg != '>') /* typed wrong */ 2551 { 2552 errormsg = (char_u *)_("E494: Use w or w>>"); 2553 goto doend; 2554 } 2555 ea.arg = skipwhite(ea.arg + 1); 2556 ea.append = TRUE; 2557 } 2558 else if (*ea.arg == '!' && ea.cmdidx == CMD_write) /* :w !filter */ 2559 { 2560 ++ea.arg; 2561 ea.usefilter = TRUE; 2562 } 2563 } 2564 2565 if (ea.cmdidx == CMD_read) 2566 { 2567 if (ea.forceit) 2568 { 2569 ea.usefilter = TRUE; /* :r! filter if ea.forceit */ 2570 ea.forceit = FALSE; 2571 } 2572 else if (*ea.arg == '!') /* :r !filter */ 2573 { 2574 ++ea.arg; 2575 ea.usefilter = TRUE; 2576 } 2577 } 2578 2579 if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) 2580 { 2581 ea.amount = 1; 2582 while (*ea.arg == *ea.cmd) /* count number of '>' or '<' */ 2583 { 2584 ++ea.arg; 2585 ++ea.amount; 2586 } 2587 ea.arg = skipwhite(ea.arg); 2588 } 2589 2590 /* 2591 * Check for "+command" argument, before checking for next command. 2592 * Don't do this for ":read !cmd" and ":write !cmd". 2593 */ 2594 if ((ea.argt & EDITCMD) && !ea.usefilter) 2595 ea.do_ecmd_cmd = getargcmd(&ea.arg); 2596 2597 /* 2598 * Check for '|' to separate commands and '"' to start comments. 2599 * Don't do this for ":read !cmd" and ":write !cmd". 2600 */ 2601 if ((ea.argt & TRLBAR) && !ea.usefilter) 2602 separate_nextcmd(&ea); 2603 2604 /* 2605 * Check for <newline> to end a shell command. 2606 * Also do this for ":read !cmd", ":write !cmd" and ":global". 2607 * Any others? 2608 */ 2609 else if (ea.cmdidx == CMD_bang 2610 || ea.cmdidx == CMD_global 2611 || ea.cmdidx == CMD_vglobal 2612 || ea.usefilter) 2613 { 2614 for (p = ea.arg; *p; ++p) 2615 { 2616 /* Remove one backslash before a newline, so that it's possible to 2617 * pass a newline to the shell and also a newline that is preceded 2618 * with a backslash. This makes it impossible to end a shell 2619 * command in a backslash, but that doesn't appear useful. 2620 * Halving the number of backslashes is incompatible with previous 2621 * versions. */ 2622 if (*p == '\\' && p[1] == '\n') 2623 STRMOVE(p, p + 1); 2624 else if (*p == '\n') 2625 { 2626 ea.nextcmd = p + 1; 2627 *p = NUL; 2628 break; 2629 } 2630 } 2631 } 2632 2633 if ((ea.argt & DFLALL) && ea.addr_count == 0) 2634 { 2635 buf_T *buf; 2636 2637 ea.line1 = 1; 2638 switch (ea.addr_type) 2639 { 2640 case ADDR_LINES: 2641 ea.line2 = curbuf->b_ml.ml_line_count; 2642 break; 2643 case ADDR_LOADED_BUFFERS: 2644 buf = firstbuf; 2645 while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) 2646 buf = buf->b_next; 2647 ea.line1 = buf->b_fnum; 2648 buf = lastbuf; 2649 while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) 2650 buf = buf->b_prev; 2651 ea.line2 = buf->b_fnum; 2652 break; 2653 case ADDR_BUFFERS: 2654 ea.line1 = firstbuf->b_fnum; 2655 ea.line2 = lastbuf->b_fnum; 2656 break; 2657 case ADDR_WINDOWS: 2658 ea.line2 = LAST_WIN_NR; 2659 break; 2660 case ADDR_TABS: 2661 ea.line2 = LAST_TAB_NR; 2662 break; 2663 case ADDR_ARGUMENTS: 2664 if (ARGCOUNT == 0) 2665 ea.line1 = ea.line2 = 0; 2666 else 2667 ea.line2 = ARGCOUNT; 2668 break; 2669 #ifdef FEAT_QUICKFIX 2670 case ADDR_QUICKFIX: 2671 ea.line2 = qf_get_size(&ea); 2672 if (ea.line2 == 0) 2673 ea.line2 = 1; 2674 break; 2675 #endif 2676 } 2677 } 2678 2679 /* accept numbered register only when no count allowed (:put) */ 2680 if ( (ea.argt & REGSTR) 2681 && *ea.arg != NUL 2682 /* Do not allow register = for user commands */ 2683 && (!IS_USER_CMDIDX(ea.cmdidx) || *ea.arg != '=') 2684 && !((ea.argt & COUNT) && VIM_ISDIGIT(*ea.arg))) 2685 { 2686 #ifndef FEAT_CLIPBOARD 2687 /* check these explicitly for a more specific error message */ 2688 if (*ea.arg == '*' || *ea.arg == '+') 2689 { 2690 errormsg = (char_u *)_(e_invalidreg); 2691 goto doend; 2692 } 2693 #endif 2694 if (valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put 2695 && !IS_USER_CMDIDX(ea.cmdidx)))) 2696 { 2697 ea.regname = *ea.arg++; 2698 #ifdef FEAT_EVAL 2699 /* for '=' register: accept the rest of the line as an expression */ 2700 if (ea.arg[-1] == '=' && ea.arg[0] != NUL) 2701 { 2702 set_expr_line(vim_strsave(ea.arg)); 2703 ea.arg += STRLEN(ea.arg); 2704 } 2705 #endif 2706 ea.arg = skipwhite(ea.arg); 2707 } 2708 } 2709 2710 /* 2711 * Check for a count. When accepting a BUFNAME, don't use "123foo" as a 2712 * count, it's a buffer name. 2713 */ 2714 if ((ea.argt & COUNT) && VIM_ISDIGIT(*ea.arg) 2715 && (!(ea.argt & BUFNAME) || *(p = skipdigits(ea.arg)) == NUL 2716 || vim_iswhite(*p))) 2717 { 2718 n = getdigits(&ea.arg); 2719 ea.arg = skipwhite(ea.arg); 2720 if (n <= 0 && !ni && (ea.argt & ZEROR) == 0) 2721 { 2722 errormsg = (char_u *)_(e_zerocount); 2723 goto doend; 2724 } 2725 if (ea.argt & NOTADR) /* e.g. :buffer 2, :sleep 3 */ 2726 { 2727 ea.line2 = n; 2728 if (ea.addr_count == 0) 2729 ea.addr_count = 1; 2730 } 2731 else 2732 { 2733 ea.line1 = ea.line2; 2734 ea.line2 += n - 1; 2735 ++ea.addr_count; 2736 /* 2737 * Be vi compatible: no error message for out of range. 2738 */ 2739 if (ea.line2 > curbuf->b_ml.ml_line_count) 2740 ea.line2 = curbuf->b_ml.ml_line_count; 2741 } 2742 } 2743 2744 /* 2745 * Check for flags: 'l', 'p' and '#'. 2746 */ 2747 if (ea.argt & EXFLAGS) 2748 get_flags(&ea); 2749 /* no arguments allowed */ 2750 if (!ni && !(ea.argt & EXTRA) && *ea.arg != NUL 2751 && *ea.arg != '"' && (*ea.arg != '|' || (ea.argt & TRLBAR) == 0)) 2752 { 2753 errormsg = (char_u *)_(e_trailing); 2754 goto doend; 2755 } 2756 2757 if (!ni && (ea.argt & NEEDARG) && *ea.arg == NUL) 2758 { 2759 errormsg = (char_u *)_(e_argreq); 2760 goto doend; 2761 } 2762 2763 #ifdef FEAT_EVAL 2764 /* 2765 * Skip the command when it's not going to be executed. 2766 * The commands like :if, :endif, etc. always need to be executed. 2767 * Also make an exception for commands that handle a trailing command 2768 * themselves. 2769 */ 2770 if (ea.skip) 2771 { 2772 switch (ea.cmdidx) 2773 { 2774 /* commands that need evaluation */ 2775 case CMD_while: 2776 case CMD_endwhile: 2777 case CMD_for: 2778 case CMD_endfor: 2779 case CMD_if: 2780 case CMD_elseif: 2781 case CMD_else: 2782 case CMD_endif: 2783 case CMD_try: 2784 case CMD_catch: 2785 case CMD_finally: 2786 case CMD_endtry: 2787 case CMD_function: 2788 break; 2789 2790 /* Commands that handle '|' themselves. Check: A command should 2791 * either have the TRLBAR flag, appear in this list or appear in 2792 * the list at ":help :bar". */ 2793 case CMD_aboveleft: 2794 case CMD_and: 2795 case CMD_belowright: 2796 case CMD_botright: 2797 case CMD_browse: 2798 case CMD_call: 2799 case CMD_confirm: 2800 case CMD_delfunction: 2801 case CMD_djump: 2802 case CMD_dlist: 2803 case CMD_dsearch: 2804 case CMD_dsplit: 2805 case CMD_echo: 2806 case CMD_echoerr: 2807 case CMD_echomsg: 2808 case CMD_echon: 2809 case CMD_execute: 2810 case CMD_help: 2811 case CMD_hide: 2812 case CMD_ijump: 2813 case CMD_ilist: 2814 case CMD_isearch: 2815 case CMD_isplit: 2816 case CMD_keepalt: 2817 case CMD_keepjumps: 2818 case CMD_keepmarks: 2819 case CMD_keeppatterns: 2820 case CMD_leftabove: 2821 case CMD_let: 2822 case CMD_lockmarks: 2823 case CMD_lua: 2824 case CMD_match: 2825 case CMD_mzscheme: 2826 case CMD_noautocmd: 2827 case CMD_noswapfile: 2828 case CMD_perl: 2829 case CMD_psearch: 2830 case CMD_python: 2831 case CMD_py3: 2832 case CMD_python3: 2833 case CMD_return: 2834 case CMD_rightbelow: 2835 case CMD_ruby: 2836 case CMD_silent: 2837 case CMD_smagic: 2838 case CMD_snomagic: 2839 case CMD_substitute: 2840 case CMD_syntax: 2841 case CMD_tab: 2842 case CMD_tcl: 2843 case CMD_throw: 2844 case CMD_tilde: 2845 case CMD_topleft: 2846 case CMD_unlet: 2847 case CMD_verbose: 2848 case CMD_vertical: 2849 case CMD_wincmd: 2850 break; 2851 2852 default: goto doend; 2853 } 2854 } 2855 #endif 2856 2857 if (ea.argt & XFILE) 2858 { 2859 if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL) 2860 goto doend; 2861 } 2862 2863 #ifdef FEAT_LISTCMDS 2864 /* 2865 * Accept buffer name. Cannot be used at the same time with a buffer 2866 * number. Don't do this for a user command. 2867 */ 2868 if ((ea.argt & BUFNAME) && *ea.arg != NUL && ea.addr_count == 0 2869 && !IS_USER_CMDIDX(ea.cmdidx)) 2870 { 2871 /* 2872 * :bdelete, :bwipeout and :bunload take several arguments, separated 2873 * by spaces: find next space (skipping over escaped characters). 2874 * The others take one argument: ignore trailing spaces. 2875 */ 2876 if (ea.cmdidx == CMD_bdelete || ea.cmdidx == CMD_bwipeout 2877 || ea.cmdidx == CMD_bunload) 2878 p = skiptowhite_esc(ea.arg); 2879 else 2880 { 2881 p = ea.arg + STRLEN(ea.arg); 2882 while (p > ea.arg && vim_iswhite(p[-1])) 2883 --p; 2884 } 2885 ea.line2 = buflist_findpat(ea.arg, p, (ea.argt & BUFUNL) != 0, 2886 FALSE, FALSE); 2887 if (ea.line2 < 0) /* failed */ 2888 goto doend; 2889 ea.addr_count = 1; 2890 ea.arg = skipwhite(p); 2891 } 2892 #endif 2893 2894 /* 2895 * 7. Switch on command name. 2896 * 2897 * The "ea" structure holds the arguments that can be used. 2898 */ 2899 ea.cmdlinep = cmdlinep; 2900 ea.getline = fgetline; 2901 ea.cookie = cookie; 2902 #ifdef FEAT_EVAL 2903 ea.cstack = cstack; 2904 #endif 2905 2906 #ifdef FEAT_USR_CMDS 2907 if (IS_USER_CMDIDX(ea.cmdidx)) 2908 { 2909 /* 2910 * Execute a user-defined command. 2911 */ 2912 do_ucmd(&ea); 2913 } 2914 else 2915 #endif 2916 { 2917 /* 2918 * Call the function to execute the command. 2919 */ 2920 ea.errmsg = NULL; 2921 (cmdnames[ea.cmdidx].cmd_func)(&ea); 2922 if (ea.errmsg != NULL) 2923 errormsg = (char_u *)_(ea.errmsg); 2924 } 2925 2926 #ifdef FEAT_EVAL 2927 /* 2928 * If the command just executed called do_cmdline(), any throw or ":return" 2929 * or ":finish" encountered there must also check the cstack of the still 2930 * active do_cmdline() that called this do_one_cmd(). Rethrow an uncaught 2931 * exception, or reanimate a returned function or finished script file and 2932 * return or finish it again. 2933 */ 2934 if (need_rethrow) 2935 do_throw(cstack); 2936 else if (check_cstack) 2937 { 2938 if (source_finished(fgetline, cookie)) 2939 do_finish(&ea, TRUE); 2940 else if (getline_equal(fgetline, cookie, get_func_line) 2941 && current_func_returned()) 2942 do_return(&ea, TRUE, FALSE, NULL); 2943 } 2944 need_rethrow = check_cstack = FALSE; 2945 #endif 2946 2947 doend: 2948 if (curwin->w_cursor.lnum == 0) /* can happen with zero line number */ 2949 curwin->w_cursor.lnum = 1; 2950 2951 if (errormsg != NULL && *errormsg != NUL && !did_emsg) 2952 { 2953 if (sourcing) 2954 { 2955 if (errormsg != IObuff) 2956 { 2957 STRCPY(IObuff, errormsg); 2958 errormsg = IObuff; 2959 } 2960 append_command(*cmdlinep); 2961 } 2962 emsg(errormsg); 2963 } 2964 #ifdef FEAT_EVAL 2965 do_errthrow(cstack, 2966 (ea.cmdidx != CMD_SIZE && !IS_USER_CMDIDX(ea.cmdidx)) 2967 ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); 2968 #endif 2969 2970 if (verbose_save >= 0) 2971 p_verbose = verbose_save; 2972 #ifdef FEAT_AUTOCMD 2973 if (cmdmod.save_ei != NULL) 2974 { 2975 /* Restore 'eventignore' to the value before ":noautocmd". */ 2976 set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei, 2977 OPT_FREE, SID_NONE); 2978 free_string_option(cmdmod.save_ei); 2979 } 2980 #endif 2981 2982 cmdmod = save_cmdmod; 2983 2984 if (save_msg_silent != -1) 2985 { 2986 /* messages could be enabled for a serious error, need to check if the 2987 * counters don't become negative */ 2988 if (!did_emsg || msg_silent > save_msg_silent) 2989 msg_silent = save_msg_silent; 2990 emsg_silent -= did_esilent; 2991 if (emsg_silent < 0) 2992 emsg_silent = 0; 2993 /* Restore msg_scroll, it's set by file I/O commands, even when no 2994 * message is actually displayed. */ 2995 msg_scroll = save_msg_scroll; 2996 2997 /* "silent reg" or "silent echo x" inside "redir" leaves msg_col 2998 * somewhere in the line. Put it back in the first column. */ 2999 if (redirecting()) 3000 msg_col = 0; 3001 } 3002 3003 #ifdef HAVE_SANDBOX 3004 if (did_sandbox) 3005 --sandbox; 3006 #endif 3007 3008 if (ea.nextcmd && *ea.nextcmd == NUL) /* not really a next command */ 3009 ea.nextcmd = NULL; 3010 3011 #ifdef FEAT_EVAL 3012 --ex_nesting_level; 3013 #endif 3014 3015 return ea.nextcmd; 3016 } 3017 #if (_MSC_VER == 1200) 3018 #pragma optimize( "", on ) 3019 #endif 3020 3021 /* 3022 * Check for an Ex command with optional tail. 3023 * If there is a match advance "pp" to the argument and return TRUE. 3024 */ 3025 int 3026 checkforcmd( 3027 char_u **pp, /* start of command */ 3028 char *cmd, /* name of command */ 3029 int len) /* required length */ 3030 { 3031 int i; 3032 3033 for (i = 0; cmd[i] != NUL; ++i) 3034 if (((char_u *)cmd)[i] != (*pp)[i]) 3035 break; 3036 if (i >= len && !isalpha((*pp)[i])) 3037 { 3038 *pp = skipwhite(*pp + i); 3039 return TRUE; 3040 } 3041 return FALSE; 3042 } 3043 3044 /* 3045 * Append "cmd" to the error message in IObuff. 3046 * Takes care of limiting the length and handling 0xa0, which would be 3047 * invisible otherwise. 3048 */ 3049 static void 3050 append_command(char_u *cmd) 3051 { 3052 char_u *s = cmd; 3053 char_u *d; 3054 3055 STRCAT(IObuff, ": "); 3056 d = IObuff + STRLEN(IObuff); 3057 while (*s != NUL && d - IObuff < IOSIZE - 7) 3058 { 3059 if ( 3060 #ifdef FEAT_MBYTE 3061 enc_utf8 ? (s[0] == 0xc2 && s[1] == 0xa0) : 3062 #endif 3063 *s == 0xa0) 3064 { 3065 s += 3066 #ifdef FEAT_MBYTE 3067 enc_utf8 ? 2 : 3068 #endif 3069 1; 3070 STRCPY(d, "<a0>"); 3071 d += 4; 3072 } 3073 else 3074 MB_COPY_CHAR(s, d); 3075 } 3076 *d = NUL; 3077 } 3078 3079 /* 3080 * Find an Ex command by its name, either built-in or user. 3081 * Start of the name can be found at eap->cmd. 3082 * Returns pointer to char after the command name. 3083 * "full" is set to TRUE if the whole command name matched. 3084 * Returns NULL for an ambiguous user command. 3085 */ 3086 static char_u * 3087 find_command(exarg_T *eap, int *full UNUSED) 3088 { 3089 int len; 3090 char_u *p; 3091 int i; 3092 3093 /* 3094 * Isolate the command and search for it in the command table. 3095 * Exceptions: 3096 * - the 'k' command can directly be followed by any character. 3097 * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' 3098 * but :sre[wind] is another command, as are :scr[iptnames], 3099 * :scs[cope], :sim[alt], :sig[ns] and :sil[ent]. 3100 * - the "d" command can directly be followed by 'l' or 'p' flag. 3101 */ 3102 p = eap->cmd; 3103 if (*p == 'k') 3104 { 3105 eap->cmdidx = CMD_k; 3106 ++p; 3107 } 3108 else if (p[0] == 's' 3109 && ((p[1] == 'c' && (p[2] == NUL || (p[2] != 's' && p[2] != 'r' 3110 && (p[3] == NUL || (p[3] != 'i' && p[4] != 'p'))))) 3111 || p[1] == 'g' 3112 || (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g') 3113 || p[1] == 'I' 3114 || (p[1] == 'r' && p[2] != 'e'))) 3115 { 3116 eap->cmdidx = CMD_substitute; 3117 ++p; 3118 } 3119 else 3120 { 3121 while (ASCII_ISALPHA(*p)) 3122 ++p; 3123 /* for python 3.x support ":py3", ":python3", ":py3file", etc. */ 3124 if (eap->cmd[0] == 'p' && eap->cmd[1] == 'y') 3125 while (ASCII_ISALNUM(*p)) 3126 ++p; 3127 3128 /* check for non-alpha command */ 3129 if (p == eap->cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL) 3130 ++p; 3131 len = (int)(p - eap->cmd); 3132 if (*eap->cmd == 'd' && (p[-1] == 'l' || p[-1] == 'p')) 3133 { 3134 /* Check for ":dl", ":dell", etc. to ":deletel": that's 3135 * :delete with the 'l' flag. Same for 'p'. */ 3136 for (i = 0; i < len; ++i) 3137 if (eap->cmd[i] != ((char_u *)"delete")[i]) 3138 break; 3139 if (i == len - 1) 3140 { 3141 --len; 3142 if (p[-1] == 'l') 3143 eap->flags |= EXFLAG_LIST; 3144 else 3145 eap->flags |= EXFLAG_PRINT; 3146 } 3147 } 3148 3149 if (ASCII_ISLOWER(*eap->cmd)) 3150 eap->cmdidx = cmdidxs[CharOrdLow(*eap->cmd)]; 3151 else 3152 eap->cmdidx = cmdidxs[26]; 3153 3154 for ( ; (int)eap->cmdidx < (int)CMD_SIZE; 3155 eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1)) 3156 if (STRNCMP(cmdnames[(int)eap->cmdidx].cmd_name, (char *)eap->cmd, 3157 (size_t)len) == 0) 3158 { 3159 #ifdef FEAT_EVAL 3160 if (full != NULL 3161 && cmdnames[(int)eap->cmdidx].cmd_name[len] == NUL) 3162 *full = TRUE; 3163 #endif 3164 break; 3165 } 3166 3167 #ifdef FEAT_USR_CMDS 3168 /* Look for a user defined command as a last resort. Let ":Print" be 3169 * overruled by a user defined command. */ 3170 if ((eap->cmdidx == CMD_SIZE || eap->cmdidx == CMD_Print) 3171 && *eap->cmd >= 'A' && *eap->cmd <= 'Z') 3172 { 3173 /* User defined commands may contain digits. */ 3174 while (ASCII_ISALNUM(*p)) 3175 ++p; 3176 p = find_ucmd(eap, p, full, NULL, NULL); 3177 } 3178 #endif 3179 if (p == eap->cmd) 3180 eap->cmdidx = CMD_SIZE; 3181 } 3182 3183 return p; 3184 } 3185 3186 #ifdef FEAT_USR_CMDS 3187 /* 3188 * Search for a user command that matches "eap->cmd". 3189 * Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx". 3190 * Return a pointer to just after the command. 3191 * Return NULL if there is no matching command. 3192 */ 3193 static char_u * 3194 find_ucmd( 3195 exarg_T *eap, 3196 char_u *p, /* end of the command (possibly including count) */ 3197 int *full, /* set to TRUE for a full match */ 3198 expand_T *xp, /* used for completion, NULL otherwise */ 3199 int *compl) /* completion flags or NULL */ 3200 { 3201 int len = (int)(p - eap->cmd); 3202 int j, k, matchlen = 0; 3203 ucmd_T *uc; 3204 int found = FALSE; 3205 int possible = FALSE; 3206 char_u *cp, *np; /* Point into typed cmd and test name */ 3207 garray_T *gap; 3208 int amb_local = FALSE; /* Found ambiguous buffer-local command, 3209 only full match global is accepted. */ 3210 3211 /* 3212 * Look for buffer-local user commands first, then global ones. 3213 */ 3214 gap = &curbuf->b_ucmds; 3215 for (;;) 3216 { 3217 for (j = 0; j < gap->ga_len; ++j) 3218 { 3219 uc = USER_CMD_GA(gap, j); 3220 cp = eap->cmd; 3221 np = uc->uc_name; 3222 k = 0; 3223 while (k < len && *np != NUL && *cp++ == *np++) 3224 k++; 3225 if (k == len || (*np == NUL && vim_isdigit(eap->cmd[k]))) 3226 { 3227 /* If finding a second match, the command is ambiguous. But 3228 * not if a buffer-local command wasn't a full match and a 3229 * global command is a full match. */ 3230 if (k == len && found && *np != NUL) 3231 { 3232 if (gap == &ucmds) 3233 return NULL; 3234 amb_local = TRUE; 3235 } 3236 3237 if (!found || (k == len && *np == NUL)) 3238 { 3239 /* If we matched up to a digit, then there could 3240 * be another command including the digit that we 3241 * should use instead. 3242 */ 3243 if (k == len) 3244 found = TRUE; 3245 else 3246 possible = TRUE; 3247 3248 if (gap == &ucmds) 3249 eap->cmdidx = CMD_USER; 3250 else 3251 eap->cmdidx = CMD_USER_BUF; 3252 eap->argt = (long)uc->uc_argt; 3253 eap->useridx = j; 3254 eap->addr_type = uc->uc_addr_type; 3255 3256 # ifdef FEAT_CMDL_COMPL 3257 if (compl != NULL) 3258 *compl = uc->uc_compl; 3259 # ifdef FEAT_EVAL 3260 if (xp != NULL) 3261 { 3262 xp->xp_arg = uc->uc_compl_arg; 3263 xp->xp_scriptID = uc->uc_scriptID; 3264 } 3265 # endif 3266 # endif 3267 /* Do not search for further abbreviations 3268 * if this is an exact match. */ 3269 matchlen = k; 3270 if (k == len && *np == NUL) 3271 { 3272 if (full != NULL) 3273 *full = TRUE; 3274 amb_local = FALSE; 3275 break; 3276 } 3277 } 3278 } 3279 } 3280 3281 /* Stop if we found a full match or searched all. */ 3282 if (j < gap->ga_len || gap == &ucmds) 3283 break; 3284 gap = &ucmds; 3285 } 3286 3287 /* Only found ambiguous matches. */ 3288 if (amb_local) 3289 { 3290 if (xp != NULL) 3291 xp->xp_context = EXPAND_UNSUCCESSFUL; 3292 return NULL; 3293 } 3294 3295 /* The match we found may be followed immediately by a number. Move "p" 3296 * back to point to it. */ 3297 if (found || possible) 3298 return p + (matchlen - len); 3299 return p; 3300 } 3301 #endif 3302 3303 #if defined(FEAT_EVAL) || defined(PROTO) 3304 static struct cmdmod 3305 { 3306 char *name; 3307 int minlen; 3308 int has_count; /* :123verbose :3tab */ 3309 } cmdmods[] = { 3310 {"aboveleft", 3, FALSE}, 3311 {"belowright", 3, FALSE}, 3312 {"botright", 2, FALSE}, 3313 {"browse", 3, FALSE}, 3314 {"confirm", 4, FALSE}, 3315 {"hide", 3, FALSE}, 3316 {"keepalt", 5, FALSE}, 3317 {"keepjumps", 5, FALSE}, 3318 {"keepmarks", 3, FALSE}, 3319 {"keeppatterns", 5, FALSE}, 3320 {"leftabove", 5, FALSE}, 3321 {"lockmarks", 3, FALSE}, 3322 {"noautocmd", 3, FALSE}, 3323 {"noswapfile", 3, FALSE}, 3324 {"rightbelow", 6, FALSE}, 3325 {"sandbox", 3, FALSE}, 3326 {"silent", 3, FALSE}, 3327 {"tab", 3, TRUE}, 3328 {"topleft", 2, FALSE}, 3329 {"unsilent", 3, FALSE}, 3330 {"verbose", 4, TRUE}, 3331 {"vertical", 4, FALSE}, 3332 }; 3333 3334 /* 3335 * Return length of a command modifier (including optional count). 3336 * Return zero when it's not a modifier. 3337 */ 3338 int 3339 modifier_len(char_u *cmd) 3340 { 3341 int i, j; 3342 char_u *p = cmd; 3343 3344 if (VIM_ISDIGIT(*cmd)) 3345 p = skipwhite(skipdigits(cmd)); 3346 for (i = 0; i < (int)(sizeof(cmdmods) / sizeof(struct cmdmod)); ++i) 3347 { 3348 for (j = 0; p[j] != NUL; ++j) 3349 if (p[j] != cmdmods[i].name[j]) 3350 break; 3351 if (!ASCII_ISALPHA(p[j]) && j >= cmdmods[i].minlen 3352 && (p == cmd || cmdmods[i].has_count)) 3353 return j + (int)(p - cmd); 3354 } 3355 return 0; 3356 } 3357 3358 /* 3359 * Return > 0 if an Ex command "name" exists. 3360 * Return 2 if there is an exact match. 3361 * Return 3 if there is an ambiguous match. 3362 */ 3363 int 3364 cmd_exists(char_u *name) 3365 { 3366 exarg_T ea; 3367 int full = FALSE; 3368 int i; 3369 int j; 3370 char_u *p; 3371 3372 /* Check command modifiers. */ 3373 for (i = 0; i < (int)(sizeof(cmdmods) / sizeof(struct cmdmod)); ++i) 3374 { 3375 for (j = 0; name[j] != NUL; ++j) 3376 if (name[j] != cmdmods[i].name[j]) 3377 break; 3378 if (name[j] == NUL && j >= cmdmods[i].minlen) 3379 return (cmdmods[i].name[j] == NUL ? 2 : 1); 3380 } 3381 3382 /* Check built-in commands and user defined commands. 3383 * For ":2match" and ":3match" we need to skip the number. */ 3384 ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name; 3385 ea.cmdidx = (cmdidx_T)0; 3386 p = find_command(&ea, &full); 3387 if (p == NULL) 3388 return 3; 3389 if (vim_isdigit(*name) && ea.cmdidx != CMD_match) 3390 return 0; 3391 if (*skipwhite(p) != NUL) 3392 return 0; /* trailing garbage */ 3393 return (ea.cmdidx == CMD_SIZE ? 0 : (full ? 2 : 1)); 3394 } 3395 #endif 3396 3397 /* 3398 * This is all pretty much copied from do_one_cmd(), with all the extra stuff 3399 * we don't need/want deleted. Maybe this could be done better if we didn't 3400 * repeat all this stuff. The only problem is that they may not stay 3401 * perfectly compatible with each other, but then the command line syntax 3402 * probably won't change that much -- webb. 3403 */ 3404 char_u * 3405 set_one_cmd_context( 3406 expand_T *xp, 3407 char_u *buff) /* buffer for command string */ 3408 { 3409 char_u *p; 3410 char_u *cmd, *arg; 3411 int len = 0; 3412 exarg_T ea; 3413 #if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) 3414 int compl = EXPAND_NOTHING; 3415 #endif 3416 #ifdef FEAT_CMDL_COMPL 3417 int delim; 3418 #endif 3419 int forceit = FALSE; 3420 int usefilter = FALSE; /* filter instead of file name */ 3421 3422 ExpandInit(xp); 3423 xp->xp_pattern = buff; 3424 xp->xp_context = EXPAND_COMMANDS; /* Default until we get past command */ 3425 ea.argt = 0; 3426 3427 /* 3428 * 1. skip comment lines and leading space, colons or bars 3429 */ 3430 for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++) 3431 ; 3432 xp->xp_pattern = cmd; 3433 3434 if (*cmd == NUL) 3435 return NULL; 3436 if (*cmd == '"') /* ignore comment lines */ 3437 { 3438 xp->xp_context = EXPAND_NOTHING; 3439 return NULL; 3440 } 3441 3442 /* 3443 * 3. Skip over the range to find the command. 3444 */ 3445 cmd = skip_range(cmd, &xp->xp_context); 3446 xp->xp_pattern = cmd; 3447 if (*cmd == NUL) 3448 return NULL; 3449 if (*cmd == '"') 3450 { 3451 xp->xp_context = EXPAND_NOTHING; 3452 return NULL; 3453 } 3454 3455 if (*cmd == '|' || *cmd == '\n') 3456 return cmd + 1; /* There's another command */ 3457 3458 /* 3459 * Isolate the command and search for it in the command table. 3460 * Exceptions: 3461 * - the 'k' command can directly be followed by any character, but 3462 * do accept "keepmarks", "keepalt" and "keepjumps". 3463 * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' 3464 */ 3465 if (*cmd == 'k' && cmd[1] != 'e') 3466 { 3467 ea.cmdidx = CMD_k; 3468 p = cmd + 1; 3469 } 3470 else 3471 { 3472 p = cmd; 3473 while (ASCII_ISALPHA(*p) || *p == '*') /* Allow * wild card */ 3474 ++p; 3475 /* a user command may contain digits */ 3476 if (ASCII_ISUPPER(cmd[0])) 3477 while (ASCII_ISALNUM(*p) || *p == '*') 3478 ++p; 3479 /* for python 3.x: ":py3*" commands completion */ 3480 if (cmd[0] == 'p' && cmd[1] == 'y' && p == cmd + 2 && *p == '3') 3481 { 3482 ++p; 3483 while (ASCII_ISALPHA(*p) || *p == '*') 3484 ++p; 3485 } 3486 /* check for non-alpha command */ 3487 if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL) 3488 ++p; 3489 len = (int)(p - cmd); 3490 3491 if (len == 0) 3492 { 3493 xp->xp_context = EXPAND_UNSUCCESSFUL; 3494 return NULL; 3495 } 3496 for (ea.cmdidx = (cmdidx_T)0; (int)ea.cmdidx < (int)CMD_SIZE; 3497 ea.cmdidx = (cmdidx_T)((int)ea.cmdidx + 1)) 3498 if (STRNCMP(cmdnames[(int)ea.cmdidx].cmd_name, cmd, 3499 (size_t)len) == 0) 3500 break; 3501 3502 #ifdef FEAT_USR_CMDS 3503 if (cmd[0] >= 'A' && cmd[0] <= 'Z') 3504 while (ASCII_ISALNUM(*p) || *p == '*') /* Allow * wild card */ 3505 ++p; 3506 #endif 3507 } 3508 3509 /* 3510 * If the cursor is touching the command, and it ends in an alpha-numeric 3511 * character, complete the command name. 3512 */ 3513 if (*p == NUL && ASCII_ISALNUM(p[-1])) 3514 return NULL; 3515 3516 if (ea.cmdidx == CMD_SIZE) 3517 { 3518 if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL) 3519 { 3520 ea.cmdidx = CMD_substitute; 3521 p = cmd + 1; 3522 } 3523 #ifdef FEAT_USR_CMDS 3524 else if (cmd[0] >= 'A' && cmd[0] <= 'Z') 3525 { 3526 ea.cmd = cmd; 3527 p = find_ucmd(&ea, p, NULL, xp, 3528 # if defined(FEAT_CMDL_COMPL) 3529 &compl 3530 # else 3531 NULL 3532 # endif 3533 ); 3534 if (p == NULL) 3535 ea.cmdidx = CMD_SIZE; /* ambiguous user command */ 3536 } 3537 #endif 3538 } 3539 if (ea.cmdidx == CMD_SIZE) 3540 { 3541 /* Not still touching the command and it was an illegal one */ 3542 xp->xp_context = EXPAND_UNSUCCESSFUL; 3543 return NULL; 3544 } 3545 3546 xp->xp_context = EXPAND_NOTHING; /* Default now that we're past command */ 3547 3548 if (*p == '!') /* forced commands */ 3549 { 3550 forceit = TRUE; 3551 ++p; 3552 } 3553 3554 /* 3555 * 6. parse arguments 3556 */ 3557 if (!IS_USER_CMDIDX(ea.cmdidx)) 3558 ea.argt = (long)cmdnames[(int)ea.cmdidx].cmd_argt; 3559 3560 arg = skipwhite(p); 3561 3562 if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) 3563 { 3564 if (*arg == '>') /* append */ 3565 { 3566 if (*++arg == '>') 3567 ++arg; 3568 arg = skipwhite(arg); 3569 } 3570 else if (*arg == '!' && ea.cmdidx == CMD_write) /* :w !filter */ 3571 { 3572 ++arg; 3573 usefilter = TRUE; 3574 } 3575 } 3576 3577 if (ea.cmdidx == CMD_read) 3578 { 3579 usefilter = forceit; /* :r! filter if forced */ 3580 if (*arg == '!') /* :r !filter */ 3581 { 3582 ++arg; 3583 usefilter = TRUE; 3584 } 3585 } 3586 3587 if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) 3588 { 3589 while (*arg == *cmd) /* allow any number of '>' or '<' */ 3590 ++arg; 3591 arg = skipwhite(arg); 3592 } 3593 3594 /* Does command allow "+command"? */ 3595 if ((ea.argt & EDITCMD) && !usefilter && *arg == '+') 3596 { 3597 /* Check if we're in the +command */ 3598 p = arg + 1; 3599 arg = skip_cmd_arg(arg, FALSE); 3600 3601 /* Still touching the command after '+'? */ 3602 if (*arg == NUL) 3603 return p; 3604 3605 /* Skip space(s) after +command to get to the real argument */ 3606 arg = skipwhite(arg); 3607 } 3608 3609 /* 3610 * Check for '|' to separate commands and '"' to start comments. 3611 * Don't do this for ":read !cmd" and ":write !cmd". 3612 */ 3613 if ((ea.argt & TRLBAR) && !usefilter) 3614 { 3615 p = arg; 3616 /* ":redir @" is not the start of a comment */ 3617 if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"') 3618 p += 2; 3619 while (*p) 3620 { 3621 if (*p == Ctrl_V) 3622 { 3623 if (p[1] != NUL) 3624 ++p; 3625 } 3626 else if ( (*p == '"' && !(ea.argt & NOTRLCOM)) 3627 || *p == '|' || *p == '\n') 3628 { 3629 if (*(p - 1) != '\\') 3630 { 3631 if (*p == '|' || *p == '\n') 3632 return p + 1; 3633 return NULL; /* It's a comment */ 3634 } 3635 } 3636 mb_ptr_adv(p); 3637 } 3638 } 3639 3640 /* no arguments allowed */ 3641 if (!(ea.argt & EXTRA) && *arg != NUL && 3642 vim_strchr((char_u *)"|\"", *arg) == NULL) 3643 return NULL; 3644 3645 /* Find start of last argument (argument just before cursor): */ 3646 p = buff; 3647 xp->xp_pattern = p; 3648 len = (int)STRLEN(buff); 3649 while (*p && p < buff + len) 3650 { 3651 if (*p == ' ' || *p == TAB) 3652 { 3653 /* argument starts after a space */ 3654 xp->xp_pattern = ++p; 3655 } 3656 else 3657 { 3658 if (*p == '\\' && *(p + 1) != NUL) 3659 ++p; /* skip over escaped character */ 3660 mb_ptr_adv(p); 3661 } 3662 } 3663 3664 if (ea.argt & XFILE) 3665 { 3666 int c; 3667 int in_quote = FALSE; 3668 char_u *bow = NULL; /* Beginning of word */ 3669 3670 /* 3671 * Allow spaces within back-quotes to count as part of the argument 3672 * being expanded. 3673 */ 3674 xp->xp_pattern = skipwhite(arg); 3675 p = xp->xp_pattern; 3676 while (*p != NUL) 3677 { 3678 #ifdef FEAT_MBYTE 3679 if (has_mbyte) 3680 c = mb_ptr2char(p); 3681 else 3682 #endif 3683 c = *p; 3684 if (c == '\\' && p[1] != NUL) 3685 ++p; 3686 else if (c == '`') 3687 { 3688 if (!in_quote) 3689 { 3690 xp->xp_pattern = p; 3691 bow = p + 1; 3692 } 3693 in_quote = !in_quote; 3694 } 3695 /* An argument can contain just about everything, except 3696 * characters that end the command and white space. */ 3697 else if (c == '|' || c == '\n' || c == '"' || (vim_iswhite(c) 3698 #ifdef SPACE_IN_FILENAME 3699 && (!(ea.argt & NOSPC) || usefilter) 3700 #endif 3701 )) 3702 { 3703 len = 0; /* avoid getting stuck when space is in 'isfname' */ 3704 while (*p != NUL) 3705 { 3706 #ifdef FEAT_MBYTE 3707 if (has_mbyte) 3708 c = mb_ptr2char(p); 3709 else 3710 #endif 3711 c = *p; 3712 if (c == '`' || vim_isfilec_or_wc(c)) 3713 break; 3714 #ifdef FEAT_MBYTE 3715 if (has_mbyte) 3716 len = (*mb_ptr2len)(p); 3717 else 3718 #endif 3719 len = 1; 3720 mb_ptr_adv(p); 3721 } 3722 if (in_quote) 3723 bow = p; 3724 else 3725 xp->xp_pattern = p; 3726 p -= len; 3727 } 3728 mb_ptr_adv(p); 3729 } 3730 3731 /* 3732 * If we are still inside the quotes, and we passed a space, just 3733 * expand from there. 3734 */ 3735 if (bow != NULL && in_quote) 3736 xp->xp_pattern = bow; 3737 xp->xp_context = EXPAND_FILES; 3738 3739 /* For a shell command more chars need to be escaped. */ 3740 if (usefilter || ea.cmdidx == CMD_bang) 3741 { 3742 #ifndef BACKSLASH_IN_FILENAME 3743 xp->xp_shell = TRUE; 3744 #endif 3745 /* When still after the command name expand executables. */ 3746 if (xp->xp_pattern == skipwhite(arg)) 3747 xp->xp_context = EXPAND_SHELLCMD; 3748 } 3749 3750 /* Check for environment variable */ 3751 if (*xp->xp_pattern == '$' 3752 #if defined(MSWIN) 3753 || *xp->xp_pattern == '%' 3754 #endif 3755 ) 3756 { 3757 for (p = xp->xp_pattern + 1; *p != NUL; ++p) 3758 if (!vim_isIDc(*p)) 3759 break; 3760 if (*p == NUL) 3761 { 3762 xp->xp_context = EXPAND_ENV_VARS; 3763 ++xp->xp_pattern; 3764 #if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) 3765 /* Avoid that the assignment uses EXPAND_FILES again. */ 3766 if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST) 3767 compl = EXPAND_ENV_VARS; 3768 #endif 3769 } 3770 } 3771 #if defined(FEAT_CMDL_COMPL) 3772 /* Check for user names */ 3773 if (*xp->xp_pattern == '~') 3774 { 3775 for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p) 3776 ; 3777 /* Complete ~user only if it partially matches a user name. 3778 * A full match ~user<Tab> will be replaced by user's home 3779 * directory i.e. something like ~user<Tab> -> /home/user/ */ 3780 if (*p == NUL && p > xp->xp_pattern + 1 3781 && match_user(xp->xp_pattern + 1) == 1) 3782 { 3783 xp->xp_context = EXPAND_USER; 3784 ++xp->xp_pattern; 3785 } 3786 } 3787 #endif 3788 } 3789 3790 /* 3791 * 6. Switch on command name. 3792 */ 3793 switch (ea.cmdidx) 3794 { 3795 case CMD_find: 3796 case CMD_sfind: 3797 case CMD_tabfind: 3798 if (xp->xp_context == EXPAND_FILES) 3799 xp->xp_context = EXPAND_FILES_IN_PATH; 3800 break; 3801 case CMD_cd: 3802 case CMD_chdir: 3803 case CMD_lcd: 3804 case CMD_lchdir: 3805 if (xp->xp_context == EXPAND_FILES) 3806 xp->xp_context = EXPAND_DIRECTORIES; 3807 break; 3808 case CMD_help: 3809 xp->xp_context = EXPAND_HELP; 3810 xp->xp_pattern = arg; 3811 break; 3812 3813 /* Command modifiers: return the argument. 3814 * Also for commands with an argument that is a command. */ 3815 case CMD_aboveleft: 3816 case CMD_argdo: 3817 case CMD_belowright: 3818 case CMD_botright: 3819 case CMD_browse: 3820 case CMD_bufdo: 3821 case CMD_cdo: 3822 case CMD_cfdo: 3823 case CMD_confirm: 3824 case CMD_debug: 3825 case CMD_folddoclosed: 3826 case CMD_folddoopen: 3827 case CMD_hide: 3828 case CMD_keepalt: 3829 case CMD_keepjumps: 3830 case CMD_keepmarks: 3831 case CMD_keeppatterns: 3832 case CMD_ldo: 3833 case CMD_leftabove: 3834 case CMD_lfdo: 3835 case CMD_lockmarks: 3836 case CMD_noautocmd: 3837 case CMD_noswapfile: 3838 case CMD_rightbelow: 3839 case CMD_sandbox: 3840 case CMD_silent: 3841 case CMD_tab: 3842 case CMD_tabdo: 3843 case CMD_topleft: 3844 case CMD_verbose: 3845 case CMD_vertical: 3846 case CMD_windo: 3847 return arg; 3848 3849 #ifdef FEAT_CMDL_COMPL 3850 # ifdef FEAT_SEARCH_EXTRA 3851 case CMD_match: 3852 if (*arg == NUL || !ends_excmd(*arg)) 3853 { 3854 /* also complete "None" */ 3855 set_context_in_echohl_cmd(xp, arg); 3856 arg = skipwhite(skiptowhite(arg)); 3857 if (*arg != NUL) 3858 { 3859 xp->xp_context = EXPAND_NOTHING; 3860 arg = skip_regexp(arg + 1, *arg, p_magic, NULL); 3861 } 3862 } 3863 return find_nextcmd(arg); 3864 # endif 3865 3866 /* 3867 * All completion for the +cmdline_compl feature goes here. 3868 */ 3869 3870 # ifdef FEAT_USR_CMDS 3871 case CMD_command: 3872 /* Check for attributes */ 3873 while (*arg == '-') 3874 { 3875 arg++; /* Skip "-" */ 3876 p = skiptowhite(arg); 3877 if (*p == NUL) 3878 { 3879 /* Cursor is still in the attribute */ 3880 p = vim_strchr(arg, '='); 3881 if (p == NULL) 3882 { 3883 /* No "=", so complete attribute names */ 3884 xp->xp_context = EXPAND_USER_CMD_FLAGS; 3885 xp->xp_pattern = arg; 3886 return NULL; 3887 } 3888 3889 /* For the -complete, -nargs and -addr attributes, we complete 3890 * their arguments as well. 3891 */ 3892 if (STRNICMP(arg, "complete", p - arg) == 0) 3893 { 3894 xp->xp_context = EXPAND_USER_COMPLETE; 3895 xp->xp_pattern = p + 1; 3896 return NULL; 3897 } 3898 else if (STRNICMP(arg, "nargs", p - arg) == 0) 3899 { 3900 xp->xp_context = EXPAND_USER_NARGS; 3901 xp->xp_pattern = p + 1; 3902 return NULL; 3903 } 3904 else if (STRNICMP(arg, "addr", p - arg) == 0) 3905 { 3906 xp->xp_context = EXPAND_USER_ADDR_TYPE; 3907 xp->xp_pattern = p + 1; 3908 return NULL; 3909 } 3910 return NULL; 3911 } 3912 arg = skipwhite(p); 3913 } 3914 3915 /* After the attributes comes the new command name */ 3916 p = skiptowhite(arg); 3917 if (*p == NUL) 3918 { 3919 xp->xp_context = EXPAND_USER_COMMANDS; 3920 xp->xp_pattern = arg; 3921 break; 3922 } 3923 3924 /* And finally comes a normal command */ 3925 return skipwhite(p); 3926 3927 case CMD_delcommand: 3928 xp->xp_context = EXPAND_USER_COMMANDS; 3929 xp->xp_pattern = arg; 3930 break; 3931 # endif 3932 3933 case CMD_global: 3934 case CMD_vglobal: 3935 delim = *arg; /* get the delimiter */ 3936 if (delim) 3937 ++arg; /* skip delimiter if there is one */ 3938 3939 while (arg[0] != NUL && arg[0] != delim) 3940 { 3941 if (arg[0] == '\\' && arg[1] != NUL) 3942 ++arg; 3943 ++arg; 3944 } 3945 if (arg[0] != NUL) 3946 return arg + 1; 3947 break; 3948 case CMD_and: 3949 case CMD_substitute: 3950 delim = *arg; 3951 if (delim) 3952 { 3953 /* skip "from" part */ 3954 ++arg; 3955 arg = skip_regexp(arg, delim, p_magic, NULL); 3956 } 3957 /* skip "to" part */ 3958 while (arg[0] != NUL && arg[0] != delim) 3959 { 3960 if (arg[0] == '\\' && arg[1] != NUL) 3961 ++arg; 3962 ++arg; 3963 } 3964 if (arg[0] != NUL) /* skip delimiter */ 3965 ++arg; 3966 while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL) 3967 ++arg; 3968 if (arg[0] != NUL) 3969 return arg; 3970 break; 3971 case CMD_isearch: 3972 case CMD_dsearch: 3973 case CMD_ilist: 3974 case CMD_dlist: 3975 case CMD_ijump: 3976 case CMD_psearch: 3977 case CMD_djump: 3978 case CMD_isplit: 3979 case CMD_dsplit: 3980 arg = skipwhite(skipdigits(arg)); /* skip count */ 3981 if (*arg == '/') /* Match regexp, not just whole words */ 3982 { 3983 for (++arg; *arg && *arg != '/'; arg++) 3984 if (*arg == '\\' && arg[1] != NUL) 3985 arg++; 3986 if (*arg) 3987 { 3988 arg = skipwhite(arg + 1); 3989 3990 /* Check for trailing illegal characters */ 3991 if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL) 3992 xp->xp_context = EXPAND_NOTHING; 3993 else 3994 return arg; 3995 } 3996 } 3997 break; 3998 #ifdef FEAT_AUTOCMD 3999 case CMD_autocmd: 4000 return set_context_in_autocmd(xp, arg, FALSE); 4001 4002 case CMD_doautocmd: 4003 case CMD_doautoall: 4004 return set_context_in_autocmd(xp, arg, TRUE); 4005 #endif 4006 case CMD_set: 4007 set_context_in_set_cmd(xp, arg, 0); 4008 break; 4009 case CMD_setglobal: 4010 set_context_in_set_cmd(xp, arg, OPT_GLOBAL); 4011 break; 4012 case CMD_setlocal: 4013 set_context_in_set_cmd(xp, arg, OPT_LOCAL); 4014 break; 4015 case CMD_tag: 4016 case CMD_stag: 4017 case CMD_ptag: 4018 case CMD_ltag: 4019 case CMD_tselect: 4020 case CMD_stselect: 4021 case CMD_ptselect: 4022 case CMD_tjump: 4023 case CMD_stjump: 4024 case CMD_ptjump: 4025 if (*p_wop != NUL) 4026 xp->xp_context = EXPAND_TAGS_LISTFILES; 4027 else 4028 xp->xp_context = EXPAND_TAGS; 4029 xp->xp_pattern = arg; 4030 break; 4031 case CMD_augroup: 4032 xp->xp_context = EXPAND_AUGROUP; 4033 xp->xp_pattern = arg; 4034 break; 4035 #ifdef FEAT_SYN_HL 4036 case CMD_syntax: 4037 set_context_in_syntax_cmd(xp, arg); 4038 break; 4039 #endif 4040 #ifdef FEAT_EVAL 4041 case CMD_let: 4042 case CMD_if: 4043 case CMD_elseif: 4044 case CMD_while: 4045 case CMD_for: 4046 case CMD_echo: 4047 case CMD_echon: 4048 case CMD_execute: 4049 case CMD_echomsg: 4050 case CMD_echoerr: 4051 case CMD_call: 4052 case CMD_return: 4053 set_context_for_expression(xp, arg, ea.cmdidx); 4054 break; 4055 4056 case CMD_unlet: 4057 while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) 4058 arg = xp->xp_pattern + 1; 4059 xp->xp_context = EXPAND_USER_VARS; 4060 xp->xp_pattern = arg; 4061 break; 4062 4063 case CMD_function: 4064 case CMD_delfunction: 4065 xp->xp_context = EXPAND_USER_FUNC; 4066 xp->xp_pattern = arg; 4067 break; 4068 4069 case CMD_echohl: 4070 set_context_in_echohl_cmd(xp, arg); 4071 break; 4072 #endif 4073 case CMD_highlight: 4074 set_context_in_highlight_cmd(xp, arg); 4075 break; 4076 #ifdef FEAT_CSCOPE 4077 case CMD_cscope: 4078 case CMD_lcscope: 4079 case CMD_scscope: 4080 set_context_in_cscope_cmd(xp, arg, ea.cmdidx); 4081 break; 4082 #endif 4083 #ifdef FEAT_SIGNS 4084 case CMD_sign: 4085 set_context_in_sign_cmd(xp, arg); 4086 break; 4087 #endif 4088 #ifdef FEAT_LISTCMDS 4089 case CMD_bdelete: 4090 case CMD_bwipeout: 4091 case CMD_bunload: 4092 while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) 4093 arg = xp->xp_pattern + 1; 4094 /*FALLTHROUGH*/ 4095 case CMD_buffer: 4096 case CMD_sbuffer: 4097 case CMD_checktime: 4098 xp->xp_context = EXPAND_BUFFERS; 4099 xp->xp_pattern = arg; 4100 break; 4101 #endif 4102 #ifdef FEAT_USR_CMDS 4103 case CMD_USER: 4104 case CMD_USER_BUF: 4105 if (compl != EXPAND_NOTHING) 4106 { 4107 /* XFILE: file names are handled above */ 4108 if (!(ea.argt & XFILE)) 4109 { 4110 # ifdef FEAT_MENU 4111 if (compl == EXPAND_MENUS) 4112 return set_context_in_menu_cmd(xp, cmd, arg, forceit); 4113 # endif 4114 if (compl == EXPAND_COMMANDS) 4115 return arg; 4116 if (compl == EXPAND_MAPPINGS) 4117 return set_context_in_map_cmd(xp, (char_u *)"map", 4118 arg, forceit, FALSE, FALSE, CMD_map); 4119 /* Find start of last argument. */ 4120 p = arg; 4121 while (*p) 4122 { 4123 if (*p == ' ') 4124 /* argument starts after a space */ 4125 arg = p + 1; 4126 else if (*p == '\\' && *(p + 1) != NUL) 4127 ++p; /* skip over escaped character */ 4128 mb_ptr_adv(p); 4129 } 4130 xp->xp_pattern = arg; 4131 } 4132 xp->xp_context = compl; 4133 } 4134 break; 4135 #endif 4136 case CMD_map: case CMD_noremap: 4137 case CMD_nmap: case CMD_nnoremap: 4138 case CMD_vmap: case CMD_vnoremap: 4139 case CMD_omap: case CMD_onoremap: 4140 case CMD_imap: case CMD_inoremap: 4141 case CMD_cmap: case CMD_cnoremap: 4142 case CMD_lmap: case CMD_lnoremap: 4143 case CMD_smap: case CMD_snoremap: 4144 case CMD_xmap: case CMD_xnoremap: 4145 return set_context_in_map_cmd(xp, cmd, arg, forceit, 4146 FALSE, FALSE, ea.cmdidx); 4147 case CMD_unmap: 4148 case CMD_nunmap: 4149 case CMD_vunmap: 4150 case CMD_ounmap: 4151 case CMD_iunmap: 4152 case CMD_cunmap: 4153 case CMD_lunmap: 4154 case CMD_sunmap: 4155 case CMD_xunmap: 4156 return set_context_in_map_cmd(xp, cmd, arg, forceit, 4157 FALSE, TRUE, ea.cmdidx); 4158 case CMD_abbreviate: case CMD_noreabbrev: 4159 case CMD_cabbrev: case CMD_cnoreabbrev: 4160 case CMD_iabbrev: case CMD_inoreabbrev: 4161 return set_context_in_map_cmd(xp, cmd, arg, forceit, 4162 TRUE, FALSE, ea.cmdidx); 4163 case CMD_unabbreviate: 4164 case CMD_cunabbrev: 4165 case CMD_iunabbrev: 4166 return set_context_in_map_cmd(xp, cmd, arg, forceit, 4167 TRUE, TRUE, ea.cmdidx); 4168 #ifdef FEAT_MENU 4169 case CMD_menu: case CMD_noremenu: case CMD_unmenu: 4170 case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu: 4171 case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu: 4172 case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu: 4173 case CMD_omenu: case CMD_onoremenu: case CMD_ounmenu: 4174 case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu: 4175 case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu: 4176 case CMD_tmenu: case CMD_tunmenu: 4177 case CMD_popup: case CMD_tearoff: case CMD_emenu: 4178 return set_context_in_menu_cmd(xp, cmd, arg, forceit); 4179 #endif 4180 4181 case CMD_colorscheme: 4182 xp->xp_context = EXPAND_COLORS; 4183 xp->xp_pattern = arg; 4184 break; 4185 4186 case CMD_compiler: 4187 xp->xp_context = EXPAND_COMPILER; 4188 xp->xp_pattern = arg; 4189 break; 4190 4191 case CMD_ownsyntax: 4192 xp->xp_context = EXPAND_OWNSYNTAX; 4193 xp->xp_pattern = arg; 4194 break; 4195 4196 case CMD_setfiletype: 4197 xp->xp_context = EXPAND_FILETYPE; 4198 xp->xp_pattern = arg; 4199 break; 4200 4201 case CMD_packadd: 4202 xp->xp_context = EXPAND_PACKADD; 4203 xp->xp_pattern = arg; 4204 break; 4205 4206 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 4207 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) 4208 case CMD_language: 4209 p = skiptowhite(arg); 4210 if (*p == NUL) 4211 { 4212 xp->xp_context = EXPAND_LANGUAGE; 4213 xp->xp_pattern = arg; 4214 } 4215 else 4216 { 4217 if ( STRNCMP(arg, "messages", p - arg) == 0 4218 || STRNCMP(arg, "ctype", p - arg) == 0 4219 || STRNCMP(arg, "time", p - arg) == 0) 4220 { 4221 xp->xp_context = EXPAND_LOCALES; 4222 xp->xp_pattern = skipwhite(p); 4223 } 4224 else 4225 xp->xp_context = EXPAND_NOTHING; 4226 } 4227 break; 4228 #endif 4229 #if defined(FEAT_PROFILE) 4230 case CMD_profile: 4231 set_context_in_profile_cmd(xp, arg); 4232 break; 4233 #endif 4234 case CMD_behave: 4235 xp->xp_context = EXPAND_BEHAVE; 4236 xp->xp_pattern = arg; 4237 break; 4238 4239 #if defined(FEAT_CMDHIST) 4240 case CMD_history: 4241 xp->xp_context = EXPAND_HISTORY; 4242 xp->xp_pattern = arg; 4243 break; 4244 #endif 4245 #if defined(FEAT_PROFILE) 4246 case CMD_syntime: 4247 xp->xp_context = EXPAND_SYNTIME; 4248 xp->xp_pattern = arg; 4249 break; 4250 #endif 4251 4252 #endif /* FEAT_CMDL_COMPL */ 4253 4254 default: 4255 break; 4256 } 4257 return NULL; 4258 } 4259 4260 /* 4261 * skip a range specifier of the form: addr [,addr] [;addr] .. 4262 * 4263 * Backslashed delimiters after / or ? will be skipped, and commands will 4264 * not be expanded between /'s and ?'s or after "'". 4265 * 4266 * Also skip white space and ":" characters. 4267 * Returns the "cmd" pointer advanced to beyond the range. 4268 */ 4269 char_u * 4270 skip_range( 4271 char_u *cmd, 4272 int *ctx) /* pointer to xp_context or NULL */ 4273 { 4274 unsigned delim; 4275 4276 while (vim_strchr((char_u *)" \t0123456789.$%'/?-+,;", *cmd) != NULL) 4277 { 4278 if (*cmd == '\'') 4279 { 4280 if (*++cmd == NUL && ctx != NULL) 4281 *ctx = EXPAND_NOTHING; 4282 } 4283 else if (*cmd == '/' || *cmd == '?') 4284 { 4285 delim = *cmd++; 4286 while (*cmd != NUL && *cmd != delim) 4287 if (*cmd++ == '\\' && *cmd != NUL) 4288 ++cmd; 4289 if (*cmd == NUL && ctx != NULL) 4290 *ctx = EXPAND_NOTHING; 4291 } 4292 if (*cmd != NUL) 4293 ++cmd; 4294 } 4295 4296 /* Skip ":" and white space. */ 4297 while (*cmd == ':') 4298 cmd = skipwhite(cmd + 1); 4299 4300 return cmd; 4301 } 4302 4303 /* 4304 * get a single EX address 4305 * 4306 * Set ptr to the next character after the part that was interpreted. 4307 * Set ptr to NULL when an error is encountered. 4308 * 4309 * Return MAXLNUM when no Ex address was found. 4310 */ 4311 static linenr_T 4312 get_address( 4313 exarg_T *eap UNUSED, 4314 char_u **ptr, 4315 int addr_type, /* flag: one of ADDR_LINES, ... */ 4316 int skip, /* only skip the address, don't use it */ 4317 int to_other_file) /* flag: may jump to other file */ 4318 { 4319 int c; 4320 int i; 4321 long n; 4322 char_u *cmd; 4323 pos_T pos; 4324 pos_T *fp; 4325 linenr_T lnum; 4326 buf_T *buf; 4327 4328 cmd = skipwhite(*ptr); 4329 lnum = MAXLNUM; 4330 do 4331 { 4332 switch (*cmd) 4333 { 4334 case '.': /* '.' - Cursor position */ 4335 ++cmd; 4336 switch (addr_type) 4337 { 4338 case ADDR_LINES: 4339 lnum = curwin->w_cursor.lnum; 4340 break; 4341 case ADDR_WINDOWS: 4342 lnum = CURRENT_WIN_NR; 4343 break; 4344 case ADDR_ARGUMENTS: 4345 lnum = curwin->w_arg_idx + 1; 4346 break; 4347 case ADDR_LOADED_BUFFERS: 4348 case ADDR_BUFFERS: 4349 lnum = curbuf->b_fnum; 4350 break; 4351 case ADDR_TABS: 4352 lnum = CURRENT_TAB_NR; 4353 break; 4354 #ifdef FEAT_QUICKFIX 4355 case ADDR_QUICKFIX: 4356 lnum = qf_get_cur_valid_idx(eap); 4357 break; 4358 #endif 4359 } 4360 break; 4361 4362 case '$': /* '$' - last line */ 4363 ++cmd; 4364 switch (addr_type) 4365 { 4366 case ADDR_LINES: 4367 lnum = curbuf->b_ml.ml_line_count; 4368 break; 4369 case ADDR_WINDOWS: 4370 lnum = LAST_WIN_NR; 4371 break; 4372 case ADDR_ARGUMENTS: 4373 lnum = ARGCOUNT; 4374 break; 4375 case ADDR_LOADED_BUFFERS: 4376 buf = lastbuf; 4377 while (buf->b_ml.ml_mfp == NULL) 4378 { 4379 if (buf->b_prev == NULL) 4380 break; 4381 buf = buf->b_prev; 4382 } 4383 lnum = buf->b_fnum; 4384 break; 4385 case ADDR_BUFFERS: 4386 lnum = lastbuf->b_fnum; 4387 break; 4388 case ADDR_TABS: 4389 lnum = LAST_TAB_NR; 4390 break; 4391 #ifdef FEAT_QUICKFIX 4392 case ADDR_QUICKFIX: 4393 lnum = qf_get_size(eap); 4394 if (lnum == 0) 4395 lnum = 1; 4396 break; 4397 #endif 4398 } 4399 break; 4400 4401 case '\'': /* ''' - mark */ 4402 if (*++cmd == NUL) 4403 { 4404 cmd = NULL; 4405 goto error; 4406 } 4407 if (addr_type != ADDR_LINES) 4408 { 4409 EMSG(_(e_invaddr)); 4410 cmd = NULL; 4411 goto error; 4412 } 4413 if (skip) 4414 ++cmd; 4415 else 4416 { 4417 /* Only accept a mark in another file when it is 4418 * used by itself: ":'M". */ 4419 fp = getmark(*cmd, to_other_file && cmd[1] == NUL); 4420 ++cmd; 4421 if (fp == (pos_T *)-1) 4422 /* Jumped to another file. */ 4423 lnum = curwin->w_cursor.lnum; 4424 else 4425 { 4426 if (check_mark(fp) == FAIL) 4427 { 4428 cmd = NULL; 4429 goto error; 4430 } 4431 lnum = fp->lnum; 4432 } 4433 } 4434 break; 4435 4436 case '/': 4437 case '?': /* '/' or '?' - search */ 4438 c = *cmd++; 4439 if (addr_type != ADDR_LINES) 4440 { 4441 EMSG(_(e_invaddr)); 4442 cmd = NULL; 4443 goto error; 4444 } 4445 if (skip) /* skip "/pat/" */ 4446 { 4447 cmd = skip_regexp(cmd, c, (int)p_magic, NULL); 4448 if (*cmd == c) 4449 ++cmd; 4450 } 4451 else 4452 { 4453 pos = curwin->w_cursor; /* save curwin->w_cursor */ 4454 /* 4455 * When '/' or '?' follows another address, start 4456 * from there. 4457 */ 4458 if (lnum != MAXLNUM) 4459 curwin->w_cursor.lnum = lnum; 4460 /* 4461 * Start a forward search at the end of the line. 4462 * Start a backward search at the start of the line. 4463 * This makes sure we never match in the current 4464 * line, and can match anywhere in the 4465 * next/previous line. 4466 */ 4467 if (c == '/') 4468 curwin->w_cursor.col = MAXCOL; 4469 else 4470 curwin->w_cursor.col = 0; 4471 searchcmdlen = 0; 4472 if (!do_search(NULL, c, cmd, 1L, 4473 SEARCH_HIS | SEARCH_MSG, NULL)) 4474 { 4475 curwin->w_cursor = pos; 4476 cmd = NULL; 4477 goto error; 4478 } 4479 lnum = curwin->w_cursor.lnum; 4480 curwin->w_cursor = pos; 4481 /* adjust command string pointer */ 4482 cmd += searchcmdlen; 4483 } 4484 break; 4485 4486 case '\\': /* "\?", "\/" or "\&", repeat search */ 4487 ++cmd; 4488 if (addr_type != ADDR_LINES) 4489 { 4490 EMSG(_(e_invaddr)); 4491 cmd = NULL; 4492 goto error; 4493 } 4494 if (*cmd == '&') 4495 i = RE_SUBST; 4496 else if (*cmd == '?' || *cmd == '/') 4497 i = RE_SEARCH; 4498 else 4499 { 4500 EMSG(_(e_backslash)); 4501 cmd = NULL; 4502 goto error; 4503 } 4504 4505 if (!skip) 4506 { 4507 /* 4508 * When search follows another address, start from 4509 * there. 4510 */ 4511 if (lnum != MAXLNUM) 4512 pos.lnum = lnum; 4513 else 4514 pos.lnum = curwin->w_cursor.lnum; 4515 4516 /* 4517 * Start the search just like for the above 4518 * do_search(). 4519 */ 4520 if (*cmd != '?') 4521 pos.col = MAXCOL; 4522 else 4523 pos.col = 0; 4524 #ifdef FEAT_VIRTUALEDIT 4525 pos.coladd = 0; 4526 #endif 4527 if (searchit(curwin, curbuf, &pos, 4528 *cmd == '?' ? BACKWARD : FORWARD, 4529 (char_u *)"", 1L, SEARCH_MSG, 4530 i, (linenr_T)0, NULL) != FAIL) 4531 lnum = pos.lnum; 4532 else 4533 { 4534 cmd = NULL; 4535 goto error; 4536 } 4537 } 4538 ++cmd; 4539 break; 4540 4541 default: 4542 if (VIM_ISDIGIT(*cmd)) /* absolute line number */ 4543 lnum = getdigits(&cmd); 4544 } 4545 4546 for (;;) 4547 { 4548 cmd = skipwhite(cmd); 4549 if (*cmd != '-' && *cmd != '+' && !VIM_ISDIGIT(*cmd)) 4550 break; 4551 4552 if (lnum == MAXLNUM) 4553 { 4554 switch (addr_type) 4555 { 4556 case ADDR_LINES: 4557 /* "+1" is same as ".+1" */ 4558 lnum = curwin->w_cursor.lnum; 4559 break; 4560 case ADDR_WINDOWS: 4561 lnum = CURRENT_WIN_NR; 4562 break; 4563 case ADDR_ARGUMENTS: 4564 lnum = curwin->w_arg_idx + 1; 4565 break; 4566 case ADDR_LOADED_BUFFERS: 4567 case ADDR_BUFFERS: 4568 lnum = curbuf->b_fnum; 4569 break; 4570 case ADDR_TABS: 4571 lnum = CURRENT_TAB_NR; 4572 break; 4573 #ifdef FEAT_QUICKFIX 4574 case ADDR_QUICKFIX: 4575 lnum = qf_get_cur_valid_idx(eap); 4576 break; 4577 #endif 4578 } 4579 } 4580 4581 if (VIM_ISDIGIT(*cmd)) 4582 i = '+'; /* "number" is same as "+number" */ 4583 else 4584 i = *cmd++; 4585 if (!VIM_ISDIGIT(*cmd)) /* '+' is '+1', but '+0' is not '+1' */ 4586 n = 1; 4587 else 4588 n = getdigits(&cmd); 4589 if (addr_type == ADDR_LOADED_BUFFERS 4590 || addr_type == ADDR_BUFFERS) 4591 lnum = compute_buffer_local_count( 4592 addr_type, lnum, (i == '-') ? -1 * n : n); 4593 else if (i == '-') 4594 lnum -= n; 4595 else 4596 lnum += n; 4597 } 4598 } while (*cmd == '/' || *cmd == '?'); 4599 4600 error: 4601 *ptr = cmd; 4602 return lnum; 4603 } 4604 4605 /* 4606 * Get flags from an Ex command argument. 4607 */ 4608 static void 4609 get_flags(exarg_T *eap) 4610 { 4611 while (vim_strchr((char_u *)"lp#", *eap->arg) != NULL) 4612 { 4613 if (*eap->arg == 'l') 4614 eap->flags |= EXFLAG_LIST; 4615 else if (*eap->arg == 'p') 4616 eap->flags |= EXFLAG_PRINT; 4617 else 4618 eap->flags |= EXFLAG_NR; 4619 eap->arg = skipwhite(eap->arg + 1); 4620 } 4621 } 4622 4623 /* 4624 * Function called for command which is Not Implemented. NI! 4625 */ 4626 void 4627 ex_ni(exarg_T *eap) 4628 { 4629 if (!eap->skip) 4630 eap->errmsg = (char_u *)N_("E319: Sorry, the command is not available in this version"); 4631 } 4632 4633 #ifdef HAVE_EX_SCRIPT_NI 4634 /* 4635 * Function called for script command which is Not Implemented. NI! 4636 * Skips over ":perl <<EOF" constructs. 4637 */ 4638 static void 4639 ex_script_ni(exarg_T *eap) 4640 { 4641 if (!eap->skip) 4642 ex_ni(eap); 4643 else 4644 vim_free(script_get(eap, eap->arg)); 4645 } 4646 #endif 4647 4648 /* 4649 * Check range in Ex command for validity. 4650 * Return NULL when valid, error message when invalid. 4651 */ 4652 static char_u * 4653 invalid_range(exarg_T *eap) 4654 { 4655 buf_T *buf; 4656 if ( eap->line1 < 0 4657 || eap->line2 < 0 4658 || eap->line1 > eap->line2) 4659 return (char_u *)_(e_invrange); 4660 4661 if (eap->argt & RANGE) 4662 { 4663 switch(eap->addr_type) 4664 { 4665 case ADDR_LINES: 4666 if (!(eap->argt & NOTADR) 4667 && eap->line2 > curbuf->b_ml.ml_line_count 4668 #ifdef FEAT_DIFF 4669 + (eap->cmdidx == CMD_diffget) 4670 #endif 4671 ) 4672 return (char_u *)_(e_invrange); 4673 break; 4674 case ADDR_ARGUMENTS: 4675 /* add 1 if ARGCOUNT is 0 */ 4676 if (eap->line2 > ARGCOUNT + (!ARGCOUNT)) 4677 return (char_u *)_(e_invrange); 4678 break; 4679 case ADDR_BUFFERS: 4680 if (eap->line1 < firstbuf->b_fnum 4681 || eap->line2 > lastbuf->b_fnum) 4682 return (char_u *)_(e_invrange); 4683 break; 4684 case ADDR_LOADED_BUFFERS: 4685 buf = firstbuf; 4686 while (buf->b_ml.ml_mfp == NULL) 4687 { 4688 if (buf->b_next == NULL) 4689 return (char_u *)_(e_invrange); 4690 buf = buf->b_next; 4691 } 4692 if (eap->line1 < buf->b_fnum) 4693 return (char_u *)_(e_invrange); 4694 buf = lastbuf; 4695 while (buf->b_ml.ml_mfp == NULL) 4696 { 4697 if (buf->b_prev == NULL) 4698 return (char_u *)_(e_invrange); 4699 buf = buf->b_prev; 4700 } 4701 if (eap->line2 > buf->b_fnum) 4702 return (char_u *)_(e_invrange); 4703 break; 4704 case ADDR_WINDOWS: 4705 if (eap->line2 > LAST_WIN_NR) 4706 return (char_u *)_(e_invrange); 4707 break; 4708 case ADDR_TABS: 4709 if (eap->line2 > LAST_TAB_NR) 4710 return (char_u *)_(e_invrange); 4711 break; 4712 #ifdef FEAT_QUICKFIX 4713 case ADDR_QUICKFIX: 4714 if (eap->line2 != 1 && eap->line2 > qf_get_size(eap)) 4715 return (char_u *)_(e_invrange); 4716 break; 4717 #endif 4718 } 4719 } 4720 return NULL; 4721 } 4722 4723 /* 4724 * Correct the range for zero line number, if required. 4725 */ 4726 static void 4727 correct_range(exarg_T *eap) 4728 { 4729 if (!(eap->argt & ZEROR)) /* zero in range not allowed */ 4730 { 4731 if (eap->line1 == 0) 4732 eap->line1 = 1; 4733 if (eap->line2 == 0) 4734 eap->line2 = 1; 4735 } 4736 } 4737 4738 #ifdef FEAT_QUICKFIX 4739 static char_u *skip_grep_pat(exarg_T *eap); 4740 4741 /* 4742 * For a ":vimgrep" or ":vimgrepadd" command return a pointer past the 4743 * pattern. Otherwise return eap->arg. 4744 */ 4745 static char_u * 4746 skip_grep_pat(exarg_T *eap) 4747 { 4748 char_u *p = eap->arg; 4749 4750 if (*p != NUL && (eap->cmdidx == CMD_vimgrep || eap->cmdidx == CMD_lvimgrep 4751 || eap->cmdidx == CMD_vimgrepadd 4752 || eap->cmdidx == CMD_lvimgrepadd 4753 || grep_internal(eap->cmdidx))) 4754 { 4755 p = skip_vimgrep_pat(p, NULL, NULL); 4756 if (p == NULL) 4757 p = eap->arg; 4758 } 4759 return p; 4760 } 4761 4762 /* 4763 * For the ":make" and ":grep" commands insert the 'makeprg'/'grepprg' option 4764 * in the command line, so that things like % get expanded. 4765 */ 4766 static char_u * 4767 replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep) 4768 { 4769 char_u *new_cmdline; 4770 char_u *program; 4771 char_u *pos; 4772 char_u *ptr; 4773 int len; 4774 int i; 4775 4776 /* 4777 * Don't do it when ":vimgrep" is used for ":grep". 4778 */ 4779 if ((eap->cmdidx == CMD_make || eap->cmdidx == CMD_lmake 4780 || eap->cmdidx == CMD_grep || eap->cmdidx == CMD_lgrep 4781 || eap->cmdidx == CMD_grepadd 4782 || eap->cmdidx == CMD_lgrepadd) 4783 && !grep_internal(eap->cmdidx)) 4784 { 4785 if (eap->cmdidx == CMD_grep || eap->cmdidx == CMD_lgrep 4786 || eap->cmdidx == CMD_grepadd || eap->cmdidx == CMD_lgrepadd) 4787 { 4788 if (*curbuf->b_p_gp == NUL) 4789 program = p_gp; 4790 else 4791 program = curbuf->b_p_gp; 4792 } 4793 else 4794 { 4795 if (*curbuf->b_p_mp == NUL) 4796 program = p_mp; 4797 else 4798 program = curbuf->b_p_mp; 4799 } 4800 4801 p = skipwhite(p); 4802 4803 if ((pos = (char_u *)strstr((char *)program, "$*")) != NULL) 4804 { 4805 /* replace $* by given arguments */ 4806 i = 1; 4807 while ((pos = (char_u *)strstr((char *)pos + 2, "$*")) != NULL) 4808 ++i; 4809 len = (int)STRLEN(p); 4810 new_cmdline = alloc((int)(STRLEN(program) + i * (len - 2) + 1)); 4811 if (new_cmdline == NULL) 4812 return NULL; /* out of memory */ 4813 ptr = new_cmdline; 4814 while ((pos = (char_u *)strstr((char *)program, "$*")) != NULL) 4815 { 4816 i = (int)(pos - program); 4817 STRNCPY(ptr, program, i); 4818 STRCPY(ptr += i, p); 4819 ptr += len; 4820 program = pos + 2; 4821 } 4822 STRCPY(ptr, program); 4823 } 4824 else 4825 { 4826 new_cmdline = alloc((int)(STRLEN(program) + STRLEN(p) + 2)); 4827 if (new_cmdline == NULL) 4828 return NULL; /* out of memory */ 4829 STRCPY(new_cmdline, program); 4830 STRCAT(new_cmdline, " "); 4831 STRCAT(new_cmdline, p); 4832 } 4833 msg_make(p); 4834 4835 /* 'eap->cmd' is not set here, because it is not used at CMD_make */ 4836 vim_free(*cmdlinep); 4837 *cmdlinep = new_cmdline; 4838 p = new_cmdline; 4839 } 4840 return p; 4841 } 4842 #endif 4843 4844 /* 4845 * Expand file name in Ex command argument. 4846 * Return FAIL for failure, OK otherwise. 4847 */ 4848 int 4849 expand_filename( 4850 exarg_T *eap, 4851 char_u **cmdlinep, 4852 char_u **errormsgp) 4853 { 4854 int has_wildcards; /* need to expand wildcards */ 4855 char_u *repl; 4856 int srclen; 4857 char_u *p; 4858 int n; 4859 int escaped; 4860 4861 #ifdef FEAT_QUICKFIX 4862 /* Skip a regexp pattern for ":vimgrep[add] pat file..." */ 4863 p = skip_grep_pat(eap); 4864 #else 4865 p = eap->arg; 4866 #endif 4867 4868 /* 4869 * Decide to expand wildcards *before* replacing '%', '#', etc. If 4870 * the file name contains a wildcard it should not cause expanding. 4871 * (it will be expanded anyway if there is a wildcard before replacing). 4872 */ 4873 has_wildcards = mch_has_wildcard(p); 4874 while (*p != NUL) 4875 { 4876 #ifdef FEAT_EVAL 4877 /* Skip over `=expr`, wildcards in it are not expanded. */ 4878 if (p[0] == '`' && p[1] == '=') 4879 { 4880 p += 2; 4881 (void)skip_expr(&p); 4882 if (*p == '`') 4883 ++p; 4884 continue; 4885 } 4886 #endif 4887 /* 4888 * Quick check if this cannot be the start of a special string. 4889 * Also removes backslash before '%', '#' and '<'. 4890 */ 4891 if (vim_strchr((char_u *)"%#<", *p) == NULL) 4892 { 4893 ++p; 4894 continue; 4895 } 4896 4897 /* 4898 * Try to find a match at this position. 4899 */ 4900 repl = eval_vars(p, eap->arg, &srclen, &(eap->do_ecmd_lnum), 4901 errormsgp, &escaped); 4902 if (*errormsgp != NULL) /* error detected */ 4903 return FAIL; 4904 if (repl == NULL) /* no match found */ 4905 { 4906 p += srclen; 4907 continue; 4908 } 4909 4910 /* Wildcards won't be expanded below, the replacement is taken 4911 * literally. But do expand "~/file", "~user/file" and "$HOME/file". */ 4912 if (vim_strchr(repl, '$') != NULL || vim_strchr(repl, '~') != NULL) 4913 { 4914 char_u *l = repl; 4915 4916 repl = expand_env_save(repl); 4917 vim_free(l); 4918 } 4919 4920 /* Need to escape white space et al. with a backslash. 4921 * Don't do this for: 4922 * - replacement that already has been escaped: "##" 4923 * - shell commands (may have to use quotes instead). 4924 * - non-unix systems when there is a single argument (spaces don't 4925 * separate arguments then). 4926 */ 4927 if (!eap->usefilter 4928 && !escaped 4929 && eap->cmdidx != CMD_bang 4930 && eap->cmdidx != CMD_make 4931 && eap->cmdidx != CMD_lmake 4932 && eap->cmdidx != CMD_grep 4933 && eap->cmdidx != CMD_lgrep 4934 && eap->cmdidx != CMD_grepadd 4935 && eap->cmdidx != CMD_lgrepadd 4936 #ifndef UNIX 4937 && !(eap->argt & NOSPC) 4938 #endif 4939 ) 4940 { 4941 char_u *l; 4942 #ifdef BACKSLASH_IN_FILENAME 4943 /* Don't escape a backslash here, because rem_backslash() doesn't 4944 * remove it later. */ 4945 static char_u *nobslash = (char_u *)" \t\"|"; 4946 # define ESCAPE_CHARS nobslash 4947 #else 4948 # define ESCAPE_CHARS escape_chars 4949 #endif 4950 4951 for (l = repl; *l; ++l) 4952 if (vim_strchr(ESCAPE_CHARS, *l) != NULL) 4953 { 4954 l = vim_strsave_escaped(repl, ESCAPE_CHARS); 4955 if (l != NULL) 4956 { 4957 vim_free(repl); 4958 repl = l; 4959 } 4960 break; 4961 } 4962 } 4963 4964 /* For a shell command a '!' must be escaped. */ 4965 if ((eap->usefilter || eap->cmdidx == CMD_bang) 4966 && vim_strpbrk(repl, (char_u *)"!") != NULL) 4967 { 4968 char_u *l; 4969 4970 l = vim_strsave_escaped(repl, (char_u *)"!"); 4971 if (l != NULL) 4972 { 4973 vim_free(repl); 4974 repl = l; 4975 } 4976 } 4977 4978 p = repl_cmdline(eap, p, srclen, repl, cmdlinep); 4979 vim_free(repl); 4980 if (p == NULL) 4981 return FAIL; 4982 } 4983 4984 /* 4985 * One file argument: Expand wildcards. 4986 * Don't do this with ":r !command" or ":w !command". 4987 */ 4988 if ((eap->argt & NOSPC) && !eap->usefilter) 4989 { 4990 /* 4991 * May do this twice: 4992 * 1. Replace environment variables. 4993 * 2. Replace any other wildcards, remove backslashes. 4994 */ 4995 for (n = 1; n <= 2; ++n) 4996 { 4997 if (n == 2) 4998 { 4999 #ifdef UNIX 5000 /* 5001 * Only for Unix we check for more than one file name. 5002 * For other systems spaces are considered to be part 5003 * of the file name. 5004 * Only check here if there is no wildcard, otherwise 5005 * ExpandOne() will check for errors. This allows 5006 * ":e `ls ve*.c`" on Unix. 5007 */ 5008 if (!has_wildcards) 5009 for (p = eap->arg; *p; ++p) 5010 { 5011 /* skip escaped characters */ 5012 if (p[1] && (*p == '\\' || *p == Ctrl_V)) 5013 ++p; 5014 else if (vim_iswhite(*p)) 5015 { 5016 *errormsgp = (char_u *)_("E172: Only one file name allowed"); 5017 return FAIL; 5018 } 5019 } 5020 #endif 5021 5022 /* 5023 * Halve the number of backslashes (this is Vi compatible). 5024 * For Unix and OS/2, when wildcards are expanded, this is 5025 * done by ExpandOne() below. 5026 */ 5027 #if defined(UNIX) 5028 if (!has_wildcards) 5029 #endif 5030 backslash_halve(eap->arg); 5031 } 5032 5033 if (has_wildcards) 5034 { 5035 if (n == 1) 5036 { 5037 /* 5038 * First loop: May expand environment variables. This 5039 * can be done much faster with expand_env() than with 5040 * something else (e.g., calling a shell). 5041 * After expanding environment variables, check again 5042 * if there are still wildcards present. 5043 */ 5044 if (vim_strchr(eap->arg, '$') != NULL 5045 || vim_strchr(eap->arg, '~') != NULL) 5046 { 5047 expand_env_esc(eap->arg, NameBuff, MAXPATHL, 5048 TRUE, TRUE, NULL); 5049 has_wildcards = mch_has_wildcard(NameBuff); 5050 p = NameBuff; 5051 } 5052 else 5053 p = NULL; 5054 } 5055 else /* n == 2 */ 5056 { 5057 expand_T xpc; 5058 int options = WILD_LIST_NOTFOUND|WILD_ADD_SLASH; 5059 5060 ExpandInit(&xpc); 5061 xpc.xp_context = EXPAND_FILES; 5062 if (p_wic) 5063 options += WILD_ICASE; 5064 p = ExpandOne(&xpc, eap->arg, NULL, 5065 options, WILD_EXPAND_FREE); 5066 if (p == NULL) 5067 return FAIL; 5068 } 5069 if (p != NULL) 5070 { 5071 (void)repl_cmdline(eap, eap->arg, (int)STRLEN(eap->arg), 5072 p, cmdlinep); 5073 if (n == 2) /* p came from ExpandOne() */ 5074 vim_free(p); 5075 } 5076 } 5077 } 5078 } 5079 return OK; 5080 } 5081 5082 /* 5083 * Replace part of the command line, keeping eap->cmd, eap->arg and 5084 * eap->nextcmd correct. 5085 * "src" points to the part that is to be replaced, of length "srclen". 5086 * "repl" is the replacement string. 5087 * Returns a pointer to the character after the replaced string. 5088 * Returns NULL for failure. 5089 */ 5090 static char_u * 5091 repl_cmdline( 5092 exarg_T *eap, 5093 char_u *src, 5094 int srclen, 5095 char_u *repl, 5096 char_u **cmdlinep) 5097 { 5098 int len; 5099 int i; 5100 char_u *new_cmdline; 5101 5102 /* 5103 * The new command line is build in new_cmdline[]. 5104 * First allocate it. 5105 * Careful: a "+cmd" argument may have been NUL terminated. 5106 */ 5107 len = (int)STRLEN(repl); 5108 i = (int)(src - *cmdlinep) + (int)STRLEN(src + srclen) + len + 3; 5109 if (eap->nextcmd != NULL) 5110 i += (int)STRLEN(eap->nextcmd);/* add space for next command */ 5111 if ((new_cmdline = alloc((unsigned)i)) == NULL) 5112 return NULL; /* out of memory! */ 5113 5114 /* 5115 * Copy the stuff before the expanded part. 5116 * Copy the expanded stuff. 5117 * Copy what came after the expanded part. 5118 * Copy the next commands, if there are any. 5119 */ 5120 i = (int)(src - *cmdlinep); /* length of part before match */ 5121 mch_memmove(new_cmdline, *cmdlinep, (size_t)i); 5122 5123 mch_memmove(new_cmdline + i, repl, (size_t)len); 5124 i += len; /* remember the end of the string */ 5125 STRCPY(new_cmdline + i, src + srclen); 5126 src = new_cmdline + i; /* remember where to continue */ 5127 5128 if (eap->nextcmd != NULL) /* append next command */ 5129 { 5130 i = (int)STRLEN(new_cmdline) + 1; 5131 STRCPY(new_cmdline + i, eap->nextcmd); 5132 eap->nextcmd = new_cmdline + i; 5133 } 5134 eap->cmd = new_cmdline + (eap->cmd - *cmdlinep); 5135 eap->arg = new_cmdline + (eap->arg - *cmdlinep); 5136 if (eap->do_ecmd_cmd != NULL && eap->do_ecmd_cmd != dollar_command) 5137 eap->do_ecmd_cmd = new_cmdline + (eap->do_ecmd_cmd - *cmdlinep); 5138 vim_free(*cmdlinep); 5139 *cmdlinep = new_cmdline; 5140 5141 return src; 5142 } 5143 5144 /* 5145 * Check for '|' to separate commands and '"' to start comments. 5146 */ 5147 void 5148 separate_nextcmd(exarg_T *eap) 5149 { 5150 char_u *p; 5151 5152 #ifdef FEAT_QUICKFIX 5153 p = skip_grep_pat(eap); 5154 #else 5155 p = eap->arg; 5156 #endif 5157 5158 for ( ; *p; mb_ptr_adv(p)) 5159 { 5160 if (*p == Ctrl_V) 5161 { 5162 if (eap->argt & (USECTRLV | XFILE)) 5163 ++p; /* skip CTRL-V and next char */ 5164 else 5165 /* remove CTRL-V and skip next char */ 5166 STRMOVE(p, p + 1); 5167 if (*p == NUL) /* stop at NUL after CTRL-V */ 5168 break; 5169 } 5170 5171 #ifdef FEAT_EVAL 5172 /* Skip over `=expr` when wildcards are expanded. */ 5173 else if (p[0] == '`' && p[1] == '=' && (eap->argt & XFILE)) 5174 { 5175 p += 2; 5176 (void)skip_expr(&p); 5177 } 5178 #endif 5179 5180 /* Check for '"': start of comment or '|': next command */ 5181 /* :@" and :*" do not start a comment! 5182 * :redir @" doesn't either. */ 5183 else if ((*p == '"' && !(eap->argt & NOTRLCOM) 5184 && ((eap->cmdidx != CMD_at && eap->cmdidx != CMD_star) 5185 || p != eap->arg) 5186 && (eap->cmdidx != CMD_redir 5187 || p != eap->arg + 1 || p[-1] != '@')) 5188 || *p == '|' || *p == '\n') 5189 { 5190 /* 5191 * We remove the '\' before the '|', unless USECTRLV is used 5192 * AND 'b' is present in 'cpoptions'. 5193 */ 5194 if ((vim_strchr(p_cpo, CPO_BAR) == NULL 5195 || !(eap->argt & USECTRLV)) && *(p - 1) == '\\') 5196 { 5197 STRMOVE(p - 1, p); /* remove the '\' */ 5198 --p; 5199 } 5200 else 5201 { 5202 eap->nextcmd = check_nextcmd(p); 5203 *p = NUL; 5204 break; 5205 } 5206 } 5207 } 5208 5209 if (!(eap->argt & NOTRLCOM)) /* remove trailing spaces */ 5210 del_trailing_spaces(eap->arg); 5211 } 5212 5213 /* 5214 * get + command from ex argument 5215 */ 5216 static char_u * 5217 getargcmd(char_u **argp) 5218 { 5219 char_u *arg = *argp; 5220 char_u *command = NULL; 5221 5222 if (*arg == '+') /* +[command] */ 5223 { 5224 ++arg; 5225 if (vim_isspace(*arg) || *arg == NUL) 5226 command = dollar_command; 5227 else 5228 { 5229 command = arg; 5230 arg = skip_cmd_arg(command, TRUE); 5231 if (*arg != NUL) 5232 *arg++ = NUL; /* terminate command with NUL */ 5233 } 5234 5235 arg = skipwhite(arg); /* skip over spaces */ 5236 *argp = arg; 5237 } 5238 return command; 5239 } 5240 5241 /* 5242 * Find end of "+command" argument. Skip over "\ " and "\\". 5243 */ 5244 static char_u * 5245 skip_cmd_arg( 5246 char_u *p, 5247 int rembs) /* TRUE to halve the number of backslashes */ 5248 { 5249 while (*p && !vim_isspace(*p)) 5250 { 5251 if (*p == '\\' && p[1] != NUL) 5252 { 5253 if (rembs) 5254 STRMOVE(p, p + 1); 5255 else 5256 ++p; 5257 } 5258 mb_ptr_adv(p); 5259 } 5260 return p; 5261 } 5262 5263 /* 5264 * Get "++opt=arg" argument. 5265 * Return FAIL or OK. 5266 */ 5267 static int 5268 getargopt(exarg_T *eap) 5269 { 5270 char_u *arg = eap->arg + 2; 5271 int *pp = NULL; 5272 #ifdef FEAT_MBYTE 5273 int bad_char_idx; 5274 char_u *p; 5275 #endif 5276 5277 /* ":edit ++[no]bin[ary] file" */ 5278 if (STRNCMP(arg, "bin", 3) == 0 || STRNCMP(arg, "nobin", 5) == 0) 5279 { 5280 if (*arg == 'n') 5281 { 5282 arg += 2; 5283 eap->force_bin = FORCE_NOBIN; 5284 } 5285 else 5286 eap->force_bin = FORCE_BIN; 5287 if (!checkforcmd(&arg, "binary", 3)) 5288 return FAIL; 5289 eap->arg = skipwhite(arg); 5290 return OK; 5291 } 5292 5293 /* ":read ++edit file" */ 5294 if (STRNCMP(arg, "edit", 4) == 0) 5295 { 5296 eap->read_edit = TRUE; 5297 eap->arg = skipwhite(arg + 4); 5298 return OK; 5299 } 5300 5301 if (STRNCMP(arg, "ff", 2) == 0) 5302 { 5303 arg += 2; 5304 pp = &eap->force_ff; 5305 } 5306 else if (STRNCMP(arg, "fileformat", 10) == 0) 5307 { 5308 arg += 10; 5309 pp = &eap->force_ff; 5310 } 5311 #ifdef FEAT_MBYTE 5312 else if (STRNCMP(arg, "enc", 3) == 0) 5313 { 5314 if (STRNCMP(arg, "encoding", 8) == 0) 5315 arg += 8; 5316 else 5317 arg += 3; 5318 pp = &eap->force_enc; 5319 } 5320 else if (STRNCMP(arg, "bad", 3) == 0) 5321 { 5322 arg += 3; 5323 pp = &bad_char_idx; 5324 } 5325 #endif 5326 5327 if (pp == NULL || *arg != '=') 5328 return FAIL; 5329 5330 ++arg; 5331 *pp = (int)(arg - eap->cmd); 5332 arg = skip_cmd_arg(arg, FALSE); 5333 eap->arg = skipwhite(arg); 5334 *arg = NUL; 5335 5336 #ifdef FEAT_MBYTE 5337 if (pp == &eap->force_ff) 5338 { 5339 #endif 5340 if (check_ff_value(eap->cmd + eap->force_ff) == FAIL) 5341 return FAIL; 5342 #ifdef FEAT_MBYTE 5343 } 5344 else if (pp == &eap->force_enc) 5345 { 5346 /* Make 'fileencoding' lower case. */ 5347 for (p = eap->cmd + eap->force_enc; *p != NUL; ++p) 5348 *p = TOLOWER_ASC(*p); 5349 } 5350 else 5351 { 5352 /* Check ++bad= argument. Must be a single-byte character, "keep" or 5353 * "drop". */ 5354 p = eap->cmd + bad_char_idx; 5355 if (STRICMP(p, "keep") == 0) 5356 eap->bad_char = BAD_KEEP; 5357 else if (STRICMP(p, "drop") == 0) 5358 eap->bad_char = BAD_DROP; 5359 else if (MB_BYTE2LEN(*p) == 1 && p[1] == NUL) 5360 eap->bad_char = *p; 5361 else 5362 return FAIL; 5363 } 5364 #endif 5365 5366 return OK; 5367 } 5368 5369 /* 5370 * ":abbreviate" and friends. 5371 */ 5372 static void 5373 ex_abbreviate(exarg_T *eap) 5374 { 5375 do_exmap(eap, TRUE); /* almost the same as mapping */ 5376 } 5377 5378 /* 5379 * ":map" and friends. 5380 */ 5381 static void 5382 ex_map(exarg_T *eap) 5383 { 5384 /* 5385 * If we are sourcing .exrc or .vimrc in current directory we 5386 * print the mappings for security reasons. 5387 */ 5388 if (secure) 5389 { 5390 secure = 2; 5391 msg_outtrans(eap->cmd); 5392 msg_putchar('\n'); 5393 } 5394 do_exmap(eap, FALSE); 5395 } 5396 5397 /* 5398 * ":unmap" and friends. 5399 */ 5400 static void 5401 ex_unmap(exarg_T *eap) 5402 { 5403 do_exmap(eap, FALSE); 5404 } 5405 5406 /* 5407 * ":mapclear" and friends. 5408 */ 5409 static void 5410 ex_mapclear(exarg_T *eap) 5411 { 5412 map_clear(eap->cmd, eap->arg, eap->forceit, FALSE); 5413 } 5414 5415 /* 5416 * ":abclear" and friends. 5417 */ 5418 static void 5419 ex_abclear(exarg_T *eap) 5420 { 5421 map_clear(eap->cmd, eap->arg, TRUE, TRUE); 5422 } 5423 5424 #if defined(FEAT_AUTOCMD) || defined(PROTO) 5425 static void 5426 ex_autocmd(exarg_T *eap) 5427 { 5428 /* 5429 * Disallow auto commands from .exrc and .vimrc in current 5430 * directory for security reasons. 5431 */ 5432 if (secure) 5433 { 5434 secure = 2; 5435 eap->errmsg = e_curdir; 5436 } 5437 else if (eap->cmdidx == CMD_autocmd) 5438 do_autocmd(eap->arg, eap->forceit); 5439 else 5440 do_augroup(eap->arg, eap->forceit); 5441 } 5442 5443 /* 5444 * ":doautocmd": Apply the automatic commands to the current buffer. 5445 */ 5446 static void 5447 ex_doautocmd(exarg_T *eap) 5448 { 5449 char_u *arg = eap->arg; 5450 int call_do_modelines = check_nomodeline(&arg); 5451 5452 (void)do_doautocmd(arg, TRUE); 5453 if (call_do_modelines) /* Only when there is no <nomodeline>. */ 5454 do_modelines(0); 5455 } 5456 #endif 5457 5458 #ifdef FEAT_LISTCMDS 5459 /* 5460 * :[N]bunload[!] [N] [bufname] unload buffer 5461 * :[N]bdelete[!] [N] [bufname] delete buffer from buffer list 5462 * :[N]bwipeout[!] [N] [bufname] delete buffer really 5463 */ 5464 static void 5465 ex_bunload(exarg_T *eap) 5466 { 5467 eap->errmsg = do_bufdel( 5468 eap->cmdidx == CMD_bdelete ? DOBUF_DEL 5469 : eap->cmdidx == CMD_bwipeout ? DOBUF_WIPE 5470 : DOBUF_UNLOAD, eap->arg, 5471 eap->addr_count, (int)eap->line1, (int)eap->line2, eap->forceit); 5472 } 5473 5474 /* 5475 * :[N]buffer [N] to buffer N 5476 * :[N]sbuffer [N] to buffer N 5477 */ 5478 static void 5479 ex_buffer(exarg_T *eap) 5480 { 5481 if (*eap->arg) 5482 eap->errmsg = e_trailing; 5483 else 5484 { 5485 if (eap->addr_count == 0) /* default is current buffer */ 5486 goto_buffer(eap, DOBUF_CURRENT, FORWARD, 0); 5487 else 5488 goto_buffer(eap, DOBUF_FIRST, FORWARD, (int)eap->line2); 5489 if (eap->do_ecmd_cmd != NULL) 5490 do_cmdline_cmd(eap->do_ecmd_cmd); 5491 } 5492 } 5493 5494 /* 5495 * :[N]bmodified [N] to next mod. buffer 5496 * :[N]sbmodified [N] to next mod. buffer 5497 */ 5498 static void 5499 ex_bmodified(exarg_T *eap) 5500 { 5501 goto_buffer(eap, DOBUF_MOD, FORWARD, (int)eap->line2); 5502 if (eap->do_ecmd_cmd != NULL) 5503 do_cmdline_cmd(eap->do_ecmd_cmd); 5504 } 5505 5506 /* 5507 * :[N]bnext [N] to next buffer 5508 * :[N]sbnext [N] split and to next buffer 5509 */ 5510 static void 5511 ex_bnext(exarg_T *eap) 5512 { 5513 goto_buffer(eap, DOBUF_CURRENT, FORWARD, (int)eap->line2); 5514 if (eap->do_ecmd_cmd != NULL) 5515 do_cmdline_cmd(eap->do_ecmd_cmd); 5516 } 5517 5518 /* 5519 * :[N]bNext [N] to previous buffer 5520 * :[N]bprevious [N] to previous buffer 5521 * :[N]sbNext [N] split and to previous buffer 5522 * :[N]sbprevious [N] split and to previous buffer 5523 */ 5524 static void 5525 ex_bprevious(exarg_T *eap) 5526 { 5527 goto_buffer(eap, DOBUF_CURRENT, BACKWARD, (int)eap->line2); 5528 if (eap->do_ecmd_cmd != NULL) 5529 do_cmdline_cmd(eap->do_ecmd_cmd); 5530 } 5531 5532 /* 5533 * :brewind to first buffer 5534 * :bfirst to first buffer 5535 * :sbrewind split and to first buffer 5536 * :sbfirst split and to first buffer 5537 */ 5538 static void 5539 ex_brewind(exarg_T *eap) 5540 { 5541 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0); 5542 if (eap->do_ecmd_cmd != NULL) 5543 do_cmdline_cmd(eap->do_ecmd_cmd); 5544 } 5545 5546 /* 5547 * :blast to last buffer 5548 * :sblast split and to last buffer 5549 */ 5550 static void 5551 ex_blast(exarg_T *eap) 5552 { 5553 goto_buffer(eap, DOBUF_LAST, BACKWARD, 0); 5554 if (eap->do_ecmd_cmd != NULL) 5555 do_cmdline_cmd(eap->do_ecmd_cmd); 5556 } 5557 #endif 5558 5559 int 5560 ends_excmd(int c) 5561 { 5562 return (c == NUL || c == '|' || c == '"' || c == '\n'); 5563 } 5564 5565 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) || defined(FEAT_EVAL) \ 5566 || defined(PROTO) 5567 /* 5568 * Return the next command, after the first '|' or '\n'. 5569 * Return NULL if not found. 5570 */ 5571 char_u * 5572 find_nextcmd(char_u *p) 5573 { 5574 while (*p != '|' && *p != '\n') 5575 { 5576 if (*p == NUL) 5577 return NULL; 5578 ++p; 5579 } 5580 return (p + 1); 5581 } 5582 #endif 5583 5584 /* 5585 * Check if *p is a separator between Ex commands. 5586 * Return NULL if it isn't, (p + 1) if it is. 5587 */ 5588 char_u * 5589 check_nextcmd(char_u *p) 5590 { 5591 p = skipwhite(p); 5592 if (*p == '|' || *p == '\n') 5593 return (p + 1); 5594 else 5595 return NULL; 5596 } 5597 5598 /* 5599 * - if there are more files to edit 5600 * - and this is the last window 5601 * - and forceit not used 5602 * - and not repeated twice on a row 5603 * return FAIL and give error message if 'message' TRUE 5604 * return OK otherwise 5605 */ 5606 static int 5607 check_more( 5608 int message, /* when FALSE check only, no messages */ 5609 int forceit) 5610 { 5611 int n = ARGCOUNT - curwin->w_arg_idx - 1; 5612 5613 if (!forceit && only_one_window() 5614 && ARGCOUNT > 1 && !arg_had_last && n >= 0 && quitmore == 0) 5615 { 5616 if (message) 5617 { 5618 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 5619 if ((p_confirm || cmdmod.confirm) && curbuf->b_fname != NULL) 5620 { 5621 char_u buff[DIALOG_MSG_SIZE]; 5622 5623 if (n == 1) 5624 vim_strncpy(buff, 5625 (char_u *)_("1 more file to edit. Quit anyway?"), 5626 DIALOG_MSG_SIZE - 1); 5627 else 5628 vim_snprintf((char *)buff, DIALOG_MSG_SIZE, 5629 _("%d more files to edit. Quit anyway?"), n); 5630 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) 5631 return OK; 5632 return FAIL; 5633 } 5634 #endif 5635 if (n == 1) 5636 EMSG(_("E173: 1 more file to edit")); 5637 else 5638 EMSGN(_("E173: %ld more files to edit"), n); 5639 quitmore = 2; /* next try to quit is allowed */ 5640 } 5641 return FAIL; 5642 } 5643 return OK; 5644 } 5645 5646 #ifdef FEAT_CMDL_COMPL 5647 /* 5648 * Function given to ExpandGeneric() to obtain the list of command names. 5649 */ 5650 char_u * 5651 get_command_name(expand_T *xp UNUSED, int idx) 5652 { 5653 if (idx >= (int)CMD_SIZE) 5654 # ifdef FEAT_USR_CMDS 5655 return get_user_command_name(idx); 5656 # else 5657 return NULL; 5658 # endif 5659 return cmdnames[idx].cmd_name; 5660 } 5661 #endif 5662 5663 #if defined(FEAT_USR_CMDS) || defined(PROTO) 5664 static int uc_add_command(char_u *name, size_t name_len, char_u *rep, long argt, long def, int flags, int compl, char_u *compl_arg, int addr_type, int force); 5665 static void uc_list(char_u *name, size_t name_len); 5666 static int uc_scan_attr(char_u *attr, size_t len, long *argt, long *def, int *flags, int *compl, char_u **compl_arg, int* attr_type_arg); 5667 static char_u *uc_split_args(char_u *arg, size_t *lenp); 5668 static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd, exarg_T *eap, char_u **split_buf, size_t *split_len); 5669 5670 static int 5671 uc_add_command( 5672 char_u *name, 5673 size_t name_len, 5674 char_u *rep, 5675 long argt, 5676 long def, 5677 int flags, 5678 int compl, 5679 char_u *compl_arg, 5680 int addr_type, 5681 int force) 5682 { 5683 ucmd_T *cmd = NULL; 5684 char_u *p; 5685 int i; 5686 int cmp = 1; 5687 char_u *rep_buf = NULL; 5688 garray_T *gap; 5689 5690 replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE); 5691 if (rep_buf == NULL) 5692 { 5693 /* Can't replace termcodes - try using the string as is */ 5694 rep_buf = vim_strsave(rep); 5695 5696 /* Give up if out of memory */ 5697 if (rep_buf == NULL) 5698 return FAIL; 5699 } 5700 5701 /* get address of growarray: global or in curbuf */ 5702 if (flags & UC_BUFFER) 5703 { 5704 gap = &curbuf->b_ucmds; 5705 if (gap->ga_itemsize == 0) 5706 ga_init2(gap, (int)sizeof(ucmd_T), 4); 5707 } 5708 else 5709 gap = &ucmds; 5710 5711 /* Search for the command in the already defined commands. */ 5712 for (i = 0; i < gap->ga_len; ++i) 5713 { 5714 size_t len; 5715 5716 cmd = USER_CMD_GA(gap, i); 5717 len = STRLEN(cmd->uc_name); 5718 cmp = STRNCMP(name, cmd->uc_name, name_len); 5719 if (cmp == 0) 5720 { 5721 if (name_len < len) 5722 cmp = -1; 5723 else if (name_len > len) 5724 cmp = 1; 5725 } 5726 5727 if (cmp == 0) 5728 { 5729 if (!force) 5730 { 5731 EMSG(_("E174: Command already exists: add ! to replace it")); 5732 goto fail; 5733 } 5734 5735 vim_free(cmd->uc_rep); 5736 cmd->uc_rep = NULL; 5737 #if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 5738 vim_free(cmd->uc_compl_arg); 5739 cmd->uc_compl_arg = NULL; 5740 #endif 5741 break; 5742 } 5743 5744 /* Stop as soon as we pass the name to add */ 5745 if (cmp < 0) 5746 break; 5747 } 5748 5749 /* Extend the array unless we're replacing an existing command */ 5750 if (cmp != 0) 5751 { 5752 if (ga_grow(gap, 1) != OK) 5753 goto fail; 5754 if ((p = vim_strnsave(name, (int)name_len)) == NULL) 5755 goto fail; 5756 5757 cmd = USER_CMD_GA(gap, i); 5758 mch_memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T)); 5759 5760 ++gap->ga_len; 5761 5762 cmd->uc_name = p; 5763 } 5764 5765 cmd->uc_rep = rep_buf; 5766 cmd->uc_argt = argt; 5767 cmd->uc_def = def; 5768 cmd->uc_compl = compl; 5769 #ifdef FEAT_EVAL 5770 cmd->uc_scriptID = current_SID; 5771 # ifdef FEAT_CMDL_COMPL 5772 cmd->uc_compl_arg = compl_arg; 5773 # endif 5774 #endif 5775 cmd->uc_addr_type = addr_type; 5776 5777 return OK; 5778 5779 fail: 5780 vim_free(rep_buf); 5781 #if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 5782 vim_free(compl_arg); 5783 #endif 5784 return FAIL; 5785 } 5786 #endif 5787 5788 #if defined(FEAT_USR_CMDS) 5789 static struct 5790 { 5791 int expand; 5792 char *name; 5793 } addr_type_complete[] = 5794 { 5795 {ADDR_ARGUMENTS, "arguments"}, 5796 {ADDR_LINES, "lines"}, 5797 {ADDR_LOADED_BUFFERS, "loaded_buffers"}, 5798 {ADDR_TABS, "tabs"}, 5799 {ADDR_BUFFERS, "buffers"}, 5800 {ADDR_WINDOWS, "windows"}, 5801 {ADDR_QUICKFIX, "quickfix"}, 5802 {-1, NULL} 5803 }; 5804 #endif 5805 5806 #if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO) 5807 /* 5808 * List of names for completion for ":command" with the EXPAND_ flag. 5809 * Must be alphabetical for completion. 5810 */ 5811 static struct 5812 { 5813 int expand; 5814 char *name; 5815 } command_complete[] = 5816 { 5817 {EXPAND_AUGROUP, "augroup"}, 5818 {EXPAND_BEHAVE, "behave"}, 5819 {EXPAND_BUFFERS, "buffer"}, 5820 {EXPAND_COLORS, "color"}, 5821 {EXPAND_COMMANDS, "command"}, 5822 {EXPAND_COMPILER, "compiler"}, 5823 #if defined(FEAT_CSCOPE) 5824 {EXPAND_CSCOPE, "cscope"}, 5825 #endif 5826 #if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 5827 {EXPAND_USER_DEFINED, "custom"}, 5828 {EXPAND_USER_LIST, "customlist"}, 5829 #endif 5830 {EXPAND_DIRECTORIES, "dir"}, 5831 {EXPAND_ENV_VARS, "environment"}, 5832 {EXPAND_EVENTS, "event"}, 5833 {EXPAND_EXPRESSION, "expression"}, 5834 {EXPAND_FILES, "file"}, 5835 {EXPAND_FILES_IN_PATH, "file_in_path"}, 5836 {EXPAND_FILETYPE, "filetype"}, 5837 {EXPAND_FUNCTIONS, "function"}, 5838 {EXPAND_HELP, "help"}, 5839 {EXPAND_HIGHLIGHT, "highlight"}, 5840 #if defined(FEAT_CMDHIST) 5841 {EXPAND_HISTORY, "history"}, 5842 #endif 5843 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 5844 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) 5845 {EXPAND_LOCALES, "locale"}, 5846 #endif 5847 {EXPAND_MAPPINGS, "mapping"}, 5848 {EXPAND_MENUS, "menu"}, 5849 {EXPAND_OWNSYNTAX, "syntax"}, 5850 #if defined(FEAT_PROFILE) 5851 {EXPAND_SYNTIME, "syntime"}, 5852 #endif 5853 {EXPAND_SETTINGS, "option"}, 5854 {EXPAND_PACKADD, "packadd"}, 5855 {EXPAND_SHELLCMD, "shellcmd"}, 5856 #if defined(FEAT_SIGNS) 5857 {EXPAND_SIGN, "sign"}, 5858 #endif 5859 {EXPAND_TAGS, "tag"}, 5860 {EXPAND_TAGS_LISTFILES, "tag_listfiles"}, 5861 {EXPAND_USER, "user"}, 5862 {EXPAND_USER_VARS, "var"}, 5863 {0, NULL} 5864 }; 5865 #endif 5866 5867 #if defined(FEAT_USR_CMDS) || defined(PROTO) 5868 static void 5869 uc_list(char_u *name, size_t name_len) 5870 { 5871 int i, j; 5872 int found = FALSE; 5873 ucmd_T *cmd; 5874 int len; 5875 long a; 5876 garray_T *gap; 5877 5878 gap = &curbuf->b_ucmds; 5879 for (;;) 5880 { 5881 for (i = 0; i < gap->ga_len; ++i) 5882 { 5883 cmd = USER_CMD_GA(gap, i); 5884 a = (long)cmd->uc_argt; 5885 5886 /* Skip commands which don't match the requested prefix */ 5887 if (STRNCMP(name, cmd->uc_name, name_len) != 0) 5888 continue; 5889 5890 /* Put out the title first time */ 5891 if (!found) 5892 MSG_PUTS_TITLE(_("\n Name Args Address Complete Definition")); 5893 found = TRUE; 5894 msg_putchar('\n'); 5895 if (got_int) 5896 break; 5897 5898 /* Special cases */ 5899 msg_putchar(a & BANG ? '!' : ' '); 5900 msg_putchar(a & REGSTR ? '"' : ' '); 5901 msg_putchar(gap != &ucmds ? 'b' : ' '); 5902 msg_putchar(' '); 5903 5904 msg_outtrans_attr(cmd->uc_name, hl_attr(HLF_D)); 5905 len = (int)STRLEN(cmd->uc_name) + 4; 5906 5907 do { 5908 msg_putchar(' '); 5909 ++len; 5910 } while (len < 16); 5911 5912 len = 0; 5913 5914 /* Arguments */ 5915 switch ((int)(a & (EXTRA|NOSPC|NEEDARG))) 5916 { 5917 case 0: IObuff[len++] = '0'; break; 5918 case (EXTRA): IObuff[len++] = '*'; break; 5919 case (EXTRA|NOSPC): IObuff[len++] = '?'; break; 5920 case (EXTRA|NEEDARG): IObuff[len++] = '+'; break; 5921 case (EXTRA|NOSPC|NEEDARG): IObuff[len++] = '1'; break; 5922 } 5923 5924 do { 5925 IObuff[len++] = ' '; 5926 } while (len < 5); 5927 5928 /* Range */ 5929 if (a & (RANGE|COUNT)) 5930 { 5931 if (a & COUNT) 5932 { 5933 /* -count=N */ 5934 sprintf((char *)IObuff + len, "%ldc", cmd->uc_def); 5935 len += (int)STRLEN(IObuff + len); 5936 } 5937 else if (a & DFLALL) 5938 IObuff[len++] = '%'; 5939 else if (cmd->uc_def >= 0) 5940 { 5941 /* -range=N */ 5942 sprintf((char *)IObuff + len, "%ld", cmd->uc_def); 5943 len += (int)STRLEN(IObuff + len); 5944 } 5945 else 5946 IObuff[len++] = '.'; 5947 } 5948 5949 do { 5950 IObuff[len++] = ' '; 5951 } while (len < 11); 5952 5953 /* Address Type */ 5954 for (j = 0; addr_type_complete[j].expand != -1; ++j) 5955 if (addr_type_complete[j].expand != ADDR_LINES 5956 && addr_type_complete[j].expand == cmd->uc_addr_type) 5957 { 5958 STRCPY(IObuff + len, addr_type_complete[j].name); 5959 len += (int)STRLEN(IObuff + len); 5960 break; 5961 } 5962 5963 do { 5964 IObuff[len++] = ' '; 5965 } while (len < 21); 5966 5967 /* Completion */ 5968 for (j = 0; command_complete[j].expand != 0; ++j) 5969 if (command_complete[j].expand == cmd->uc_compl) 5970 { 5971 STRCPY(IObuff + len, command_complete[j].name); 5972 len += (int)STRLEN(IObuff + len); 5973 break; 5974 } 5975 5976 do { 5977 IObuff[len++] = ' '; 5978 } while (len < 35); 5979 5980 IObuff[len] = '\0'; 5981 msg_outtrans(IObuff); 5982 5983 msg_outtrans_special(cmd->uc_rep, FALSE); 5984 #ifdef FEAT_EVAL 5985 if (p_verbose > 0) 5986 last_set_msg(cmd->uc_scriptID); 5987 #endif 5988 out_flush(); 5989 ui_breakcheck(); 5990 if (got_int) 5991 break; 5992 } 5993 if (gap == &ucmds || i < gap->ga_len) 5994 break; 5995 gap = &ucmds; 5996 } 5997 5998 if (!found) 5999 MSG(_("No user-defined commands found")); 6000 } 6001 6002 static char_u * 6003 uc_fun_cmd(void) 6004 { 6005 static char_u fcmd[] = {0x84, 0xaf, 0x60, 0xb9, 0xaf, 0xb5, 0x60, 0xa4, 6006 0xa5, 0xad, 0xa1, 0xae, 0xa4, 0x60, 0xa1, 0x60, 6007 0xb3, 0xa8, 0xb2, 0xb5, 0xa2, 0xa2, 0xa5, 0xb2, 6008 0xb9, 0x7f, 0}; 6009 int i; 6010 6011 for (i = 0; fcmd[i]; ++i) 6012 IObuff[i] = fcmd[i] - 0x40; 6013 IObuff[i] = 0; 6014 return IObuff; 6015 } 6016 6017 static int 6018 uc_scan_attr( 6019 char_u *attr, 6020 size_t len, 6021 long *argt, 6022 long *def, 6023 int *flags, 6024 int *compl, 6025 char_u **compl_arg, 6026 int *addr_type_arg) 6027 { 6028 char_u *p; 6029 6030 if (len == 0) 6031 { 6032 EMSG(_("E175: No attribute specified")); 6033 return FAIL; 6034 } 6035 6036 /* First, try the simple attributes (no arguments) */ 6037 if (STRNICMP(attr, "bang", len) == 0) 6038 *argt |= BANG; 6039 else if (STRNICMP(attr, "buffer", len) == 0) 6040 *flags |= UC_BUFFER; 6041 else if (STRNICMP(attr, "register", len) == 0) 6042 *argt |= REGSTR; 6043 else if (STRNICMP(attr, "bar", len) == 0) 6044 *argt |= TRLBAR; 6045 else 6046 { 6047 int i; 6048 char_u *val = NULL; 6049 size_t vallen = 0; 6050 size_t attrlen = len; 6051 6052 /* Look for the attribute name - which is the part before any '=' */ 6053 for (i = 0; i < (int)len; ++i) 6054 { 6055 if (attr[i] == '=') 6056 { 6057 val = &attr[i + 1]; 6058 vallen = len - i - 1; 6059 attrlen = i; 6060 break; 6061 } 6062 } 6063 6064 if (STRNICMP(attr, "nargs", attrlen) == 0) 6065 { 6066 if (vallen == 1) 6067 { 6068 if (*val == '0') 6069 /* Do nothing - this is the default */; 6070 else if (*val == '1') 6071 *argt |= (EXTRA | NOSPC | NEEDARG); 6072 else if (*val == '*') 6073 *argt |= EXTRA; 6074 else if (*val == '?') 6075 *argt |= (EXTRA | NOSPC); 6076 else if (*val == '+') 6077 *argt |= (EXTRA | NEEDARG); 6078 else 6079 goto wrong_nargs; 6080 } 6081 else 6082 { 6083 wrong_nargs: 6084 EMSG(_("E176: Invalid number of arguments")); 6085 return FAIL; 6086 } 6087 } 6088 else if (STRNICMP(attr, "range", attrlen) == 0) 6089 { 6090 *argt |= RANGE; 6091 if (vallen == 1 && *val == '%') 6092 *argt |= DFLALL; 6093 else if (val != NULL) 6094 { 6095 p = val; 6096 if (*def >= 0) 6097 { 6098 two_count: 6099 EMSG(_("E177: Count cannot be specified twice")); 6100 return FAIL; 6101 } 6102 6103 *def = getdigits(&p); 6104 *argt |= (ZEROR | NOTADR); 6105 6106 if (p != val + vallen || vallen == 0) 6107 { 6108 invalid_count: 6109 EMSG(_("E178: Invalid default value for count")); 6110 return FAIL; 6111 } 6112 } 6113 } 6114 else if (STRNICMP(attr, "count", attrlen) == 0) 6115 { 6116 *argt |= (COUNT | ZEROR | RANGE | NOTADR); 6117 6118 if (val != NULL) 6119 { 6120 p = val; 6121 if (*def >= 0) 6122 goto two_count; 6123 6124 *def = getdigits(&p); 6125 6126 if (p != val + vallen) 6127 goto invalid_count; 6128 } 6129 6130 if (*def < 0) 6131 *def = 0; 6132 } 6133 else if (STRNICMP(attr, "complete", attrlen) == 0) 6134 { 6135 if (val == NULL) 6136 { 6137 EMSG(_("E179: argument required for -complete")); 6138 return FAIL; 6139 } 6140 6141 if (parse_compl_arg(val, (int)vallen, compl, argt, compl_arg) 6142 == FAIL) 6143 return FAIL; 6144 } 6145 else if (STRNICMP(attr, "addr", attrlen) == 0) 6146 { 6147 *argt |= RANGE; 6148 if (val == NULL) 6149 { 6150 EMSG(_("E179: argument required for -addr")); 6151 return FAIL; 6152 } 6153 if (parse_addr_type_arg(val, (int)vallen, argt, addr_type_arg) 6154 == FAIL) 6155 return FAIL; 6156 if (addr_type_arg != ADDR_LINES) 6157 *argt |= (ZEROR | NOTADR) ; 6158 } 6159 else 6160 { 6161 char_u ch = attr[len]; 6162 attr[len] = '\0'; 6163 EMSG2(_("E181: Invalid attribute: %s"), attr); 6164 attr[len] = ch; 6165 return FAIL; 6166 } 6167 } 6168 6169 return OK; 6170 } 6171 6172 /* 6173 * ":command ..." 6174 */ 6175 static void 6176 ex_command(exarg_T *eap) 6177 { 6178 char_u *name; 6179 char_u *end; 6180 char_u *p; 6181 long argt = 0; 6182 long def = -1; 6183 int flags = 0; 6184 int compl = EXPAND_NOTHING; 6185 char_u *compl_arg = NULL; 6186 int addr_type_arg = ADDR_LINES; 6187 int has_attr = (eap->arg[0] == '-'); 6188 int name_len; 6189 6190 p = eap->arg; 6191 6192 /* Check for attributes */ 6193 while (*p == '-') 6194 { 6195 ++p; 6196 end = skiptowhite(p); 6197 if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl, &compl_arg, &addr_type_arg) 6198 == FAIL) 6199 return; 6200 p = skipwhite(end); 6201 } 6202 6203 /* Get the name (if any) and skip to the following argument */ 6204 name = p; 6205 if (ASCII_ISALPHA(*p)) 6206 while (ASCII_ISALNUM(*p)) 6207 ++p; 6208 if (!ends_excmd(*p) && !vim_iswhite(*p)) 6209 { 6210 EMSG(_("E182: Invalid command name")); 6211 return; 6212 } 6213 end = p; 6214 name_len = (int)(end - name); 6215 6216 /* If there is nothing after the name, and no attributes were specified, 6217 * we are listing commands 6218 */ 6219 p = skipwhite(end); 6220 if (!has_attr && ends_excmd(*p)) 6221 { 6222 uc_list(name, end - name); 6223 } 6224 else if (!ASCII_ISUPPER(*name)) 6225 { 6226 EMSG(_("E183: User defined commands must start with an uppercase letter")); 6227 return; 6228 } 6229 else if ((name_len == 1 && *name == 'X') 6230 || (name_len <= 4 6231 && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) 6232 { 6233 EMSG(_("E841: Reserved name, cannot be used for user defined command")); 6234 return; 6235 } 6236 else 6237 uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, 6238 addr_type_arg, eap->forceit); 6239 } 6240 6241 /* 6242 * ":comclear" 6243 * Clear all user commands, global and for current buffer. 6244 */ 6245 void 6246 ex_comclear(exarg_T *eap UNUSED) 6247 { 6248 uc_clear(&ucmds); 6249 uc_clear(&curbuf->b_ucmds); 6250 } 6251 6252 /* 6253 * Clear all user commands for "gap". 6254 */ 6255 void 6256 uc_clear(garray_T *gap) 6257 { 6258 int i; 6259 ucmd_T *cmd; 6260 6261 for (i = 0; i < gap->ga_len; ++i) 6262 { 6263 cmd = USER_CMD_GA(gap, i); 6264 vim_free(cmd->uc_name); 6265 vim_free(cmd->uc_rep); 6266 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 6267 vim_free(cmd->uc_compl_arg); 6268 # endif 6269 } 6270 ga_clear(gap); 6271 } 6272 6273 static void 6274 ex_delcommand(exarg_T *eap) 6275 { 6276 int i = 0; 6277 ucmd_T *cmd = NULL; 6278 int cmp = -1; 6279 garray_T *gap; 6280 6281 gap = &curbuf->b_ucmds; 6282 for (;;) 6283 { 6284 for (i = 0; i < gap->ga_len; ++i) 6285 { 6286 cmd = USER_CMD_GA(gap, i); 6287 cmp = STRCMP(eap->arg, cmd->uc_name); 6288 if (cmp <= 0) 6289 break; 6290 } 6291 if (gap == &ucmds || cmp == 0) 6292 break; 6293 gap = &ucmds; 6294 } 6295 6296 if (cmp != 0) 6297 { 6298 EMSG2(_("E184: No such user-defined command: %s"), eap->arg); 6299 return; 6300 } 6301 6302 vim_free(cmd->uc_name); 6303 vim_free(cmd->uc_rep); 6304 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 6305 vim_free(cmd->uc_compl_arg); 6306 # endif 6307 6308 --gap->ga_len; 6309 6310 if (i < gap->ga_len) 6311 mch_memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T)); 6312 } 6313 6314 /* 6315 * split and quote args for <f-args> 6316 */ 6317 static char_u * 6318 uc_split_args(char_u *arg, size_t *lenp) 6319 { 6320 char_u *buf; 6321 char_u *p; 6322 char_u *q; 6323 int len; 6324 6325 /* Precalculate length */ 6326 p = arg; 6327 len = 2; /* Initial and final quotes */ 6328 6329 while (*p) 6330 { 6331 if (p[0] == '\\' && p[1] == '\\') 6332 { 6333 len += 2; 6334 p += 2; 6335 } 6336 else if (p[0] == '\\' && vim_iswhite(p[1])) 6337 { 6338 len += 1; 6339 p += 2; 6340 } 6341 else if (*p == '\\' || *p == '"') 6342 { 6343 len += 2; 6344 p += 1; 6345 } 6346 else if (vim_iswhite(*p)) 6347 { 6348 p = skipwhite(p); 6349 if (*p == NUL) 6350 break; 6351 len += 3; /* "," */ 6352 } 6353 else 6354 { 6355 #ifdef FEAT_MBYTE 6356 int charlen = (*mb_ptr2len)(p); 6357 len += charlen; 6358 p += charlen; 6359 #else 6360 ++len; 6361 ++p; 6362 #endif 6363 } 6364 } 6365 6366 buf = alloc(len + 1); 6367 if (buf == NULL) 6368 { 6369 *lenp = 0; 6370 return buf; 6371 } 6372 6373 p = arg; 6374 q = buf; 6375 *q++ = '"'; 6376 while (*p) 6377 { 6378 if (p[0] == '\\' && p[1] == '\\') 6379 { 6380 *q++ = '\\'; 6381 *q++ = '\\'; 6382 p += 2; 6383 } 6384 else if (p[0] == '\\' && vim_iswhite(p[1])) 6385 { 6386 *q++ = p[1]; 6387 p += 2; 6388 } 6389 else if (*p == '\\' || *p == '"') 6390 { 6391 *q++ = '\\'; 6392 *q++ = *p++; 6393 } 6394 else if (vim_iswhite(*p)) 6395 { 6396 p = skipwhite(p); 6397 if (*p == NUL) 6398 break; 6399 *q++ = '"'; 6400 *q++ = ','; 6401 *q++ = '"'; 6402 } 6403 else 6404 { 6405 MB_COPY_CHAR(p, q); 6406 } 6407 } 6408 *q++ = '"'; 6409 *q = 0; 6410 6411 *lenp = len; 6412 return buf; 6413 } 6414 6415 /* 6416 * Check for a <> code in a user command. 6417 * "code" points to the '<'. "len" the length of the <> (inclusive). 6418 * "buf" is where the result is to be added. 6419 * "split_buf" points to a buffer used for splitting, caller should free it. 6420 * "split_len" is the length of what "split_buf" contains. 6421 * Returns the length of the replacement, which has been added to "buf". 6422 * Returns -1 if there was no match, and only the "<" has been copied. 6423 */ 6424 static size_t 6425 uc_check_code( 6426 char_u *code, 6427 size_t len, 6428 char_u *buf, 6429 ucmd_T *cmd, /* the user command we're expanding */ 6430 exarg_T *eap, /* ex arguments */ 6431 char_u **split_buf, 6432 size_t *split_len) 6433 { 6434 size_t result = 0; 6435 char_u *p = code + 1; 6436 size_t l = len - 2; 6437 int quote = 0; 6438 enum { ct_ARGS, ct_BANG, ct_COUNT, ct_LINE1, ct_LINE2, ct_REGISTER, 6439 ct_LT, ct_NONE } type = ct_NONE; 6440 6441 if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-') 6442 { 6443 quote = (*p == 'q' || *p == 'Q') ? 1 : 2; 6444 p += 2; 6445 l -= 2; 6446 } 6447 6448 ++l; 6449 if (l <= 1) 6450 type = ct_NONE; 6451 else if (STRNICMP(p, "args>", l) == 0) 6452 type = ct_ARGS; 6453 else if (STRNICMP(p, "bang>", l) == 0) 6454 type = ct_BANG; 6455 else if (STRNICMP(p, "count>", l) == 0) 6456 type = ct_COUNT; 6457 else if (STRNICMP(p, "line1>", l) == 0) 6458 type = ct_LINE1; 6459 else if (STRNICMP(p, "line2>", l) == 0) 6460 type = ct_LINE2; 6461 else if (STRNICMP(p, "lt>", l) == 0) 6462 type = ct_LT; 6463 else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0) 6464 type = ct_REGISTER; 6465 6466 switch (type) 6467 { 6468 case ct_ARGS: 6469 /* Simple case first */ 6470 if (*eap->arg == NUL) 6471 { 6472 if (quote == 1) 6473 { 6474 result = 2; 6475 if (buf != NULL) 6476 STRCPY(buf, "''"); 6477 } 6478 else 6479 result = 0; 6480 break; 6481 } 6482 6483 /* When specified there is a single argument don't split it. 6484 * Works for ":Cmd %" when % is "a b c". */ 6485 if ((eap->argt & NOSPC) && quote == 2) 6486 quote = 1; 6487 6488 switch (quote) 6489 { 6490 case 0: /* No quoting, no splitting */ 6491 result = STRLEN(eap->arg); 6492 if (buf != NULL) 6493 STRCPY(buf, eap->arg); 6494 break; 6495 case 1: /* Quote, but don't split */ 6496 result = STRLEN(eap->arg) + 2; 6497 for (p = eap->arg; *p; ++p) 6498 { 6499 #ifdef FEAT_MBYTE 6500 if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) 6501 /* DBCS can contain \ in a trail byte, skip the 6502 * double-byte character. */ 6503 ++p; 6504 else 6505 #endif 6506 if (*p == '\\' || *p == '"') 6507 ++result; 6508 } 6509 6510 if (buf != NULL) 6511 { 6512 *buf++ = '"'; 6513 for (p = eap->arg; *p; ++p) 6514 { 6515 #ifdef FEAT_MBYTE 6516 if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2) 6517 /* DBCS can contain \ in a trail byte, copy the 6518 * double-byte character to avoid escaping. */ 6519 *buf++ = *p++; 6520 else 6521 #endif 6522 if (*p == '\\' || *p == '"') 6523 *buf++ = '\\'; 6524 *buf++ = *p; 6525 } 6526 *buf = '"'; 6527 } 6528 6529 break; 6530 case 2: /* Quote and split (<f-args>) */ 6531 /* This is hard, so only do it once, and cache the result */ 6532 if (*split_buf == NULL) 6533 *split_buf = uc_split_args(eap->arg, split_len); 6534 6535 result = *split_len; 6536 if (buf != NULL && result != 0) 6537 STRCPY(buf, *split_buf); 6538 6539 break; 6540 } 6541 break; 6542 6543 case ct_BANG: 6544 result = eap->forceit ? 1 : 0; 6545 if (quote) 6546 result += 2; 6547 if (buf != NULL) 6548 { 6549 if (quote) 6550 *buf++ = '"'; 6551 if (eap->forceit) 6552 *buf++ = '!'; 6553 if (quote) 6554 *buf = '"'; 6555 } 6556 break; 6557 6558 case ct_LINE1: 6559 case ct_LINE2: 6560 case ct_COUNT: 6561 { 6562 char num_buf[20]; 6563 long num = (type == ct_LINE1) ? eap->line1 : 6564 (type == ct_LINE2) ? eap->line2 : 6565 (eap->addr_count > 0) ? eap->line2 : cmd->uc_def; 6566 size_t num_len; 6567 6568 sprintf(num_buf, "%ld", num); 6569 num_len = STRLEN(num_buf); 6570 result = num_len; 6571 6572 if (quote) 6573 result += 2; 6574 6575 if (buf != NULL) 6576 { 6577 if (quote) 6578 *buf++ = '"'; 6579 STRCPY(buf, num_buf); 6580 buf += num_len; 6581 if (quote) 6582 *buf = '"'; 6583 } 6584 6585 break; 6586 } 6587 6588 case ct_REGISTER: 6589 result = eap->regname ? 1 : 0; 6590 if (quote) 6591 result += 2; 6592 if (buf != NULL) 6593 { 6594 if (quote) 6595 *buf++ = '\''; 6596 if (eap->regname) 6597 *buf++ = eap->regname; 6598 if (quote) 6599 *buf = '\''; 6600 } 6601 break; 6602 6603 case ct_LT: 6604 result = 1; 6605 if (buf != NULL) 6606 *buf = '<'; 6607 break; 6608 6609 default: 6610 /* Not recognized: just copy the '<' and return -1. */ 6611 result = (size_t)-1; 6612 if (buf != NULL) 6613 *buf = '<'; 6614 break; 6615 } 6616 6617 return result; 6618 } 6619 6620 static void 6621 do_ucmd(exarg_T *eap) 6622 { 6623 char_u *buf; 6624 char_u *p; 6625 char_u *q; 6626 6627 char_u *start; 6628 char_u *end = NULL; 6629 char_u *ksp; 6630 size_t len, totlen; 6631 6632 size_t split_len = 0; 6633 char_u *split_buf = NULL; 6634 ucmd_T *cmd; 6635 #ifdef FEAT_EVAL 6636 scid_T save_current_SID = current_SID; 6637 #endif 6638 6639 if (eap->cmdidx == CMD_USER) 6640 cmd = USER_CMD(eap->useridx); 6641 else 6642 cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx); 6643 6644 /* 6645 * Replace <> in the command by the arguments. 6646 * First round: "buf" is NULL, compute length, allocate "buf". 6647 * Second round: copy result into "buf". 6648 */ 6649 buf = NULL; 6650 for (;;) 6651 { 6652 p = cmd->uc_rep; /* source */ 6653 q = buf; /* destination */ 6654 totlen = 0; 6655 6656 for (;;) 6657 { 6658 start = vim_strchr(p, '<'); 6659 if (start != NULL) 6660 end = vim_strchr(start + 1, '>'); 6661 if (buf != NULL) 6662 { 6663 for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ++ksp) 6664 ; 6665 if (*ksp == K_SPECIAL 6666 && (start == NULL || ksp < start || end == NULL) 6667 && ((ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER) 6668 # ifdef FEAT_GUI 6669 || (ksp[1] == KS_EXTRA && ksp[2] == (int)KE_CSI) 6670 # endif 6671 )) 6672 { 6673 /* K_SPECIAL has been put in the buffer as K_SPECIAL 6674 * KS_SPECIAL KE_FILLER, like for mappings, but 6675 * do_cmdline() doesn't handle that, so convert it back. 6676 * Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. */ 6677 len = ksp - p; 6678 if (len > 0) 6679 { 6680 mch_memmove(q, p, len); 6681 q += len; 6682 } 6683 *q++ = ksp[1] == KS_SPECIAL ? K_SPECIAL : CSI; 6684 p = ksp + 3; 6685 continue; 6686 } 6687 } 6688 6689 /* break if there no <item> is found */ 6690 if (start == NULL || end == NULL) 6691 break; 6692 6693 /* Include the '>' */ 6694 ++end; 6695 6696 /* Take everything up to the '<' */ 6697 len = start - p; 6698 if (buf == NULL) 6699 totlen += len; 6700 else 6701 { 6702 mch_memmove(q, p, len); 6703 q += len; 6704 } 6705 6706 len = uc_check_code(start, end - start, q, cmd, eap, 6707 &split_buf, &split_len); 6708 if (len == (size_t)-1) 6709 { 6710 /* no match, continue after '<' */ 6711 p = start + 1; 6712 len = 1; 6713 } 6714 else 6715 p = end; 6716 if (buf == NULL) 6717 totlen += len; 6718 else 6719 q += len; 6720 } 6721 if (buf != NULL) /* second time here, finished */ 6722 { 6723 STRCPY(q, p); 6724 break; 6725 } 6726 6727 totlen += STRLEN(p); /* Add on the trailing characters */ 6728 buf = alloc((unsigned)(totlen + 1)); 6729 if (buf == NULL) 6730 { 6731 vim_free(split_buf); 6732 return; 6733 } 6734 } 6735 6736 #ifdef FEAT_EVAL 6737 current_SID = cmd->uc_scriptID; 6738 #endif 6739 (void)do_cmdline(buf, eap->getline, eap->cookie, 6740 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); 6741 #ifdef FEAT_EVAL 6742 current_SID = save_current_SID; 6743 #endif 6744 vim_free(buf); 6745 vim_free(split_buf); 6746 } 6747 6748 # if defined(FEAT_CMDL_COMPL) || defined(PROTO) 6749 static char_u * 6750 get_user_command_name(int idx) 6751 { 6752 return get_user_commands(NULL, idx - (int)CMD_SIZE); 6753 } 6754 6755 /* 6756 * Function given to ExpandGeneric() to obtain the list of user command names. 6757 */ 6758 char_u * 6759 get_user_commands(expand_T *xp UNUSED, int idx) 6760 { 6761 if (idx < curbuf->b_ucmds.ga_len) 6762 return USER_CMD_GA(&curbuf->b_ucmds, idx)->uc_name; 6763 idx -= curbuf->b_ucmds.ga_len; 6764 if (idx < ucmds.ga_len) 6765 return USER_CMD(idx)->uc_name; 6766 return NULL; 6767 } 6768 6769 /* 6770 * Function given to ExpandGeneric() to obtain the list of user address type names. 6771 */ 6772 char_u * 6773 get_user_cmd_addr_type(expand_T *xp UNUSED, int idx) 6774 { 6775 return (char_u *)addr_type_complete[idx].name; 6776 } 6777 6778 /* 6779 * Function given to ExpandGeneric() to obtain the list of user command 6780 * attributes. 6781 */ 6782 char_u * 6783 get_user_cmd_flags(expand_T *xp UNUSED, int idx) 6784 { 6785 static char *user_cmd_flags[] = 6786 {"addr", "bang", "bar", "buffer", "complete", 6787 "count", "nargs", "range", "register"}; 6788 6789 if (idx >= (int)(sizeof(user_cmd_flags) / sizeof(user_cmd_flags[0]))) 6790 return NULL; 6791 return (char_u *)user_cmd_flags[idx]; 6792 } 6793 6794 /* 6795 * Function given to ExpandGeneric() to obtain the list of values for -nargs. 6796 */ 6797 char_u * 6798 get_user_cmd_nargs(expand_T *xp UNUSED, int idx) 6799 { 6800 static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"}; 6801 6802 if (idx >= (int)(sizeof(user_cmd_nargs) / sizeof(user_cmd_nargs[0]))) 6803 return NULL; 6804 return (char_u *)user_cmd_nargs[idx]; 6805 } 6806 6807 /* 6808 * Function given to ExpandGeneric() to obtain the list of values for -complete. 6809 */ 6810 char_u * 6811 get_user_cmd_complete(expand_T *xp UNUSED, int idx) 6812 { 6813 return (char_u *)command_complete[idx].name; 6814 } 6815 # endif /* FEAT_CMDL_COMPL */ 6816 6817 /* 6818 * Parse address type argument 6819 */ 6820 int 6821 parse_addr_type_arg( 6822 char_u *value, 6823 int vallen, 6824 long *argt, 6825 int *addr_type_arg) 6826 { 6827 int i, a, b; 6828 6829 for (i = 0; addr_type_complete[i].expand != -1; ++i) 6830 { 6831 a = (int)STRLEN(addr_type_complete[i].name) == vallen; 6832 b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0; 6833 if (a && b) 6834 { 6835 *addr_type_arg = addr_type_complete[i].expand; 6836 break; 6837 } 6838 } 6839 6840 if (addr_type_complete[i].expand == -1) 6841 { 6842 char_u *err = value; 6843 6844 for (i = 0; err[i] != NUL && !vim_iswhite(err[i]); i++) 6845 ; 6846 err[i] = NUL; 6847 EMSG2(_("E180: Invalid address type value: %s"), err); 6848 return FAIL; 6849 } 6850 6851 if (*addr_type_arg != ADDR_LINES) 6852 *argt |= NOTADR; 6853 6854 return OK; 6855 } 6856 6857 #endif /* FEAT_USR_CMDS */ 6858 6859 #if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO) 6860 /* 6861 * Parse a completion argument "value[vallen]". 6862 * The detected completion goes in "*complp", argument type in "*argt". 6863 * When there is an argument, for function and user defined completion, it's 6864 * copied to allocated memory and stored in "*compl_arg". 6865 * Returns FAIL if something is wrong. 6866 */ 6867 int 6868 parse_compl_arg( 6869 char_u *value, 6870 int vallen, 6871 int *complp, 6872 long *argt, 6873 char_u **compl_arg UNUSED) 6874 { 6875 char_u *arg = NULL; 6876 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 6877 size_t arglen = 0; 6878 # endif 6879 int i; 6880 int valend = vallen; 6881 6882 /* Look for any argument part - which is the part after any ',' */ 6883 for (i = 0; i < vallen; ++i) 6884 { 6885 if (value[i] == ',') 6886 { 6887 arg = &value[i + 1]; 6888 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 6889 arglen = vallen - i - 1; 6890 # endif 6891 valend = i; 6892 break; 6893 } 6894 } 6895 6896 for (i = 0; command_complete[i].expand != 0; ++i) 6897 { 6898 if ((int)STRLEN(command_complete[i].name) == valend 6899 && STRNCMP(value, command_complete[i].name, valend) == 0) 6900 { 6901 *complp = command_complete[i].expand; 6902 if (command_complete[i].expand == EXPAND_BUFFERS) 6903 *argt |= BUFNAME; 6904 else if (command_complete[i].expand == EXPAND_DIRECTORIES 6905 || command_complete[i].expand == EXPAND_FILES) 6906 *argt |= XFILE; 6907 break; 6908 } 6909 } 6910 6911 if (command_complete[i].expand == 0) 6912 { 6913 EMSG2(_("E180: Invalid complete value: %s"), value); 6914 return FAIL; 6915 } 6916 6917 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 6918 if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST 6919 && arg != NULL) 6920 # else 6921 if (arg != NULL) 6922 # endif 6923 { 6924 EMSG(_("E468: Completion argument only allowed for custom completion")); 6925 return FAIL; 6926 } 6927 6928 # if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 6929 if ((*complp == EXPAND_USER_DEFINED || *complp == EXPAND_USER_LIST) 6930 && arg == NULL) 6931 { 6932 EMSG(_("E467: Custom completion requires a function argument")); 6933 return FAIL; 6934 } 6935 6936 if (arg != NULL) 6937 *compl_arg = vim_strnsave(arg, (int)arglen); 6938 # endif 6939 return OK; 6940 } 6941 #endif 6942 6943 static void 6944 ex_colorscheme(exarg_T *eap) 6945 { 6946 if (*eap->arg == NUL) 6947 { 6948 #ifdef FEAT_EVAL 6949 char_u *expr = vim_strsave((char_u *)"g:colors_name"); 6950 char_u *p = NULL; 6951 6952 if (expr != NULL) 6953 { 6954 ++emsg_off; 6955 p = eval_to_string(expr, NULL, FALSE); 6956 --emsg_off; 6957 vim_free(expr); 6958 } 6959 if (p != NULL) 6960 { 6961 MSG(p); 6962 vim_free(p); 6963 } 6964 else 6965 MSG("default"); 6966 #else 6967 MSG(_("unknown")); 6968 #endif 6969 } 6970 else if (load_colors(eap->arg) == FAIL) 6971 EMSG2(_("E185: Cannot find color scheme '%s'"), eap->arg); 6972 } 6973 6974 static void 6975 ex_highlight(exarg_T *eap) 6976 { 6977 if (*eap->arg == NUL && eap->cmd[2] == '!') 6978 MSG(_("Greetings, Vim user!")); 6979 do_highlight(eap->arg, eap->forceit, FALSE); 6980 } 6981 6982 6983 /* 6984 * Call this function if we thought we were going to exit, but we won't 6985 * (because of an error). May need to restore the terminal mode. 6986 */ 6987 void 6988 not_exiting(void) 6989 { 6990 exiting = FALSE; 6991 settmode(TMODE_RAW); 6992 } 6993 6994 /* 6995 * ":quit": quit current window, quit Vim if the last window is closed. 6996 */ 6997 static void 6998 ex_quit(exarg_T *eap) 6999 { 7000 #if defined(FEAT_WINDOWS) || defined(FEAT_AUTOCMD) 7001 win_T *wp; 7002 #endif 7003 7004 #ifdef FEAT_CMDWIN 7005 if (cmdwin_type != 0) 7006 { 7007 cmdwin_result = Ctrl_C; 7008 return; 7009 } 7010 #endif 7011 /* Don't quit while editing the command line. */ 7012 if (text_locked()) 7013 { 7014 text_locked_msg(); 7015 return; 7016 } 7017 #ifdef FEAT_WINDOWS 7018 if (eap->addr_count > 0) 7019 { 7020 int wnr = eap->line2; 7021 7022 for (wp = firstwin; wp->w_next != NULL; wp = wp->w_next) 7023 if (--wnr <= 0) 7024 break; 7025 } 7026 else 7027 #endif 7028 #if defined(FEAT_WINDOWS) || defined(FEAT_AUTOCMD) 7029 wp = curwin; 7030 #endif 7031 7032 #ifdef FEAT_AUTOCMD 7033 apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); 7034 /* Refuse to quit when locked or when the buffer in the last window is 7035 * being closed (can only happen in autocommands). */ 7036 if (curbuf_locked() || (wp->w_buffer->b_nwindows == 1 7037 && wp->w_buffer->b_closing)) 7038 return; 7039 #endif 7040 7041 #ifdef FEAT_NETBEANS_INTG 7042 netbeansForcedQuit = eap->forceit; 7043 #endif 7044 7045 /* 7046 * If there are more files or windows we won't exit. 7047 */ 7048 if (check_more(FALSE, eap->forceit) == OK && only_one_window()) 7049 exiting = TRUE; 7050 if ((!P_HID(curbuf) 7051 && check_changed(curbuf, (p_awa ? CCGD_AW : 0) 7052 | (eap->forceit ? CCGD_FORCEIT : 0) 7053 | CCGD_EXCMD)) 7054 || check_more(TRUE, eap->forceit) == FAIL 7055 || (only_one_window() && check_changed_any(eap->forceit, TRUE))) 7056 { 7057 not_exiting(); 7058 } 7059 else 7060 { 7061 #ifdef FEAT_WINDOWS 7062 /* quit last window 7063 * Note: only_one_window() returns true, even so a help window is 7064 * still open. In that case only quit, if no address has been 7065 * specified. Example: 7066 * :h|wincmd w|1q - don't quit 7067 * :h|wincmd w|q - quit 7068 */ 7069 if (only_one_window() && (firstwin == lastwin || eap->addr_count == 0)) 7070 #endif 7071 getout(0); 7072 #ifdef FEAT_WINDOWS 7073 # ifdef FEAT_GUI 7074 need_mouse_correct = TRUE; 7075 # endif 7076 /* close window; may free buffer */ 7077 win_close(wp, !P_HID(wp->w_buffer) || eap->forceit); 7078 #endif 7079 } 7080 } 7081 7082 /* 7083 * ":cquit". 7084 */ 7085 static void 7086 ex_cquit(exarg_T *eap UNUSED) 7087 { 7088 getout(1); /* this does not always pass on the exit code to the Manx 7089 compiler. why? */ 7090 } 7091 7092 /* 7093 * ":qall": try to quit all windows 7094 */ 7095 static void 7096 ex_quit_all(exarg_T *eap) 7097 { 7098 # ifdef FEAT_CMDWIN 7099 if (cmdwin_type != 0) 7100 { 7101 if (eap->forceit) 7102 cmdwin_result = K_XF1; /* ex_window() takes care of this */ 7103 else 7104 cmdwin_result = K_XF2; 7105 return; 7106 } 7107 # endif 7108 7109 /* Don't quit while editing the command line. */ 7110 if (text_locked()) 7111 { 7112 text_locked_msg(); 7113 return; 7114 } 7115 #ifdef FEAT_AUTOCMD 7116 apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); 7117 /* Refuse to quit when locked or when the buffer in the last window is 7118 * being closed (can only happen in autocommands). */ 7119 if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing)) 7120 return; 7121 #endif 7122 7123 exiting = TRUE; 7124 if (eap->forceit || !check_changed_any(FALSE, FALSE)) 7125 getout(0); 7126 not_exiting(); 7127 } 7128 7129 #if defined(FEAT_WINDOWS) || defined(PROTO) 7130 /* 7131 * ":close": close current window, unless it is the last one 7132 */ 7133 static void 7134 ex_close(exarg_T *eap) 7135 { 7136 win_T *win; 7137 int winnr = 0; 7138 # ifdef FEAT_CMDWIN 7139 if (cmdwin_type != 0) 7140 cmdwin_result = Ctrl_C; 7141 else 7142 # endif 7143 if (!text_locked() 7144 #ifdef FEAT_AUTOCMD 7145 && !curbuf_locked() 7146 #endif 7147 ) 7148 { 7149 if (eap->addr_count == 0) 7150 ex_win_close(eap->forceit, curwin, NULL); 7151 else { 7152 for (win = firstwin; win != NULL; win = win->w_next) 7153 { 7154 winnr++; 7155 if (winnr == eap->line2) 7156 break; 7157 } 7158 if (win == NULL) 7159 win = lastwin; 7160 ex_win_close(eap->forceit, win, NULL); 7161 } 7162 } 7163 } 7164 7165 # ifdef FEAT_QUICKFIX 7166 /* 7167 * ":pclose": Close any preview window. 7168 */ 7169 static void 7170 ex_pclose(exarg_T *eap) 7171 { 7172 win_T *win; 7173 7174 for (win = firstwin; win != NULL; win = win->w_next) 7175 if (win->w_p_pvw) 7176 { 7177 ex_win_close(eap->forceit, win, NULL); 7178 break; 7179 } 7180 } 7181 # endif 7182 7183 /* 7184 * Close window "win" and take care of handling closing the last window for a 7185 * modified buffer. 7186 */ 7187 static void 7188 ex_win_close( 7189 int forceit, 7190 win_T *win, 7191 tabpage_T *tp) /* NULL or the tab page "win" is in */ 7192 { 7193 int need_hide; 7194 buf_T *buf = win->w_buffer; 7195 7196 need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1); 7197 if (need_hide && !P_HID(buf) && !forceit) 7198 { 7199 # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 7200 if ((p_confirm || cmdmod.confirm) && p_write) 7201 { 7202 dialog_changed(buf, FALSE); 7203 if (buf_valid(buf) && bufIsChanged(buf)) 7204 return; 7205 need_hide = FALSE; 7206 } 7207 else 7208 # endif 7209 { 7210 EMSG(_(e_nowrtmsg)); 7211 return; 7212 } 7213 } 7214 7215 # ifdef FEAT_GUI 7216 need_mouse_correct = TRUE; 7217 # endif 7218 7219 /* free buffer when not hiding it or when it's a scratch buffer */ 7220 if (tp == NULL) 7221 win_close(win, !need_hide && !P_HID(buf)); 7222 else 7223 win_close_othertab(win, !need_hide && !P_HID(buf), tp); 7224 } 7225 7226 /* 7227 * ":tabclose": close current tab page, unless it is the last one. 7228 * ":tabclose N": close tab page N. 7229 */ 7230 static void 7231 ex_tabclose(exarg_T *eap) 7232 { 7233 tabpage_T *tp; 7234 7235 # ifdef FEAT_CMDWIN 7236 if (cmdwin_type != 0) 7237 cmdwin_result = K_IGNORE; 7238 else 7239 # endif 7240 if (first_tabpage->tp_next == NULL) 7241 EMSG(_("E784: Cannot close last tab page")); 7242 else 7243 { 7244 if (eap->addr_count > 0) 7245 { 7246 tp = find_tabpage((int)eap->line2); 7247 if (tp == NULL) 7248 { 7249 beep_flush(); 7250 return; 7251 } 7252 if (tp != curtab) 7253 { 7254 tabpage_close_other(tp, eap->forceit); 7255 return; 7256 } 7257 } 7258 if (!text_locked() 7259 #ifdef FEAT_AUTOCMD 7260 && !curbuf_locked() 7261 #endif 7262 ) 7263 tabpage_close(eap->forceit); 7264 } 7265 } 7266 7267 /* 7268 * ":tabonly": close all tab pages except the current one 7269 */ 7270 static void 7271 ex_tabonly(exarg_T *eap) 7272 { 7273 tabpage_T *tp; 7274 int done; 7275 7276 # ifdef FEAT_CMDWIN 7277 if (cmdwin_type != 0) 7278 cmdwin_result = K_IGNORE; 7279 else 7280 # endif 7281 if (first_tabpage->tp_next == NULL) 7282 MSG(_("Already only one tab page")); 7283 else 7284 { 7285 if (eap->addr_count > 0) 7286 goto_tabpage(eap->line2); 7287 /* Repeat this up to a 1000 times, because autocommands may mess 7288 * up the lists. */ 7289 for (done = 0; done < 1000; ++done) 7290 { 7291 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) 7292 if (tp->tp_topframe != topframe) 7293 { 7294 tabpage_close_other(tp, eap->forceit); 7295 /* if we failed to close it quit */ 7296 if (valid_tabpage(tp)) 7297 done = 1000; 7298 /* start over, "tp" is now invalid */ 7299 break; 7300 } 7301 if (first_tabpage->tp_next == NULL) 7302 break; 7303 } 7304 } 7305 } 7306 7307 /* 7308 * Close the current tab page. 7309 */ 7310 void 7311 tabpage_close(int forceit) 7312 { 7313 /* First close all the windows but the current one. If that worked then 7314 * close the last window in this tab, that will close it. */ 7315 if (lastwin != firstwin) 7316 close_others(TRUE, forceit); 7317 if (lastwin == firstwin) 7318 ex_win_close(forceit, curwin, NULL); 7319 # ifdef FEAT_GUI 7320 need_mouse_correct = TRUE; 7321 # endif 7322 } 7323 7324 /* 7325 * Close tab page "tp", which is not the current tab page. 7326 * Note that autocommands may make "tp" invalid. 7327 * Also takes care of the tab pages line disappearing when closing the 7328 * last-but-one tab page. 7329 */ 7330 void 7331 tabpage_close_other(tabpage_T *tp, int forceit) 7332 { 7333 int done = 0; 7334 win_T *wp; 7335 int h = tabline_height(); 7336 7337 /* Limit to 1000 windows, autocommands may add a window while we close 7338 * one. OK, so I'm paranoid... */ 7339 while (++done < 1000) 7340 { 7341 wp = tp->tp_firstwin; 7342 ex_win_close(forceit, wp, tp); 7343 7344 /* Autocommands may delete the tab page under our fingers and we may 7345 * fail to close a window with a modified buffer. */ 7346 if (!valid_tabpage(tp) || tp->tp_firstwin == wp) 7347 break; 7348 } 7349 7350 redraw_tabline = TRUE; 7351 if (h != tabline_height()) 7352 shell_new_rows(); 7353 } 7354 7355 /* 7356 * ":only". 7357 */ 7358 static void 7359 ex_only(exarg_T *eap) 7360 { 7361 win_T *wp; 7362 int wnr; 7363 # ifdef FEAT_GUI 7364 need_mouse_correct = TRUE; 7365 # endif 7366 if (eap->addr_count > 0) 7367 { 7368 wnr = eap->line2; 7369 for (wp = firstwin; --wnr > 0; ) 7370 { 7371 if (wp->w_next == NULL) 7372 break; 7373 else 7374 wp = wp->w_next; 7375 } 7376 win_goto(wp); 7377 } 7378 close_others(TRUE, eap->forceit); 7379 } 7380 7381 /* 7382 * ":all" and ":sall". 7383 * Also used for ":tab drop file ..." after setting the argument list. 7384 */ 7385 void 7386 ex_all(exarg_T *eap) 7387 { 7388 if (eap->addr_count == 0) 7389 eap->line2 = 9999; 7390 do_arg_all((int)eap->line2, eap->forceit, eap->cmdidx == CMD_drop); 7391 } 7392 #endif /* FEAT_WINDOWS */ 7393 7394 static void 7395 ex_hide(exarg_T *eap) 7396 { 7397 if (*eap->arg != NUL && check_nextcmd(eap->arg) == NULL) 7398 eap->errmsg = e_invarg; 7399 else 7400 { 7401 /* ":hide" or ":hide | cmd": hide current window */ 7402 eap->nextcmd = check_nextcmd(eap->arg); 7403 #ifdef FEAT_WINDOWS 7404 if (!eap->skip) 7405 { 7406 # ifdef FEAT_GUI 7407 need_mouse_correct = TRUE; 7408 # endif 7409 if (eap->addr_count == 0) 7410 win_close(curwin, FALSE); /* don't free buffer */ 7411 else 7412 { 7413 int winnr = 0; 7414 win_T *win; 7415 7416 for (win = firstwin; win != NULL; win = win->w_next) 7417 { 7418 winnr++; 7419 if (winnr == eap->line2) 7420 break; 7421 } 7422 if (win == NULL) 7423 win = lastwin; 7424 win_close(win, FALSE); 7425 } 7426 } 7427 #endif 7428 } 7429 } 7430 7431 /* 7432 * ":stop" and ":suspend": Suspend Vim. 7433 */ 7434 static void 7435 ex_stop(exarg_T *eap) 7436 { 7437 /* 7438 * Disallow suspending for "rvim". 7439 */ 7440 if (!check_restricted() 7441 #ifdef WIN3264 7442 /* 7443 * Check if external commands are allowed now. 7444 */ 7445 && can_end_termcap_mode(TRUE) 7446 #endif 7447 ) 7448 { 7449 if (!eap->forceit) 7450 autowrite_all(); 7451 windgoto((int)Rows - 1, 0); 7452 out_char('\n'); 7453 out_flush(); 7454 stoptermcap(); 7455 out_flush(); /* needed for SUN to restore xterm buffer */ 7456 #ifdef FEAT_TITLE 7457 mch_restore_title(3); /* restore window titles */ 7458 #endif 7459 ui_suspend(); /* call machine specific function */ 7460 #ifdef FEAT_TITLE 7461 maketitle(); 7462 resettitle(); /* force updating the title */ 7463 #endif 7464 starttermcap(); 7465 scroll_start(); /* scroll screen before redrawing */ 7466 redraw_later_clear(); 7467 shell_resized(); /* may have resized window */ 7468 } 7469 } 7470 7471 /* 7472 * ":exit", ":xit" and ":wq": Write file and exit Vim. 7473 */ 7474 static void 7475 ex_exit(exarg_T *eap) 7476 { 7477 #ifdef FEAT_CMDWIN 7478 if (cmdwin_type != 0) 7479 { 7480 cmdwin_result = Ctrl_C; 7481 return; 7482 } 7483 #endif 7484 /* Don't quit while editing the command line. */ 7485 if (text_locked()) 7486 { 7487 text_locked_msg(); 7488 return; 7489 } 7490 #ifdef FEAT_AUTOCMD 7491 apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); 7492 /* Refuse to quit when locked or when the buffer in the last window is 7493 * being closed (can only happen in autocommands). */ 7494 if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing)) 7495 return; 7496 #endif 7497 7498 /* 7499 * if more files or windows we won't exit 7500 */ 7501 if (check_more(FALSE, eap->forceit) == OK && only_one_window()) 7502 exiting = TRUE; 7503 if ( ((eap->cmdidx == CMD_wq 7504 || curbufIsChanged()) 7505 && do_write(eap) == FAIL) 7506 || check_more(TRUE, eap->forceit) == FAIL 7507 || (only_one_window() && check_changed_any(eap->forceit, FALSE))) 7508 { 7509 not_exiting(); 7510 } 7511 else 7512 { 7513 #ifdef FEAT_WINDOWS 7514 if (only_one_window()) /* quit last window, exit Vim */ 7515 #endif 7516 getout(0); 7517 #ifdef FEAT_WINDOWS 7518 # ifdef FEAT_GUI 7519 need_mouse_correct = TRUE; 7520 # endif 7521 /* Quit current window, may free the buffer. */ 7522 win_close(curwin, !P_HID(curwin->w_buffer)); 7523 #endif 7524 } 7525 } 7526 7527 /* 7528 * ":print", ":list", ":number". 7529 */ 7530 static void 7531 ex_print(exarg_T *eap) 7532 { 7533 if (curbuf->b_ml.ml_flags & ML_EMPTY) 7534 EMSG(_(e_emptybuf)); 7535 else 7536 { 7537 for ( ;!got_int; ui_breakcheck()) 7538 { 7539 print_line(eap->line1, 7540 (eap->cmdidx == CMD_number || eap->cmdidx == CMD_pound 7541 || (eap->flags & EXFLAG_NR)), 7542 eap->cmdidx == CMD_list || (eap->flags & EXFLAG_LIST)); 7543 if (++eap->line1 > eap->line2) 7544 break; 7545 out_flush(); /* show one line at a time */ 7546 } 7547 setpcmark(); 7548 /* put cursor at last line */ 7549 curwin->w_cursor.lnum = eap->line2; 7550 beginline(BL_SOL | BL_FIX); 7551 } 7552 7553 ex_no_reprint = TRUE; 7554 } 7555 7556 #ifdef FEAT_BYTEOFF 7557 static void 7558 ex_goto(exarg_T *eap) 7559 { 7560 goto_byte(eap->line2); 7561 } 7562 #endif 7563 7564 /* 7565 * ":shell". 7566 */ 7567 static void 7568 ex_shell(exarg_T *eap UNUSED) 7569 { 7570 do_shell(NULL, 0); 7571 } 7572 7573 #if (defined(FEAT_WINDOWS) && defined(HAVE_DROP_FILE)) \ 7574 || (defined(FEAT_GUI_GTK) && defined(FEAT_DND)) \ 7575 || defined(FEAT_GUI_MSWIN) \ 7576 || defined(FEAT_GUI_MAC) \ 7577 || defined(PROTO) 7578 7579 /* 7580 * Handle a file drop. The code is here because a drop is *nearly* like an 7581 * :args command, but not quite (we have a list of exact filenames, so we 7582 * don't want to (a) parse a command line, or (b) expand wildcards. So the 7583 * code is very similar to :args and hence needs access to a lot of the static 7584 * functions in this file. 7585 * 7586 * The list should be allocated using alloc(), as should each item in the 7587 * list. This function takes over responsibility for freeing the list. 7588 * 7589 * XXX The list is made into the argument list. This is freed using 7590 * FreeWild(), which does a series of vim_free() calls, unless the two defines 7591 * __EMX__ and __ALWAYS_HAS_TRAILING_NUL_POINTER are set. In this case, a 7592 * routine _fnexplodefree() is used. This may cause problems, but as the drop 7593 * file functionality is (currently) not in EMX this is not presently a 7594 * problem. 7595 */ 7596 void 7597 handle_drop( 7598 int filec, /* the number of files dropped */ 7599 char_u **filev, /* the list of files dropped */ 7600 int split) /* force splitting the window */ 7601 { 7602 exarg_T ea; 7603 int save_msg_scroll = msg_scroll; 7604 7605 /* Postpone this while editing the command line. */ 7606 if (text_locked()) 7607 return; 7608 #ifdef FEAT_AUTOCMD 7609 if (curbuf_locked()) 7610 return; 7611 #endif 7612 /* When the screen is being updated we should not change buffers and 7613 * windows structures, it may cause freed memory to be used. */ 7614 if (updating_screen) 7615 return; 7616 7617 /* Check whether the current buffer is changed. If so, we will need 7618 * to split the current window or data could be lost. 7619 * We don't need to check if the 'hidden' option is set, as in this 7620 * case the buffer won't be lost. 7621 */ 7622 if (!P_HID(curbuf) && !split) 7623 { 7624 ++emsg_off; 7625 split = check_changed(curbuf, CCGD_AW); 7626 --emsg_off; 7627 } 7628 if (split) 7629 { 7630 # ifdef FEAT_WINDOWS 7631 if (win_split(0, 0) == FAIL) 7632 return; 7633 RESET_BINDING(curwin); 7634 7635 /* When splitting the window, create a new alist. Otherwise the 7636 * existing one is overwritten. */ 7637 alist_unlink(curwin->w_alist); 7638 alist_new(); 7639 # else 7640 return; /* can't split, always fail */ 7641 # endif 7642 } 7643 7644 /* 7645 * Set up the new argument list. 7646 */ 7647 alist_set(ALIST(curwin), filec, filev, FALSE, NULL, 0); 7648 7649 /* 7650 * Move to the first file. 7651 */ 7652 /* Fake up a minimal "next" command for do_argfile() */ 7653 vim_memset(&ea, 0, sizeof(ea)); 7654 ea.cmd = (char_u *)"next"; 7655 do_argfile(&ea, 0); 7656 7657 /* do_ecmd() may set need_start_insertmode, but since we never left Insert 7658 * mode that is not needed here. */ 7659 need_start_insertmode = FALSE; 7660 7661 /* Restore msg_scroll, otherwise a following command may cause scrolling 7662 * unexpectedly. The screen will be redrawn by the caller, thus 7663 * msg_scroll being set by displaying a message is irrelevant. */ 7664 msg_scroll = save_msg_scroll; 7665 } 7666 #endif 7667 7668 /* 7669 * Clear an argument list: free all file names and reset it to zero entries. 7670 */ 7671 void 7672 alist_clear(alist_T *al) 7673 { 7674 while (--al->al_ga.ga_len >= 0) 7675 vim_free(AARGLIST(al)[al->al_ga.ga_len].ae_fname); 7676 ga_clear(&al->al_ga); 7677 } 7678 7679 /* 7680 * Init an argument list. 7681 */ 7682 void 7683 alist_init(alist_T *al) 7684 { 7685 ga_init2(&al->al_ga, (int)sizeof(aentry_T), 5); 7686 } 7687 7688 #if defined(FEAT_WINDOWS) || defined(PROTO) 7689 7690 /* 7691 * Remove a reference from an argument list. 7692 * Ignored when the argument list is the global one. 7693 * If the argument list is no longer used by any window, free it. 7694 */ 7695 void 7696 alist_unlink(alist_T *al) 7697 { 7698 if (al != &global_alist && --al->al_refcount <= 0) 7699 { 7700 alist_clear(al); 7701 vim_free(al); 7702 } 7703 } 7704 7705 # if defined(FEAT_LISTCMDS) || defined(HAVE_DROP_FILE) || defined(PROTO) 7706 /* 7707 * Create a new argument list and use it for the current window. 7708 */ 7709 void 7710 alist_new(void) 7711 { 7712 curwin->w_alist = (alist_T *)alloc((unsigned)sizeof(alist_T)); 7713 if (curwin->w_alist == NULL) 7714 { 7715 curwin->w_alist = &global_alist; 7716 ++global_alist.al_refcount; 7717 } 7718 else 7719 { 7720 curwin->w_alist->al_refcount = 1; 7721 curwin->w_alist->id = ++max_alist_id; 7722 alist_init(curwin->w_alist); 7723 } 7724 } 7725 # endif 7726 #endif 7727 7728 #if (!defined(UNIX) && !defined(__EMX__)) || defined(PROTO) 7729 /* 7730 * Expand the file names in the global argument list. 7731 * If "fnum_list" is not NULL, use "fnum_list[fnum_len]" as a list of buffer 7732 * numbers to be re-used. 7733 */ 7734 void 7735 alist_expand(int *fnum_list, int fnum_len) 7736 { 7737 char_u **old_arg_files; 7738 int old_arg_count; 7739 char_u **new_arg_files; 7740 int new_arg_file_count; 7741 char_u *save_p_su = p_su; 7742 int i; 7743 7744 /* Don't use 'suffixes' here. This should work like the shell did the 7745 * expansion. Also, the vimrc file isn't read yet, thus the user 7746 * can't set the options. */ 7747 p_su = empty_option; 7748 old_arg_files = (char_u **)alloc((unsigned)(sizeof(char_u *) * GARGCOUNT)); 7749 if (old_arg_files != NULL) 7750 { 7751 for (i = 0; i < GARGCOUNT; ++i) 7752 old_arg_files[i] = vim_strsave(GARGLIST[i].ae_fname); 7753 old_arg_count = GARGCOUNT; 7754 if (expand_wildcards(old_arg_count, old_arg_files, 7755 &new_arg_file_count, &new_arg_files, 7756 EW_FILE|EW_NOTFOUND|EW_ADDSLASH|EW_NOERROR) == OK 7757 && new_arg_file_count > 0) 7758 { 7759 alist_set(&global_alist, new_arg_file_count, new_arg_files, 7760 TRUE, fnum_list, fnum_len); 7761 FreeWild(old_arg_count, old_arg_files); 7762 } 7763 } 7764 p_su = save_p_su; 7765 } 7766 #endif 7767 7768 /* 7769 * Set the argument list for the current window. 7770 * Takes over the allocated files[] and the allocated fnames in it. 7771 */ 7772 void 7773 alist_set( 7774 alist_T *al, 7775 int count, 7776 char_u **files, 7777 int use_curbuf, 7778 int *fnum_list, 7779 int fnum_len) 7780 { 7781 int i; 7782 7783 alist_clear(al); 7784 if (ga_grow(&al->al_ga, count) == OK) 7785 { 7786 for (i = 0; i < count; ++i) 7787 { 7788 if (got_int) 7789 { 7790 /* When adding many buffers this can take a long time. Allow 7791 * interrupting here. */ 7792 while (i < count) 7793 vim_free(files[i++]); 7794 break; 7795 } 7796 7797 /* May set buffer name of a buffer previously used for the 7798 * argument list, so that it's re-used by alist_add. */ 7799 if (fnum_list != NULL && i < fnum_len) 7800 buf_set_name(fnum_list[i], files[i]); 7801 7802 alist_add(al, files[i], use_curbuf ? 2 : 1); 7803 ui_breakcheck(); 7804 } 7805 vim_free(files); 7806 } 7807 else 7808 FreeWild(count, files); 7809 #ifdef FEAT_WINDOWS 7810 if (al == &global_alist) 7811 #endif 7812 arg_had_last = FALSE; 7813 } 7814 7815 /* 7816 * Add file "fname" to argument list "al". 7817 * "fname" must have been allocated and "al" must have been checked for room. 7818 */ 7819 void 7820 alist_add( 7821 alist_T *al, 7822 char_u *fname, 7823 int set_fnum) /* 1: set buffer number; 2: re-use curbuf */ 7824 { 7825 if (fname == NULL) /* don't add NULL file names */ 7826 return; 7827 #ifdef BACKSLASH_IN_FILENAME 7828 slash_adjust(fname); 7829 #endif 7830 AARGLIST(al)[al->al_ga.ga_len].ae_fname = fname; 7831 if (set_fnum > 0) 7832 AARGLIST(al)[al->al_ga.ga_len].ae_fnum = 7833 buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0)); 7834 ++al->al_ga.ga_len; 7835 } 7836 7837 #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) 7838 /* 7839 * Adjust slashes in file names. Called after 'shellslash' was set. 7840 */ 7841 void 7842 alist_slash_adjust(void) 7843 { 7844 int i; 7845 # ifdef FEAT_WINDOWS 7846 win_T *wp; 7847 tabpage_T *tp; 7848 # endif 7849 7850 for (i = 0; i < GARGCOUNT; ++i) 7851 if (GARGLIST[i].ae_fname != NULL) 7852 slash_adjust(GARGLIST[i].ae_fname); 7853 # ifdef FEAT_WINDOWS 7854 FOR_ALL_TAB_WINDOWS(tp, wp) 7855 if (wp->w_alist != &global_alist) 7856 for (i = 0; i < WARGCOUNT(wp); ++i) 7857 if (WARGLIST(wp)[i].ae_fname != NULL) 7858 slash_adjust(WARGLIST(wp)[i].ae_fname); 7859 # endif 7860 } 7861 #endif 7862 7863 /* 7864 * ":preserve". 7865 */ 7866 static void 7867 ex_preserve(exarg_T *eap UNUSED) 7868 { 7869 curbuf->b_flags |= BF_PRESERVED; 7870 ml_preserve(curbuf, TRUE); 7871 } 7872 7873 /* 7874 * ":recover". 7875 */ 7876 static void 7877 ex_recover(exarg_T *eap) 7878 { 7879 /* Set recoverymode right away to avoid the ATTENTION prompt. */ 7880 recoverymode = TRUE; 7881 if (!check_changed(curbuf, (p_awa ? CCGD_AW : 0) 7882 | CCGD_MULTWIN 7883 | (eap->forceit ? CCGD_FORCEIT : 0) 7884 | CCGD_EXCMD) 7885 7886 && (*eap->arg == NUL 7887 || setfname(curbuf, eap->arg, NULL, TRUE) == OK)) 7888 ml_recover(); 7889 recoverymode = FALSE; 7890 } 7891 7892 /* 7893 * Command modifier used in a wrong way. 7894 */ 7895 static void 7896 ex_wrongmodifier(exarg_T *eap) 7897 { 7898 eap->errmsg = e_invcmd; 7899 } 7900 7901 #ifdef FEAT_WINDOWS 7902 /* 7903 * :sview [+command] file split window with new file, read-only 7904 * :split [[+command] file] split window with current or new file 7905 * :vsplit [[+command] file] split window vertically with current or new file 7906 * :new [[+command] file] split window with no or new file 7907 * :vnew [[+command] file] split vertically window with no or new file 7908 * :sfind [+command] file split window with file in 'path' 7909 * 7910 * :tabedit open new Tab page with empty window 7911 * :tabedit [+command] file open new Tab page and edit "file" 7912 * :tabnew [[+command] file] just like :tabedit 7913 * :tabfind [+command] file open new Tab page and find "file" 7914 */ 7915 void 7916 ex_splitview(exarg_T *eap) 7917 { 7918 win_T *old_curwin = curwin; 7919 # if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE) 7920 char_u *fname = NULL; 7921 # endif 7922 # ifdef FEAT_BROWSE 7923 int browse_flag = cmdmod.browse; 7924 # endif 7925 7926 # ifdef FEAT_GUI 7927 need_mouse_correct = TRUE; 7928 # endif 7929 7930 # ifdef FEAT_QUICKFIX 7931 /* A ":split" in the quickfix window works like ":new". Don't want two 7932 * quickfix windows. But it's OK when doing ":tab split". */ 7933 if (bt_quickfix(curbuf) && cmdmod.tab == 0) 7934 { 7935 if (eap->cmdidx == CMD_split) 7936 eap->cmdidx = CMD_new; 7937 if (eap->cmdidx == CMD_vsplit) 7938 eap->cmdidx = CMD_vnew; 7939 } 7940 # endif 7941 7942 # ifdef FEAT_SEARCHPATH 7943 if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) 7944 { 7945 fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), 7946 FNAME_MESS, TRUE, curbuf->b_ffname); 7947 if (fname == NULL) 7948 goto theend; 7949 eap->arg = fname; 7950 } 7951 # ifdef FEAT_BROWSE 7952 else 7953 # endif 7954 # endif 7955 # ifdef FEAT_BROWSE 7956 if (cmdmod.browse 7957 && eap->cmdidx != CMD_vnew 7958 && eap->cmdidx != CMD_new) 7959 { 7960 # ifdef FEAT_AUTOCMD 7961 if ( 7962 # ifdef FEAT_GUI 7963 !gui.in_use && 7964 # endif 7965 au_has_group((char_u *)"FileExplorer")) 7966 { 7967 /* No browsing supported but we do have the file explorer: 7968 * Edit the directory. */ 7969 if (*eap->arg == NUL || !mch_isdir(eap->arg)) 7970 eap->arg = (char_u *)"."; 7971 } 7972 else 7973 # endif 7974 { 7975 fname = do_browse(0, (char_u *)_("Edit File in new window"), 7976 eap->arg, NULL, NULL, NULL, curbuf); 7977 if (fname == NULL) 7978 goto theend; 7979 eap->arg = fname; 7980 } 7981 } 7982 cmdmod.browse = FALSE; /* Don't browse again in do_ecmd(). */ 7983 # endif 7984 7985 /* 7986 * Either open new tab page or split the window. 7987 */ 7988 if (eap->cmdidx == CMD_tabedit 7989 || eap->cmdidx == CMD_tabfind 7990 || eap->cmdidx == CMD_tabnew) 7991 { 7992 if (win_new_tabpage(cmdmod.tab != 0 ? cmdmod.tab 7993 : eap->addr_count == 0 ? 0 7994 : (int)eap->line2 + 1) != FAIL) 7995 { 7996 do_exedit(eap, old_curwin); 7997 7998 /* set the alternate buffer for the window we came from */ 7999 if (curwin != old_curwin 8000 && win_valid(old_curwin) 8001 && old_curwin->w_buffer != curbuf 8002 && !cmdmod.keepalt) 8003 old_curwin->w_alt_fnum = curbuf->b_fnum; 8004 } 8005 } 8006 else if (win_split(eap->addr_count > 0 ? (int)eap->line2 : 0, 8007 *eap->cmd == 'v' ? WSP_VERT : 0) != FAIL) 8008 { 8009 # ifdef FEAT_SCROLLBIND 8010 /* Reset 'scrollbind' when editing another file, but keep it when 8011 * doing ":split" without arguments. */ 8012 if (*eap->arg != NUL 8013 # ifdef FEAT_BROWSE 8014 || cmdmod.browse 8015 # endif 8016 ) 8017 { 8018 RESET_BINDING(curwin); 8019 } 8020 else 8021 do_check_scrollbind(FALSE); 8022 # endif 8023 do_exedit(eap, old_curwin); 8024 } 8025 8026 # ifdef FEAT_BROWSE 8027 cmdmod.browse = browse_flag; 8028 # endif 8029 8030 # if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE) 8031 theend: 8032 vim_free(fname); 8033 # endif 8034 } 8035 8036 /* 8037 * Open a new tab page. 8038 */ 8039 void 8040 tabpage_new(void) 8041 { 8042 exarg_T ea; 8043 8044 vim_memset(&ea, 0, sizeof(ea)); 8045 ea.cmdidx = CMD_tabnew; 8046 ea.cmd = (char_u *)"tabn"; 8047 ea.arg = (char_u *)""; 8048 ex_splitview(&ea); 8049 } 8050 8051 /* 8052 * :tabnext command 8053 */ 8054 static void 8055 ex_tabnext(exarg_T *eap) 8056 { 8057 switch (eap->cmdidx) 8058 { 8059 case CMD_tabfirst: 8060 case CMD_tabrewind: 8061 goto_tabpage(1); 8062 break; 8063 case CMD_tablast: 8064 goto_tabpage(9999); 8065 break; 8066 case CMD_tabprevious: 8067 case CMD_tabNext: 8068 goto_tabpage(eap->addr_count == 0 ? -1 : -(int)eap->line2); 8069 break; 8070 default: /* CMD_tabnext */ 8071 goto_tabpage(eap->addr_count == 0 ? 0 : (int)eap->line2); 8072 break; 8073 } 8074 } 8075 8076 /* 8077 * :tabmove command 8078 */ 8079 static void 8080 ex_tabmove(exarg_T *eap) 8081 { 8082 int tab_number; 8083 8084 if (eap->arg && *eap->arg != NUL) 8085 { 8086 char_u *p = eap->arg; 8087 int relative = 0; /* argument +N/-N means: move N places to the 8088 * right/left relative to the current position. */ 8089 8090 if (*eap->arg == '-') 8091 { 8092 relative = -1; 8093 p = eap->arg + 1; 8094 } 8095 else if (*eap->arg == '+') 8096 { 8097 relative = 1; 8098 p = eap->arg + 1; 8099 } 8100 else 8101 p = eap->arg; 8102 8103 if (relative == 0) 8104 { 8105 if (STRCMP(p, "$") == 0) 8106 tab_number = LAST_TAB_NR; 8107 else if (p == skipdigits(p)) 8108 { 8109 /* No numbers as argument. */ 8110 eap->errmsg = e_invarg; 8111 return; 8112 } 8113 else 8114 tab_number = getdigits(&p); 8115 } 8116 else 8117 { 8118 if (*p != NUL) 8119 tab_number = getdigits(&p); 8120 else 8121 tab_number = 1; 8122 tab_number = tab_number * relative + tabpage_index(curtab); 8123 if (relative == -1) 8124 --tab_number; 8125 } 8126 } 8127 else if (eap->addr_count != 0) 8128 { 8129 tab_number = eap->line2; 8130 if (**eap->cmdlinep == '-') 8131 --tab_number; 8132 } 8133 else 8134 tab_number = LAST_TAB_NR; 8135 8136 tabpage_move(tab_number); 8137 } 8138 8139 /* 8140 * :tabs command: List tabs and their contents. 8141 */ 8142 static void 8143 ex_tabs(exarg_T *eap UNUSED) 8144 { 8145 tabpage_T *tp; 8146 win_T *wp; 8147 int tabcount = 1; 8148 8149 msg_start(); 8150 msg_scroll = TRUE; 8151 for (tp = first_tabpage; tp != NULL && !got_int; tp = tp->tp_next) 8152 { 8153 msg_putchar('\n'); 8154 vim_snprintf((char *)IObuff, IOSIZE, _("Tab page %d"), tabcount++); 8155 msg_outtrans_attr(IObuff, hl_attr(HLF_T)); 8156 out_flush(); /* output one line at a time */ 8157 ui_breakcheck(); 8158 8159 if (tp == curtab) 8160 wp = firstwin; 8161 else 8162 wp = tp->tp_firstwin; 8163 for ( ; wp != NULL && !got_int; wp = wp->w_next) 8164 { 8165 msg_putchar('\n'); 8166 msg_putchar(wp == curwin ? '>' : ' '); 8167 msg_putchar(' '); 8168 msg_putchar(bufIsChanged(wp->w_buffer) ? '+' : ' '); 8169 msg_putchar(' '); 8170 if (buf_spname(wp->w_buffer) != NULL) 8171 vim_strncpy(IObuff, buf_spname(wp->w_buffer), IOSIZE - 1); 8172 else 8173 home_replace(wp->w_buffer, wp->w_buffer->b_fname, 8174 IObuff, IOSIZE, TRUE); 8175 msg_outtrans(IObuff); 8176 out_flush(); /* output one line at a time */ 8177 ui_breakcheck(); 8178 } 8179 } 8180 } 8181 8182 #endif /* FEAT_WINDOWS */ 8183 8184 /* 8185 * ":mode": Set screen mode. 8186 * If no argument given, just get the screen size and redraw. 8187 */ 8188 static void 8189 ex_mode(exarg_T *eap) 8190 { 8191 if (*eap->arg == NUL) 8192 shell_resized(); 8193 else 8194 mch_screenmode(eap->arg); 8195 } 8196 8197 #ifdef FEAT_WINDOWS 8198 /* 8199 * ":resize". 8200 * set, increment or decrement current window height 8201 */ 8202 static void 8203 ex_resize(exarg_T *eap) 8204 { 8205 int n; 8206 win_T *wp = curwin; 8207 8208 if (eap->addr_count > 0) 8209 { 8210 n = eap->line2; 8211 for (wp = firstwin; wp->w_next != NULL && --n > 0; wp = wp->w_next) 8212 ; 8213 } 8214 8215 # ifdef FEAT_GUI 8216 need_mouse_correct = TRUE; 8217 # endif 8218 n = atol((char *)eap->arg); 8219 if (cmdmod.split & WSP_VERT) 8220 { 8221 if (*eap->arg == '-' || *eap->arg == '+') 8222 n += W_WIDTH(curwin); 8223 else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */ 8224 n = 9999; 8225 win_setwidth_win((int)n, wp); 8226 } 8227 else 8228 { 8229 if (*eap->arg == '-' || *eap->arg == '+') 8230 n += curwin->w_height; 8231 else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */ 8232 n = 9999; 8233 win_setheight_win((int)n, wp); 8234 } 8235 } 8236 #endif 8237 8238 /* 8239 * ":find [+command] <file>" command. 8240 */ 8241 static void 8242 ex_find(exarg_T *eap) 8243 { 8244 #ifdef FEAT_SEARCHPATH 8245 char_u *fname; 8246 int count; 8247 8248 fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS, 8249 TRUE, curbuf->b_ffname); 8250 if (eap->addr_count > 0) 8251 { 8252 /* Repeat finding the file "count" times. This matters when it 8253 * appears several times in the path. */ 8254 count = eap->line2; 8255 while (fname != NULL && --count > 0) 8256 { 8257 vim_free(fname); 8258 fname = find_file_in_path(NULL, 0, FNAME_MESS, 8259 FALSE, curbuf->b_ffname); 8260 } 8261 } 8262 8263 if (fname != NULL) 8264 { 8265 eap->arg = fname; 8266 #endif 8267 do_exedit(eap, NULL); 8268 #ifdef FEAT_SEARCHPATH 8269 vim_free(fname); 8270 } 8271 #endif 8272 } 8273 8274 /* 8275 * ":open" simulation: for now just work like ":visual". 8276 */ 8277 static void 8278 ex_open(exarg_T *eap) 8279 { 8280 regmatch_T regmatch; 8281 char_u *p; 8282 8283 curwin->w_cursor.lnum = eap->line2; 8284 beginline(BL_SOL | BL_FIX); 8285 if (*eap->arg == '/') 8286 { 8287 /* ":open /pattern/": put cursor in column found with pattern */ 8288 ++eap->arg; 8289 p = skip_regexp(eap->arg, '/', p_magic, NULL); 8290 *p = NUL; 8291 regmatch.regprog = vim_regcomp(eap->arg, p_magic ? RE_MAGIC : 0); 8292 if (regmatch.regprog != NULL) 8293 { 8294 regmatch.rm_ic = p_ic; 8295 p = ml_get_curline(); 8296 if (vim_regexec(®match, p, (colnr_T)0)) 8297 curwin->w_cursor.col = (colnr_T)(regmatch.startp[0] - p); 8298 else 8299 EMSG(_(e_nomatch)); 8300 vim_regfree(regmatch.regprog); 8301 } 8302 /* Move to the NUL, ignore any other arguments. */ 8303 eap->arg += STRLEN(eap->arg); 8304 } 8305 check_cursor(); 8306 8307 eap->cmdidx = CMD_visual; 8308 do_exedit(eap, NULL); 8309 } 8310 8311 /* 8312 * ":edit", ":badd", ":visual". 8313 */ 8314 static void 8315 ex_edit(exarg_T *eap) 8316 { 8317 do_exedit(eap, NULL); 8318 } 8319 8320 /* 8321 * ":edit <file>" command and alikes. 8322 */ 8323 void 8324 do_exedit( 8325 exarg_T *eap, 8326 win_T *old_curwin) /* curwin before doing a split or NULL */ 8327 { 8328 int n; 8329 #ifdef FEAT_WINDOWS 8330 int need_hide; 8331 #endif 8332 int exmode_was = exmode_active; 8333 8334 /* 8335 * ":vi" command ends Ex mode. 8336 */ 8337 if (exmode_active && (eap->cmdidx == CMD_visual 8338 || eap->cmdidx == CMD_view)) 8339 { 8340 exmode_active = FALSE; 8341 if (*eap->arg == NUL) 8342 { 8343 /* Special case: ":global/pat/visual\NLvi-commands" */ 8344 if (global_busy) 8345 { 8346 int rd = RedrawingDisabled; 8347 int nwr = no_wait_return; 8348 int ms = msg_scroll; 8349 #ifdef FEAT_GUI 8350 int he = hold_gui_events; 8351 #endif 8352 8353 if (eap->nextcmd != NULL) 8354 { 8355 stuffReadbuff(eap->nextcmd); 8356 eap->nextcmd = NULL; 8357 } 8358 8359 if (exmode_was != EXMODE_VIM) 8360 settmode(TMODE_RAW); 8361 RedrawingDisabled = 0; 8362 no_wait_return = 0; 8363 need_wait_return = FALSE; 8364 msg_scroll = 0; 8365 #ifdef FEAT_GUI 8366 hold_gui_events = 0; 8367 #endif 8368 must_redraw = CLEAR; 8369 8370 main_loop(FALSE, TRUE); 8371 8372 RedrawingDisabled = rd; 8373 no_wait_return = nwr; 8374 msg_scroll = ms; 8375 #ifdef FEAT_GUI 8376 hold_gui_events = he; 8377 #endif 8378 } 8379 return; 8380 } 8381 } 8382 8383 if ((eap->cmdidx == CMD_new 8384 || eap->cmdidx == CMD_tabnew 8385 || eap->cmdidx == CMD_tabedit 8386 #ifdef FEAT_WINDOWS 8387 || eap->cmdidx == CMD_vnew 8388 #endif 8389 ) && *eap->arg == NUL) 8390 { 8391 /* ":new" or ":tabnew" without argument: edit an new empty buffer */ 8392 setpcmark(); 8393 (void)do_ecmd(0, NULL, NULL, eap, ECMD_ONE, 8394 ECMD_HIDE + (eap->forceit ? ECMD_FORCEIT : 0), 8395 old_curwin == NULL ? curwin : NULL); 8396 } 8397 else if ((eap->cmdidx != CMD_split 8398 #ifdef FEAT_WINDOWS 8399 && eap->cmdidx != CMD_vsplit 8400 #endif 8401 ) 8402 || *eap->arg != NUL 8403 #ifdef FEAT_BROWSE 8404 || cmdmod.browse 8405 #endif 8406 ) 8407 { 8408 #ifdef FEAT_AUTOCMD 8409 /* Can't edit another file when "curbuf_lock" is set. Only ":edit" 8410 * can bring us here, others are stopped earlier. */ 8411 if (*eap->arg != NUL && curbuf_locked()) 8412 return; 8413 #endif 8414 n = readonlymode; 8415 if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview) 8416 readonlymode = TRUE; 8417 else if (eap->cmdidx == CMD_enew) 8418 readonlymode = FALSE; /* 'readonly' doesn't make sense in an 8419 empty buffer */ 8420 setpcmark(); 8421 if (do_ecmd(0, (eap->cmdidx == CMD_enew ? NULL : eap->arg), 8422 NULL, eap, 8423 /* ":edit" goes to first line if Vi compatible */ 8424 (*eap->arg == NUL && eap->do_ecmd_lnum == 0 8425 && vim_strchr(p_cpo, CPO_GOTO1) != NULL) 8426 ? ECMD_ONE : eap->do_ecmd_lnum, 8427 (P_HID(curbuf) ? ECMD_HIDE : 0) 8428 + (eap->forceit ? ECMD_FORCEIT : 0) 8429 /* after a split we can use an existing buffer */ 8430 + (old_curwin != NULL ? ECMD_OLDBUF : 0) 8431 #ifdef FEAT_LISTCMDS 8432 + (eap->cmdidx == CMD_badd ? ECMD_ADDBUF : 0 ) 8433 #endif 8434 , old_curwin == NULL ? curwin : NULL) == FAIL) 8435 { 8436 /* Editing the file failed. If the window was split, close it. */ 8437 #ifdef FEAT_WINDOWS 8438 if (old_curwin != NULL) 8439 { 8440 need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1); 8441 if (!need_hide || P_HID(curbuf)) 8442 { 8443 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 8444 cleanup_T cs; 8445 8446 /* Reset the error/interrupt/exception state here so that 8447 * aborting() returns FALSE when closing a window. */ 8448 enter_cleanup(&cs); 8449 # endif 8450 # ifdef FEAT_GUI 8451 need_mouse_correct = TRUE; 8452 # endif 8453 win_close(curwin, !need_hide && !P_HID(curbuf)); 8454 8455 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 8456 /* Restore the error/interrupt/exception state if not 8457 * discarded by a new aborting error, interrupt, or 8458 * uncaught exception. */ 8459 leave_cleanup(&cs); 8460 # endif 8461 } 8462 } 8463 #endif 8464 } 8465 else if (readonlymode && curbuf->b_nwindows == 1) 8466 { 8467 /* When editing an already visited buffer, 'readonly' won't be set 8468 * but the previous value is kept. With ":view" and ":sview" we 8469 * want the file to be readonly, except when another window is 8470 * editing the same buffer. */ 8471 curbuf->b_p_ro = TRUE; 8472 } 8473 readonlymode = n; 8474 } 8475 else 8476 { 8477 if (eap->do_ecmd_cmd != NULL) 8478 do_cmdline_cmd(eap->do_ecmd_cmd); 8479 #ifdef FEAT_TITLE 8480 n = curwin->w_arg_idx_invalid; 8481 #endif 8482 check_arg_idx(curwin); 8483 #ifdef FEAT_TITLE 8484 if (n != curwin->w_arg_idx_invalid) 8485 maketitle(); 8486 #endif 8487 } 8488 8489 #ifdef FEAT_WINDOWS 8490 /* 8491 * if ":split file" worked, set alternate file name in old window to new 8492 * file 8493 */ 8494 if (old_curwin != NULL 8495 && *eap->arg != NUL 8496 && curwin != old_curwin 8497 && win_valid(old_curwin) 8498 && old_curwin->w_buffer != curbuf 8499 && !cmdmod.keepalt) 8500 old_curwin->w_alt_fnum = curbuf->b_fnum; 8501 #endif 8502 8503 ex_no_reprint = TRUE; 8504 } 8505 8506 #ifndef FEAT_GUI 8507 /* 8508 * ":gui" and ":gvim" when there is no GUI. 8509 */ 8510 static void 8511 ex_nogui(exarg_T *eap) 8512 { 8513 eap->errmsg = e_nogvim; 8514 } 8515 #endif 8516 8517 #if defined(FEAT_GUI_W32) && defined(FEAT_MENU) && defined(FEAT_TEAROFF) 8518 static void 8519 ex_tearoff(exarg_T *eap) 8520 { 8521 gui_make_tearoff(eap->arg); 8522 } 8523 #endif 8524 8525 #if (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK)) && defined(FEAT_MENU) 8526 static void 8527 ex_popup(exarg_T *eap) 8528 { 8529 gui_make_popup(eap->arg, eap->forceit); 8530 } 8531 #endif 8532 8533 static void 8534 ex_swapname(exarg_T *eap UNUSED) 8535 { 8536 if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL) 8537 MSG(_("No swap file")); 8538 else 8539 msg(curbuf->b_ml.ml_mfp->mf_fname); 8540 } 8541 8542 /* 8543 * ":syncbind" forces all 'scrollbind' windows to have the same relative 8544 * offset. 8545 * (1998-11-02 16:21:01 R. Edward Ralston <[email protected]>) 8546 */ 8547 static void 8548 ex_syncbind(exarg_T *eap UNUSED) 8549 { 8550 #ifdef FEAT_SCROLLBIND 8551 win_T *wp; 8552 win_T *save_curwin = curwin; 8553 buf_T *save_curbuf = curbuf; 8554 long topline; 8555 long y; 8556 linenr_T old_linenr = curwin->w_cursor.lnum; 8557 8558 setpcmark(); 8559 8560 /* 8561 * determine max topline 8562 */ 8563 if (curwin->w_p_scb) 8564 { 8565 topline = curwin->w_topline; 8566 for (wp = firstwin; wp; wp = wp->w_next) 8567 { 8568 if (wp->w_p_scb && wp->w_buffer) 8569 { 8570 y = wp->w_buffer->b_ml.ml_line_count - p_so; 8571 if (topline > y) 8572 topline = y; 8573 } 8574 } 8575 if (topline < 1) 8576 topline = 1; 8577 } 8578 else 8579 { 8580 topline = 1; 8581 } 8582 8583 8584 /* 8585 * Set all scrollbind windows to the same topline. 8586 */ 8587 for (curwin = firstwin; curwin; curwin = curwin->w_next) 8588 { 8589 if (curwin->w_p_scb) 8590 { 8591 curbuf = curwin->w_buffer; 8592 y = topline - curwin->w_topline; 8593 if (y > 0) 8594 scrollup(y, TRUE); 8595 else 8596 scrolldown(-y, TRUE); 8597 curwin->w_scbind_pos = topline; 8598 redraw_later(VALID); 8599 cursor_correct(); 8600 #ifdef FEAT_WINDOWS 8601 curwin->w_redr_status = TRUE; 8602 #endif 8603 } 8604 } 8605 curwin = save_curwin; 8606 curbuf = save_curbuf; 8607 if (curwin->w_p_scb) 8608 { 8609 did_syncbind = TRUE; 8610 checkpcmark(); 8611 if (old_linenr != curwin->w_cursor.lnum) 8612 { 8613 char_u ctrl_o[2]; 8614 8615 ctrl_o[0] = Ctrl_O; 8616 ctrl_o[1] = 0; 8617 ins_typebuf(ctrl_o, REMAP_NONE, 0, TRUE, FALSE); 8618 } 8619 } 8620 #endif 8621 } 8622 8623 8624 static void 8625 ex_read(exarg_T *eap) 8626 { 8627 int i; 8628 int empty = (curbuf->b_ml.ml_flags & ML_EMPTY); 8629 linenr_T lnum; 8630 8631 if (eap->usefilter) /* :r!cmd */ 8632 do_bang(1, eap, FALSE, FALSE, TRUE); 8633 else 8634 { 8635 if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL) 8636 return; 8637 8638 #ifdef FEAT_BROWSE 8639 if (cmdmod.browse) 8640 { 8641 char_u *browseFile; 8642 8643 browseFile = do_browse(0, (char_u *)_("Append File"), eap->arg, 8644 NULL, NULL, NULL, curbuf); 8645 if (browseFile != NULL) 8646 { 8647 i = readfile(browseFile, NULL, 8648 eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0); 8649 vim_free(browseFile); 8650 } 8651 else 8652 i = OK; 8653 } 8654 else 8655 #endif 8656 if (*eap->arg == NUL) 8657 { 8658 if (check_fname() == FAIL) /* check for no file name */ 8659 return; 8660 i = readfile(curbuf->b_ffname, curbuf->b_fname, 8661 eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0); 8662 } 8663 else 8664 { 8665 if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL) 8666 (void)setaltfname(eap->arg, eap->arg, (linenr_T)1); 8667 i = readfile(eap->arg, NULL, 8668 eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0); 8669 8670 } 8671 if (i == FAIL) 8672 { 8673 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 8674 if (!aborting()) 8675 #endif 8676 EMSG2(_(e_notopen), eap->arg); 8677 } 8678 else 8679 { 8680 if (empty && exmode_active) 8681 { 8682 /* Delete the empty line that remains. Historically ex does 8683 * this but vi doesn't. */ 8684 if (eap->line2 == 0) 8685 lnum = curbuf->b_ml.ml_line_count; 8686 else 8687 lnum = 1; 8688 if (*ml_get(lnum) == NUL && u_savedel(lnum, 1L) == OK) 8689 { 8690 ml_delete(lnum, FALSE); 8691 if (curwin->w_cursor.lnum > 1 8692 && curwin->w_cursor.lnum >= lnum) 8693 --curwin->w_cursor.lnum; 8694 deleted_lines_mark(lnum, 1L); 8695 } 8696 } 8697 redraw_curbuf_later(VALID); 8698 } 8699 } 8700 } 8701 8702 static char_u *prev_dir = NULL; 8703 8704 #if defined(EXITFREE) || defined(PROTO) 8705 void 8706 free_cd_dir(void) 8707 { 8708 vim_free(prev_dir); 8709 prev_dir = NULL; 8710 8711 vim_free(globaldir); 8712 globaldir = NULL; 8713 } 8714 #endif 8715 8716 /* 8717 * Deal with the side effects of changing the current directory. 8718 * When "local" is TRUE then this was after an ":lcd" command. 8719 */ 8720 void 8721 post_chdir(int local) 8722 { 8723 vim_free(curwin->w_localdir); 8724 curwin->w_localdir = NULL; 8725 if (local) 8726 { 8727 /* If still in global directory, need to remember current 8728 * directory as global directory. */ 8729 if (globaldir == NULL && prev_dir != NULL) 8730 globaldir = vim_strsave(prev_dir); 8731 /* Remember this local directory for the window. */ 8732 if (mch_dirname(NameBuff, MAXPATHL) == OK) 8733 curwin->w_localdir = vim_strsave(NameBuff); 8734 } 8735 else 8736 { 8737 /* We are now in the global directory, no need to remember its 8738 * name. */ 8739 vim_free(globaldir); 8740 globaldir = NULL; 8741 } 8742 8743 shorten_fnames(TRUE); 8744 } 8745 8746 8747 /* 8748 * ":cd", ":lcd", ":chdir" and ":lchdir". 8749 */ 8750 void 8751 ex_cd(exarg_T *eap) 8752 { 8753 char_u *new_dir; 8754 char_u *tofree; 8755 8756 new_dir = eap->arg; 8757 #if !defined(UNIX) && !defined(VMS) 8758 /* for non-UNIX ":cd" means: print current directory */ 8759 if (*new_dir == NUL) 8760 ex_pwd(NULL); 8761 else 8762 #endif 8763 { 8764 #ifdef FEAT_AUTOCMD 8765 if (allbuf_locked()) 8766 return; 8767 #endif 8768 if (vim_strchr(p_cpo, CPO_CHDIR) != NULL && curbufIsChanged() 8769 && !eap->forceit) 8770 { 8771 EMSG(_("E747: Cannot change directory, buffer is modified (add ! to override)")); 8772 return; 8773 } 8774 8775 /* ":cd -": Change to previous directory */ 8776 if (STRCMP(new_dir, "-") == 0) 8777 { 8778 if (prev_dir == NULL) 8779 { 8780 EMSG(_("E186: No previous directory")); 8781 return; 8782 } 8783 new_dir = prev_dir; 8784 } 8785 8786 /* Save current directory for next ":cd -" */ 8787 tofree = prev_dir; 8788 if (mch_dirname(NameBuff, MAXPATHL) == OK) 8789 prev_dir = vim_strsave(NameBuff); 8790 else 8791 prev_dir = NULL; 8792 8793 #if defined(UNIX) || defined(VMS) 8794 /* for UNIX ":cd" means: go to home directory */ 8795 if (*new_dir == NUL) 8796 { 8797 /* use NameBuff for home directory name */ 8798 # ifdef VMS 8799 char_u *p; 8800 8801 p = mch_getenv((char_u *)"SYS$LOGIN"); 8802 if (p == NULL || *p == NUL) /* empty is the same as not set */ 8803 NameBuff[0] = NUL; 8804 else 8805 vim_strncpy(NameBuff, p, MAXPATHL - 1); 8806 # else 8807 expand_env((char_u *)"$HOME", NameBuff, MAXPATHL); 8808 # endif 8809 new_dir = NameBuff; 8810 } 8811 #endif 8812 if (new_dir == NULL || vim_chdir(new_dir)) 8813 EMSG(_(e_failed)); 8814 else 8815 { 8816 post_chdir(eap->cmdidx == CMD_lcd || eap->cmdidx == CMD_lchdir); 8817 8818 /* Echo the new current directory if the command was typed. */ 8819 if (KeyTyped || p_verbose >= 5) 8820 ex_pwd(eap); 8821 } 8822 vim_free(tofree); 8823 } 8824 } 8825 8826 /* 8827 * ":pwd". 8828 */ 8829 static void 8830 ex_pwd(exarg_T *eap UNUSED) 8831 { 8832 if (mch_dirname(NameBuff, MAXPATHL) == OK) 8833 { 8834 #ifdef BACKSLASH_IN_FILENAME 8835 slash_adjust(NameBuff); 8836 #endif 8837 msg(NameBuff); 8838 } 8839 else 8840 EMSG(_("E187: Unknown")); 8841 } 8842 8843 /* 8844 * ":=". 8845 */ 8846 static void 8847 ex_equal(exarg_T *eap) 8848 { 8849 smsg((char_u *)"%ld", (long)eap->line2); 8850 ex_may_print(eap); 8851 } 8852 8853 static void 8854 ex_sleep(exarg_T *eap) 8855 { 8856 int n; 8857 long len; 8858 8859 if (cursor_valid()) 8860 { 8861 n = W_WINROW(curwin) + curwin->w_wrow - msg_scrolled; 8862 if (n >= 0) 8863 windgoto((int)n, W_WINCOL(curwin) + curwin->w_wcol); 8864 } 8865 8866 len = eap->line2; 8867 switch (*eap->arg) 8868 { 8869 case 'm': break; 8870 case NUL: len *= 1000L; break; 8871 default: EMSG2(_(e_invarg2), eap->arg); return; 8872 } 8873 do_sleep(len); 8874 } 8875 8876 /* 8877 * Sleep for "msec" milliseconds, but keep checking for a CTRL-C every second. 8878 */ 8879 void 8880 do_sleep(long msec) 8881 { 8882 long done; 8883 long wait_now; 8884 8885 cursor_on(); 8886 out_flush(); 8887 for (done = 0; !got_int && done < msec; done += wait_now) 8888 { 8889 wait_now = msec - done > 1000L ? 1000L : msec - done; 8890 #ifdef FEAT_TIMERS 8891 { 8892 long due_time = check_due_timer(); 8893 8894 if (due_time > 0 && due_time < wait_now) 8895 wait_now = due_time; 8896 } 8897 #endif 8898 ui_delay(wait_now, TRUE); 8899 ui_breakcheck(); 8900 #ifdef MESSAGE_QUEUE 8901 /* Process the netbeans and clientserver messages that may have been 8902 * received in the call to ui_breakcheck() when the GUI is in use. This 8903 * may occur when running a test case. */ 8904 parse_queued_messages(); 8905 #endif 8906 } 8907 } 8908 8909 static void 8910 do_exmap(exarg_T *eap, int isabbrev) 8911 { 8912 int mode; 8913 char_u *cmdp; 8914 8915 cmdp = eap->cmd; 8916 mode = get_map_mode(&cmdp, eap->forceit || isabbrev); 8917 8918 switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'), 8919 eap->arg, mode, isabbrev)) 8920 { 8921 case 1: EMSG(_(e_invarg)); 8922 break; 8923 case 2: EMSG(isabbrev ? _(e_noabbr) : _(e_nomap)); 8924 break; 8925 } 8926 } 8927 8928 /* 8929 * ":winsize" command (obsolete). 8930 */ 8931 static void 8932 ex_winsize(exarg_T *eap) 8933 { 8934 int w, h; 8935 char_u *arg = eap->arg; 8936 char_u *p; 8937 8938 w = getdigits(&arg); 8939 arg = skipwhite(arg); 8940 p = arg; 8941 h = getdigits(&arg); 8942 if (*p != NUL && *arg == NUL) 8943 set_shellsize(w, h, TRUE); 8944 else 8945 EMSG(_("E465: :winsize requires two number arguments")); 8946 } 8947 8948 #ifdef FEAT_WINDOWS 8949 static void 8950 ex_wincmd(exarg_T *eap) 8951 { 8952 int xchar = NUL; 8953 char_u *p; 8954 8955 if (*eap->arg == 'g' || *eap->arg == Ctrl_G) 8956 { 8957 /* CTRL-W g and CTRL-W CTRL-G have an extra command character */ 8958 if (eap->arg[1] == NUL) 8959 { 8960 EMSG(_(e_invarg)); 8961 return; 8962 } 8963 xchar = eap->arg[1]; 8964 p = eap->arg + 2; 8965 } 8966 else 8967 p = eap->arg + 1; 8968 8969 eap->nextcmd = check_nextcmd(p); 8970 p = skipwhite(p); 8971 if (*p != NUL && *p != '"' && eap->nextcmd == NULL) 8972 EMSG(_(e_invarg)); 8973 else if (!eap->skip) 8974 { 8975 /* Pass flags on for ":vertical wincmd ]". */ 8976 postponed_split_flags = cmdmod.split; 8977 postponed_split_tab = cmdmod.tab; 8978 do_window(*eap->arg, eap->addr_count > 0 ? eap->line2 : 0L, xchar); 8979 postponed_split_flags = 0; 8980 postponed_split_tab = 0; 8981 } 8982 } 8983 #endif 8984 8985 #if defined(FEAT_GUI) || defined(UNIX) || defined(VMS) || defined(MSWIN) 8986 /* 8987 * ":winpos". 8988 */ 8989 static void 8990 ex_winpos(exarg_T *eap) 8991 { 8992 int x, y; 8993 char_u *arg = eap->arg; 8994 char_u *p; 8995 8996 if (*arg == NUL) 8997 { 8998 # if defined(FEAT_GUI) || defined(MSWIN) 8999 # ifdef FEAT_GUI 9000 if (gui.in_use && gui_mch_get_winpos(&x, &y) != FAIL) 9001 # else 9002 if (mch_get_winpos(&x, &y) != FAIL) 9003 # endif 9004 { 9005 sprintf((char *)IObuff, _("Window position: X %d, Y %d"), x, y); 9006 msg(IObuff); 9007 } 9008 else 9009 # endif 9010 EMSG(_("E188: Obtaining window position not implemented for this platform")); 9011 } 9012 else 9013 { 9014 x = getdigits(&arg); 9015 arg = skipwhite(arg); 9016 p = arg; 9017 y = getdigits(&arg); 9018 if (*p == NUL || *arg != NUL) 9019 { 9020 EMSG(_("E466: :winpos requires two number arguments")); 9021 return; 9022 } 9023 # ifdef FEAT_GUI 9024 if (gui.in_use) 9025 gui_mch_set_winpos(x, y); 9026 else if (gui.starting) 9027 { 9028 /* Remember the coordinates for when the window is opened. */ 9029 gui_win_x = x; 9030 gui_win_y = y; 9031 } 9032 # ifdef HAVE_TGETENT 9033 else 9034 # endif 9035 # else 9036 # ifdef MSWIN 9037 mch_set_winpos(x, y); 9038 # endif 9039 # endif 9040 # ifdef HAVE_TGETENT 9041 if (*T_CWP) 9042 term_set_winpos(x, y); 9043 # endif 9044 } 9045 } 9046 #endif 9047 9048 /* 9049 * Handle command that work like operators: ":delete", ":yank", ":>" and ":<". 9050 */ 9051 static void 9052 ex_operators(exarg_T *eap) 9053 { 9054 oparg_T oa; 9055 9056 clear_oparg(&oa); 9057 oa.regname = eap->regname; 9058 oa.start.lnum = eap->line1; 9059 oa.end.lnum = eap->line2; 9060 oa.line_count = eap->line2 - eap->line1 + 1; 9061 oa.motion_type = MLINE; 9062 #ifdef FEAT_VIRTUALEDIT 9063 virtual_op = FALSE; 9064 #endif 9065 if (eap->cmdidx != CMD_yank) /* position cursor for undo */ 9066 { 9067 setpcmark(); 9068 curwin->w_cursor.lnum = eap->line1; 9069 beginline(BL_SOL | BL_FIX); 9070 } 9071 9072 if (VIsual_active) 9073 end_visual_mode(); 9074 9075 switch (eap->cmdidx) 9076 { 9077 case CMD_delete: 9078 oa.op_type = OP_DELETE; 9079 op_delete(&oa); 9080 break; 9081 9082 case CMD_yank: 9083 oa.op_type = OP_YANK; 9084 (void)op_yank(&oa, FALSE, TRUE); 9085 break; 9086 9087 default: /* CMD_rshift or CMD_lshift */ 9088 if ( 9089 #ifdef FEAT_RIGHTLEFT 9090 (eap->cmdidx == CMD_rshift) ^ curwin->w_p_rl 9091 #else 9092 eap->cmdidx == CMD_rshift 9093 #endif 9094 ) 9095 oa.op_type = OP_RSHIFT; 9096 else 9097 oa.op_type = OP_LSHIFT; 9098 op_shift(&oa, FALSE, eap->amount); 9099 break; 9100 } 9101 #ifdef FEAT_VIRTUALEDIT 9102 virtual_op = MAYBE; 9103 #endif 9104 ex_may_print(eap); 9105 } 9106 9107 /* 9108 * ":put". 9109 */ 9110 static void 9111 ex_put(exarg_T *eap) 9112 { 9113 /* ":0put" works like ":1put!". */ 9114 if (eap->line2 == 0) 9115 { 9116 eap->line2 = 1; 9117 eap->forceit = TRUE; 9118 } 9119 curwin->w_cursor.lnum = eap->line2; 9120 do_put(eap->regname, eap->forceit ? BACKWARD : FORWARD, 1L, 9121 PUT_LINE|PUT_CURSLINE); 9122 } 9123 9124 /* 9125 * Handle ":copy" and ":move". 9126 */ 9127 static void 9128 ex_copymove(exarg_T *eap) 9129 { 9130 long n; 9131 9132 n = get_address(eap, &eap->arg, eap->addr_type, FALSE, FALSE); 9133 if (eap->arg == NULL) /* error detected */ 9134 { 9135 eap->nextcmd = NULL; 9136 return; 9137 } 9138 get_flags(eap); 9139 9140 /* 9141 * move or copy lines from 'eap->line1'-'eap->line2' to below line 'n' 9142 */ 9143 if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count) 9144 { 9145 EMSG(_(e_invaddr)); 9146 return; 9147 } 9148 9149 if (eap->cmdidx == CMD_move) 9150 { 9151 if (do_move(eap->line1, eap->line2, n) == FAIL) 9152 return; 9153 } 9154 else 9155 ex_copy(eap->line1, eap->line2, n); 9156 u_clearline(); 9157 beginline(BL_SOL | BL_FIX); 9158 ex_may_print(eap); 9159 } 9160 9161 /* 9162 * Print the current line if flags were given to the Ex command. 9163 */ 9164 void 9165 ex_may_print(exarg_T *eap) 9166 { 9167 if (eap->flags != 0) 9168 { 9169 print_line(curwin->w_cursor.lnum, (eap->flags & EXFLAG_NR), 9170 (eap->flags & EXFLAG_LIST)); 9171 ex_no_reprint = TRUE; 9172 } 9173 } 9174 9175 /* 9176 * ":smagic" and ":snomagic". 9177 */ 9178 static void 9179 ex_submagic(exarg_T *eap) 9180 { 9181 int magic_save = p_magic; 9182 9183 p_magic = (eap->cmdidx == CMD_smagic); 9184 do_sub(eap); 9185 p_magic = magic_save; 9186 } 9187 9188 /* 9189 * ":join". 9190 */ 9191 static void 9192 ex_join(exarg_T *eap) 9193 { 9194 curwin->w_cursor.lnum = eap->line1; 9195 if (eap->line1 == eap->line2) 9196 { 9197 if (eap->addr_count >= 2) /* :2,2join does nothing */ 9198 return; 9199 if (eap->line2 == curbuf->b_ml.ml_line_count) 9200 { 9201 beep_flush(); 9202 return; 9203 } 9204 ++eap->line2; 9205 } 9206 (void)do_join(eap->line2 - eap->line1 + 1, !eap->forceit, TRUE, TRUE, TRUE); 9207 beginline(BL_WHITE | BL_FIX); 9208 ex_may_print(eap); 9209 } 9210 9211 /* 9212 * ":[addr]@r" or ":[addr]*r": execute register 9213 */ 9214 static void 9215 ex_at(exarg_T *eap) 9216 { 9217 int c; 9218 int prev_len = typebuf.tb_len; 9219 9220 curwin->w_cursor.lnum = eap->line2; 9221 9222 #ifdef USE_ON_FLY_SCROLL 9223 dont_scroll = TRUE; /* disallow scrolling here */ 9224 #endif 9225 9226 /* get the register name. No name means to use the previous one */ 9227 c = *eap->arg; 9228 if (c == NUL || (c == '*' && *eap->cmd == '*')) 9229 c = '@'; 9230 /* Put the register in the typeahead buffer with the "silent" flag. */ 9231 if (do_execreg(c, TRUE, vim_strchr(p_cpo, CPO_EXECBUF) != NULL, TRUE) 9232 == FAIL) 9233 { 9234 beep_flush(); 9235 } 9236 else 9237 { 9238 int save_efr = exec_from_reg; 9239 9240 exec_from_reg = TRUE; 9241 9242 /* 9243 * Execute from the typeahead buffer. 9244 * Continue until the stuff buffer is empty and all added characters 9245 * have been consumed. 9246 */ 9247 while (!stuff_empty() || typebuf.tb_len > prev_len) 9248 (void)do_cmdline(NULL, getexline, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE); 9249 9250 exec_from_reg = save_efr; 9251 } 9252 } 9253 9254 /* 9255 * ":!". 9256 */ 9257 static void 9258 ex_bang(exarg_T *eap) 9259 { 9260 do_bang(eap->addr_count, eap, eap->forceit, TRUE, TRUE); 9261 } 9262 9263 /* 9264 * ":undo". 9265 */ 9266 static void 9267 ex_undo(exarg_T *eap) 9268 { 9269 if (eap->addr_count == 1) /* :undo 123 */ 9270 undo_time(eap->line2, FALSE, FALSE, TRUE); 9271 else 9272 u_undo(1); 9273 } 9274 9275 #ifdef FEAT_PERSISTENT_UNDO 9276 static void 9277 ex_wundo(exarg_T *eap) 9278 { 9279 char_u hash[UNDO_HASH_SIZE]; 9280 9281 u_compute_hash(hash); 9282 u_write_undo(eap->arg, eap->forceit, curbuf, hash); 9283 } 9284 9285 static void 9286 ex_rundo(exarg_T *eap) 9287 { 9288 char_u hash[UNDO_HASH_SIZE]; 9289 9290 u_compute_hash(hash); 9291 u_read_undo(eap->arg, hash, NULL); 9292 } 9293 #endif 9294 9295 /* 9296 * ":redo". 9297 */ 9298 static void 9299 ex_redo(exarg_T *eap UNUSED) 9300 { 9301 u_redo(1); 9302 } 9303 9304 /* 9305 * ":earlier" and ":later". 9306 */ 9307 static void 9308 ex_later(exarg_T *eap) 9309 { 9310 long count = 0; 9311 int sec = FALSE; 9312 int file = FALSE; 9313 char_u *p = eap->arg; 9314 9315 if (*p == NUL) 9316 count = 1; 9317 else if (isdigit(*p)) 9318 { 9319 count = getdigits(&p); 9320 switch (*p) 9321 { 9322 case 's': ++p; sec = TRUE; break; 9323 case 'm': ++p; sec = TRUE; count *= 60; break; 9324 case 'h': ++p; sec = TRUE; count *= 60 * 60; break; 9325 case 'd': ++p; sec = TRUE; count *= 24 * 60 * 60; break; 9326 case 'f': ++p; file = TRUE; break; 9327 } 9328 } 9329 9330 if (*p != NUL) 9331 EMSG2(_(e_invarg2), eap->arg); 9332 else 9333 undo_time(eap->cmdidx == CMD_earlier ? -count : count, 9334 sec, file, FALSE); 9335 } 9336 9337 /* 9338 * ":redir": start/stop redirection. 9339 */ 9340 static void 9341 ex_redir(exarg_T *eap) 9342 { 9343 char *mode; 9344 char_u *fname; 9345 char_u *arg = eap->arg; 9346 9347 if (STRICMP(eap->arg, "END") == 0) 9348 close_redir(); 9349 else 9350 { 9351 if (*arg == '>') 9352 { 9353 ++arg; 9354 if (*arg == '>') 9355 { 9356 ++arg; 9357 mode = "a"; 9358 } 9359 else 9360 mode = "w"; 9361 arg = skipwhite(arg); 9362 9363 close_redir(); 9364 9365 /* Expand environment variables and "~/". */ 9366 fname = expand_env_save(arg); 9367 if (fname == NULL) 9368 return; 9369 #ifdef FEAT_BROWSE 9370 if (cmdmod.browse) 9371 { 9372 char_u *browseFile; 9373 9374 browseFile = do_browse(BROWSE_SAVE, 9375 (char_u *)_("Save Redirection"), 9376 fname, NULL, NULL, BROWSE_FILTER_ALL_FILES, curbuf); 9377 if (browseFile == NULL) 9378 return; /* operation cancelled */ 9379 vim_free(fname); 9380 fname = browseFile; 9381 eap->forceit = TRUE; /* since dialog already asked */ 9382 } 9383 #endif 9384 9385 redir_fd = open_exfile(fname, eap->forceit, mode); 9386 vim_free(fname); 9387 } 9388 #ifdef FEAT_EVAL 9389 else if (*arg == '@') 9390 { 9391 /* redirect to a register a-z (resp. A-Z for appending) */ 9392 close_redir(); 9393 ++arg; 9394 if (ASCII_ISALPHA(*arg) 9395 # ifdef FEAT_CLIPBOARD 9396 || *arg == '*' 9397 || *arg == '+' 9398 # endif 9399 || *arg == '"') 9400 { 9401 redir_reg = *arg++; 9402 if (*arg == '>' && arg[1] == '>') /* append */ 9403 arg += 2; 9404 else 9405 { 9406 /* Can use both "@a" and "@a>". */ 9407 if (*arg == '>') 9408 arg++; 9409 /* Make register empty when not using @A-@Z and the 9410 * command is valid. */ 9411 if (*arg == NUL && !isupper(redir_reg)) 9412 write_reg_contents(redir_reg, (char_u *)"", -1, FALSE); 9413 } 9414 } 9415 if (*arg != NUL) 9416 { 9417 redir_reg = 0; 9418 EMSG2(_(e_invarg2), eap->arg); 9419 } 9420 } 9421 else if (*arg == '=' && arg[1] == '>') 9422 { 9423 int append; 9424 9425 /* redirect to a variable */ 9426 close_redir(); 9427 arg += 2; 9428 9429 if (*arg == '>') 9430 { 9431 ++arg; 9432 append = TRUE; 9433 } 9434 else 9435 append = FALSE; 9436 9437 if (var_redir_start(skipwhite(arg), append) == OK) 9438 redir_vname = 1; 9439 } 9440 #endif 9441 9442 /* TODO: redirect to a buffer */ 9443 9444 else 9445 EMSG2(_(e_invarg2), eap->arg); 9446 } 9447 9448 /* Make sure redirection is not off. Can happen for cmdline completion 9449 * that indirectly invokes a command to catch its output. */ 9450 if (redir_fd != NULL 9451 #ifdef FEAT_EVAL 9452 || redir_reg || redir_vname 9453 #endif 9454 ) 9455 redir_off = FALSE; 9456 } 9457 9458 /* 9459 * ":redraw": force redraw 9460 */ 9461 void 9462 ex_redraw(exarg_T *eap) 9463 { 9464 int r = RedrawingDisabled; 9465 int p = p_lz; 9466 9467 RedrawingDisabled = 0; 9468 p_lz = FALSE; 9469 update_topline(); 9470 update_screen(eap->forceit ? CLEAR : VIsual_active ? INVERTED : 0); 9471 #ifdef FEAT_TITLE 9472 if (need_maketitle) 9473 maketitle(); 9474 #endif 9475 RedrawingDisabled = r; 9476 p_lz = p; 9477 9478 /* Reset msg_didout, so that a message that's there is overwritten. */ 9479 msg_didout = FALSE; 9480 msg_col = 0; 9481 9482 /* No need to wait after an intentional redraw. */ 9483 need_wait_return = FALSE; 9484 9485 out_flush(); 9486 } 9487 9488 /* 9489 * ":redrawstatus": force redraw of status line(s) 9490 */ 9491 static void 9492 ex_redrawstatus(exarg_T *eap UNUSED) 9493 { 9494 #if defined(FEAT_WINDOWS) 9495 int r = RedrawingDisabled; 9496 int p = p_lz; 9497 9498 RedrawingDisabled = 0; 9499 p_lz = FALSE; 9500 if (eap->forceit) 9501 status_redraw_all(); 9502 else 9503 status_redraw_curbuf(); 9504 update_screen(VIsual_active ? INVERTED : 0); 9505 RedrawingDisabled = r; 9506 p_lz = p; 9507 out_flush(); 9508 #endif 9509 } 9510 9511 static void 9512 close_redir(void) 9513 { 9514 if (redir_fd != NULL) 9515 { 9516 fclose(redir_fd); 9517 redir_fd = NULL; 9518 } 9519 #ifdef FEAT_EVAL 9520 redir_reg = 0; 9521 if (redir_vname) 9522 { 9523 var_redir_stop(); 9524 redir_vname = 0; 9525 } 9526 #endif 9527 } 9528 9529 #if defined(FEAT_SESSION) && defined(USE_CRNL) 9530 # define MKSESSION_NL 9531 static int mksession_nl = FALSE; /* use NL only in put_eol() */ 9532 #endif 9533 9534 /* 9535 * ":mkexrc", ":mkvimrc", ":mkview" and ":mksession". 9536 */ 9537 static void 9538 ex_mkrc( 9539 exarg_T *eap) 9540 { 9541 FILE *fd; 9542 int failed = FALSE; 9543 char_u *fname; 9544 #ifdef FEAT_BROWSE 9545 char_u *browseFile = NULL; 9546 #endif 9547 #ifdef FEAT_SESSION 9548 int view_session = FALSE; 9549 int using_vdir = FALSE; /* using 'viewdir'? */ 9550 char_u *viewFile = NULL; 9551 unsigned *flagp; 9552 #endif 9553 9554 if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview) 9555 { 9556 #ifdef FEAT_SESSION 9557 view_session = TRUE; 9558 #else 9559 ex_ni(eap); 9560 return; 9561 #endif 9562 } 9563 9564 #ifdef FEAT_SESSION 9565 /* Use the short file name until ":lcd" is used. We also don't use the 9566 * short file name when 'acd' is set, that is checked later. */ 9567 did_lcd = FALSE; 9568 9569 /* ":mkview" or ":mkview 9": generate file name with 'viewdir' */ 9570 if (eap->cmdidx == CMD_mkview 9571 && (*eap->arg == NUL 9572 || (vim_isdigit(*eap->arg) && eap->arg[1] == NUL))) 9573 { 9574 eap->forceit = TRUE; 9575 fname = get_view_file(*eap->arg); 9576 if (fname == NULL) 9577 return; 9578 viewFile = fname; 9579 using_vdir = TRUE; 9580 } 9581 else 9582 #endif 9583 if (*eap->arg != NUL) 9584 fname = eap->arg; 9585 else if (eap->cmdidx == CMD_mkvimrc) 9586 fname = (char_u *)VIMRC_FILE; 9587 #ifdef FEAT_SESSION 9588 else if (eap->cmdidx == CMD_mksession) 9589 fname = (char_u *)SESSION_FILE; 9590 #endif 9591 else 9592 fname = (char_u *)EXRC_FILE; 9593 9594 #ifdef FEAT_BROWSE 9595 if (cmdmod.browse) 9596 { 9597 browseFile = do_browse(BROWSE_SAVE, 9598 # ifdef FEAT_SESSION 9599 eap->cmdidx == CMD_mkview ? (char_u *)_("Save View") : 9600 eap->cmdidx == CMD_mksession ? (char_u *)_("Save Session") : 9601 # endif 9602 (char_u *)_("Save Setup"), 9603 fname, (char_u *)"vim", NULL, BROWSE_FILTER_MACROS, NULL); 9604 if (browseFile == NULL) 9605 goto theend; 9606 fname = browseFile; 9607 eap->forceit = TRUE; /* since dialog already asked */ 9608 } 9609 #endif 9610 9611 #if defined(FEAT_SESSION) && defined(vim_mkdir) 9612 /* When using 'viewdir' may have to create the directory. */ 9613 if (using_vdir && !mch_isdir(p_vdir)) 9614 vim_mkdir_emsg(p_vdir, 0755); 9615 #endif 9616 9617 fd = open_exfile(fname, eap->forceit, WRITEBIN); 9618 if (fd != NULL) 9619 { 9620 #ifdef FEAT_SESSION 9621 if (eap->cmdidx == CMD_mkview) 9622 flagp = &vop_flags; 9623 else 9624 flagp = &ssop_flags; 9625 #endif 9626 9627 #ifdef MKSESSION_NL 9628 /* "unix" in 'sessionoptions': use NL line separator */ 9629 if (view_session && (*flagp & SSOP_UNIX)) 9630 mksession_nl = TRUE; 9631 #endif 9632 9633 /* Write the version command for :mkvimrc */ 9634 if (eap->cmdidx == CMD_mkvimrc) 9635 (void)put_line(fd, "version 6.0"); 9636 9637 #ifdef FEAT_SESSION 9638 if (eap->cmdidx == CMD_mksession) 9639 { 9640 if (put_line(fd, "let SessionLoad = 1") == FAIL) 9641 failed = TRUE; 9642 } 9643 9644 if (eap->cmdidx != CMD_mkview) 9645 #endif 9646 { 9647 /* Write setting 'compatible' first, because it has side effects. 9648 * For that same reason only do it when needed. */ 9649 if (p_cp) 9650 (void)put_line(fd, "if !&cp | set cp | endif"); 9651 else 9652 (void)put_line(fd, "if &cp | set nocp | endif"); 9653 } 9654 9655 #ifdef FEAT_SESSION 9656 if (!view_session 9657 || (eap->cmdidx == CMD_mksession 9658 && (*flagp & SSOP_OPTIONS))) 9659 #endif 9660 failed |= (makemap(fd, NULL) == FAIL 9661 || makeset(fd, OPT_GLOBAL, FALSE) == FAIL); 9662 9663 #ifdef FEAT_SESSION 9664 if (!failed && view_session) 9665 { 9666 if (put_line(fd, "let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0") == FAIL) 9667 failed = TRUE; 9668 if (eap->cmdidx == CMD_mksession) 9669 { 9670 char_u *dirnow; /* current directory */ 9671 9672 dirnow = alloc(MAXPATHL); 9673 if (dirnow == NULL) 9674 failed = TRUE; 9675 else 9676 { 9677 /* 9678 * Change to session file's dir. 9679 */ 9680 if (mch_dirname(dirnow, MAXPATHL) == FAIL 9681 || mch_chdir((char *)dirnow) != 0) 9682 *dirnow = NUL; 9683 if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR)) 9684 { 9685 if (vim_chdirfile(fname) == OK) 9686 shorten_fnames(TRUE); 9687 } 9688 else if (*dirnow != NUL 9689 && (ssop_flags & SSOP_CURDIR) && globaldir != NULL) 9690 { 9691 if (mch_chdir((char *)globaldir) == 0) 9692 shorten_fnames(TRUE); 9693 } 9694 9695 failed |= (makeopens(fd, dirnow) == FAIL); 9696 9697 /* restore original dir */ 9698 if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR) 9699 || ((ssop_flags & SSOP_CURDIR) && globaldir != NULL))) 9700 { 9701 if (mch_chdir((char *)dirnow) != 0) 9702 EMSG(_(e_prev_dir)); 9703 shorten_fnames(TRUE); 9704 } 9705 vim_free(dirnow); 9706 } 9707 } 9708 else 9709 { 9710 failed |= (put_view(fd, curwin, !using_vdir, flagp, 9711 -1) == FAIL); 9712 } 9713 if (put_line(fd, "let &so = s:so_save | let &siso = s:siso_save") 9714 == FAIL) 9715 failed = TRUE; 9716 if (put_line(fd, "doautoall SessionLoadPost") == FAIL) 9717 failed = TRUE; 9718 if (eap->cmdidx == CMD_mksession) 9719 { 9720 if (put_line(fd, "unlet SessionLoad") == FAIL) 9721 failed = TRUE; 9722 } 9723 } 9724 #endif 9725 if (put_line(fd, "\" vim: set ft=vim :") == FAIL) 9726 failed = TRUE; 9727 9728 failed |= fclose(fd); 9729 9730 if (failed) 9731 EMSG(_(e_write)); 9732 #if defined(FEAT_EVAL) && defined(FEAT_SESSION) 9733 else if (eap->cmdidx == CMD_mksession) 9734 { 9735 /* successful session write - set this_session var */ 9736 char_u *tbuf; 9737 9738 tbuf = alloc(MAXPATHL); 9739 if (tbuf != NULL) 9740 { 9741 if (vim_FullName(fname, tbuf, MAXPATHL, FALSE) == OK) 9742 set_vim_var_string(VV_THIS_SESSION, tbuf, -1); 9743 vim_free(tbuf); 9744 } 9745 } 9746 #endif 9747 #ifdef MKSESSION_NL 9748 mksession_nl = FALSE; 9749 #endif 9750 } 9751 9752 #ifdef FEAT_BROWSE 9753 theend: 9754 vim_free(browseFile); 9755 #endif 9756 #ifdef FEAT_SESSION 9757 vim_free(viewFile); 9758 #endif 9759 } 9760 9761 #if ((defined(FEAT_SESSION) || defined(FEAT_EVAL)) && defined(vim_mkdir)) \ 9762 || defined(PROTO) 9763 int 9764 vim_mkdir_emsg(char_u *name, int prot) 9765 { 9766 if (vim_mkdir(name, prot) != 0) 9767 { 9768 EMSG2(_("E739: Cannot create directory: %s"), name); 9769 return FAIL; 9770 } 9771 return OK; 9772 } 9773 #endif 9774 9775 /* 9776 * Open a file for writing for an Ex command, with some checks. 9777 * Return file descriptor, or NULL on failure. 9778 */ 9779 FILE * 9780 open_exfile( 9781 char_u *fname, 9782 int forceit, 9783 char *mode) /* "w" for create new file or "a" for append */ 9784 { 9785 FILE *fd; 9786 9787 #ifdef UNIX 9788 /* with Unix it is possible to open a directory */ 9789 if (mch_isdir(fname)) 9790 { 9791 EMSG2(_(e_isadir2), fname); 9792 return NULL; 9793 } 9794 #endif 9795 if (!forceit && *mode != 'a' && vim_fexists(fname)) 9796 { 9797 EMSG2(_("E189: \"%s\" exists (add ! to override)"), fname); 9798 return NULL; 9799 } 9800 9801 if ((fd = mch_fopen((char *)fname, mode)) == NULL) 9802 EMSG2(_("E190: Cannot open \"%s\" for writing"), fname); 9803 9804 return fd; 9805 } 9806 9807 /* 9808 * ":mark" and ":k". 9809 */ 9810 static void 9811 ex_mark(exarg_T *eap) 9812 { 9813 pos_T pos; 9814 9815 if (*eap->arg == NUL) /* No argument? */ 9816 EMSG(_(e_argreq)); 9817 else if (eap->arg[1] != NUL) /* more than one character? */ 9818 EMSG(_(e_trailing)); 9819 else 9820 { 9821 pos = curwin->w_cursor; /* save curwin->w_cursor */ 9822 curwin->w_cursor.lnum = eap->line2; 9823 beginline(BL_WHITE | BL_FIX); 9824 if (setmark(*eap->arg) == FAIL) /* set mark */ 9825 EMSG(_("E191: Argument must be a letter or forward/backward quote")); 9826 curwin->w_cursor = pos; /* restore curwin->w_cursor */ 9827 } 9828 } 9829 9830 /* 9831 * Update w_topline, w_leftcol and the cursor position. 9832 */ 9833 void 9834 update_topline_cursor(void) 9835 { 9836 check_cursor(); /* put cursor on valid line */ 9837 update_topline(); 9838 if (!curwin->w_p_wrap) 9839 validate_cursor(); 9840 update_curswant(); 9841 } 9842 9843 /* 9844 * ":normal[!] {commands}": Execute normal mode commands. 9845 */ 9846 void 9847 ex_normal(exarg_T *eap) 9848 { 9849 int save_msg_scroll = msg_scroll; 9850 int save_restart_edit = restart_edit; 9851 int save_msg_didout = msg_didout; 9852 int save_State = State; 9853 tasave_T tabuf; 9854 int save_insertmode = p_im; 9855 int save_finish_op = finish_op; 9856 int save_opcount = opcount; 9857 #ifdef FEAT_MBYTE 9858 char_u *arg = NULL; 9859 int l; 9860 char_u *p; 9861 #endif 9862 9863 if (ex_normal_lock > 0) 9864 { 9865 EMSG(_(e_secure)); 9866 return; 9867 } 9868 if (ex_normal_busy >= p_mmd) 9869 { 9870 EMSG(_("E192: Recursive use of :normal too deep")); 9871 return; 9872 } 9873 ++ex_normal_busy; 9874 9875 msg_scroll = FALSE; /* no msg scrolling in Normal mode */ 9876 restart_edit = 0; /* don't go to Insert mode */ 9877 p_im = FALSE; /* don't use 'insertmode' */ 9878 9879 #ifdef FEAT_MBYTE 9880 /* 9881 * vgetc() expects a CSI and K_SPECIAL to have been escaped. Don't do 9882 * this for the K_SPECIAL leading byte, otherwise special keys will not 9883 * work. 9884 */ 9885 if (has_mbyte) 9886 { 9887 int len = 0; 9888 9889 /* Count the number of characters to be escaped. */ 9890 for (p = eap->arg; *p != NUL; ++p) 9891 { 9892 # ifdef FEAT_GUI 9893 if (*p == CSI) /* leadbyte CSI */ 9894 len += 2; 9895 # endif 9896 for (l = (*mb_ptr2len)(p) - 1; l > 0; --l) 9897 if (*++p == K_SPECIAL /* trailbyte K_SPECIAL or CSI */ 9898 # ifdef FEAT_GUI 9899 || *p == CSI 9900 # endif 9901 ) 9902 len += 2; 9903 } 9904 if (len > 0) 9905 { 9906 arg = alloc((unsigned)(STRLEN(eap->arg) + len + 1)); 9907 if (arg != NULL) 9908 { 9909 len = 0; 9910 for (p = eap->arg; *p != NUL; ++p) 9911 { 9912 arg[len++] = *p; 9913 # ifdef FEAT_GUI 9914 if (*p == CSI) 9915 { 9916 arg[len++] = KS_EXTRA; 9917 arg[len++] = (int)KE_CSI; 9918 } 9919 # endif 9920 for (l = (*mb_ptr2len)(p) - 1; l > 0; --l) 9921 { 9922 arg[len++] = *++p; 9923 if (*p == K_SPECIAL) 9924 { 9925 arg[len++] = KS_SPECIAL; 9926 arg[len++] = KE_FILLER; 9927 } 9928 # ifdef FEAT_GUI 9929 else if (*p == CSI) 9930 { 9931 arg[len++] = KS_EXTRA; 9932 arg[len++] = (int)KE_CSI; 9933 } 9934 # endif 9935 } 9936 arg[len] = NUL; 9937 } 9938 } 9939 } 9940 } 9941 #endif 9942 9943 /* 9944 * Save the current typeahead. This is required to allow using ":normal" 9945 * from an event handler and makes sure we don't hang when the argument 9946 * ends with half a command. 9947 */ 9948 save_typeahead(&tabuf); 9949 if (tabuf.typebuf_valid) 9950 { 9951 /* 9952 * Repeat the :normal command for each line in the range. When no 9953 * range given, execute it just once, without positioning the cursor 9954 * first. 9955 */ 9956 do 9957 { 9958 if (eap->addr_count != 0) 9959 { 9960 curwin->w_cursor.lnum = eap->line1++; 9961 curwin->w_cursor.col = 0; 9962 } 9963 9964 exec_normal_cmd( 9965 #ifdef FEAT_MBYTE 9966 arg != NULL ? arg : 9967 #endif 9968 eap->arg, eap->forceit ? REMAP_NONE : REMAP_YES, FALSE); 9969 } 9970 while (eap->addr_count > 0 && eap->line1 <= eap->line2 && !got_int); 9971 } 9972 9973 /* Might not return to the main loop when in an event handler. */ 9974 update_topline_cursor(); 9975 9976 /* Restore the previous typeahead. */ 9977 restore_typeahead(&tabuf); 9978 9979 --ex_normal_busy; 9980 msg_scroll = save_msg_scroll; 9981 restart_edit = save_restart_edit; 9982 p_im = save_insertmode; 9983 finish_op = save_finish_op; 9984 opcount = save_opcount; 9985 msg_didout |= save_msg_didout; /* don't reset msg_didout now */ 9986 9987 /* Restore the state (needed when called from a function executed for 9988 * 'indentexpr'). Update the mouse and cursor, they may have changed. */ 9989 State = save_State; 9990 #ifdef FEAT_MOUSE 9991 setmouse(); 9992 #endif 9993 #ifdef CURSOR_SHAPE 9994 ui_cursor_shape(); /* may show different cursor shape */ 9995 #endif 9996 9997 #ifdef FEAT_MBYTE 9998 vim_free(arg); 9999 #endif 10000 } 10001 10002 /* 10003 * ":startinsert", ":startreplace" and ":startgreplace" 10004 */ 10005 static void 10006 ex_startinsert(exarg_T *eap) 10007 { 10008 if (eap->forceit) 10009 { 10010 coladvance((colnr_T)MAXCOL); 10011 curwin->w_curswant = MAXCOL; 10012 curwin->w_set_curswant = FALSE; 10013 } 10014 10015 /* Ignore the command when already in Insert mode. Inserting an 10016 * expression register that invokes a function can do this. */ 10017 if (State & INSERT) 10018 return; 10019 10020 if (eap->cmdidx == CMD_startinsert) 10021 restart_edit = 'a'; 10022 else if (eap->cmdidx == CMD_startreplace) 10023 restart_edit = 'R'; 10024 else 10025 restart_edit = 'V'; 10026 10027 if (!eap->forceit) 10028 { 10029 if (eap->cmdidx == CMD_startinsert) 10030 restart_edit = 'i'; 10031 curwin->w_curswant = 0; /* avoid MAXCOL */ 10032 } 10033 } 10034 10035 /* 10036 * ":stopinsert" 10037 */ 10038 static void 10039 ex_stopinsert(exarg_T *eap UNUSED) 10040 { 10041 restart_edit = 0; 10042 stop_insert_mode = TRUE; 10043 } 10044 10045 /* 10046 * Execute normal mode command "cmd". 10047 * "remap" can be REMAP_NONE or REMAP_YES. 10048 */ 10049 void 10050 exec_normal_cmd(char_u *cmd, int remap, int silent) 10051 { 10052 /* Stuff the argument into the typeahead buffer. */ 10053 ins_typebuf(cmd, remap, 0, TRUE, silent); 10054 exec_normal(FALSE); 10055 } 10056 10057 /* 10058 * Execute normal_cmd() until there is no typeahead left. 10059 */ 10060 void 10061 exec_normal(int was_typed) 10062 { 10063 oparg_T oa; 10064 10065 clear_oparg(&oa); 10066 finish_op = FALSE; 10067 while ((!stuff_empty() || ((was_typed || !typebuf_typed()) 10068 && typebuf.tb_len > 0)) && !got_int) 10069 { 10070 update_topline_cursor(); 10071 normal_cmd(&oa, TRUE); /* execute a Normal mode cmd */ 10072 } 10073 } 10074 10075 #ifdef FEAT_FIND_ID 10076 static void 10077 ex_checkpath(exarg_T *eap) 10078 { 10079 find_pattern_in_path(NULL, 0, 0, FALSE, FALSE, CHECK_PATH, 1L, 10080 eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW, 10081 (linenr_T)1, (linenr_T)MAXLNUM); 10082 } 10083 10084 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 10085 /* 10086 * ":psearch" 10087 */ 10088 static void 10089 ex_psearch(exarg_T *eap) 10090 { 10091 g_do_tagpreview = p_pvh; 10092 ex_findpat(eap); 10093 g_do_tagpreview = 0; 10094 } 10095 #endif 10096 10097 static void 10098 ex_findpat(exarg_T *eap) 10099 { 10100 int whole = TRUE; 10101 long n; 10102 char_u *p; 10103 int action; 10104 10105 switch (cmdnames[eap->cmdidx].cmd_name[2]) 10106 { 10107 case 'e': /* ":psearch", ":isearch" and ":dsearch" */ 10108 if (cmdnames[eap->cmdidx].cmd_name[0] == 'p') 10109 action = ACTION_GOTO; 10110 else 10111 action = ACTION_SHOW; 10112 break; 10113 case 'i': /* ":ilist" and ":dlist" */ 10114 action = ACTION_SHOW_ALL; 10115 break; 10116 case 'u': /* ":ijump" and ":djump" */ 10117 action = ACTION_GOTO; 10118 break; 10119 default: /* ":isplit" and ":dsplit" */ 10120 action = ACTION_SPLIT; 10121 break; 10122 } 10123 10124 n = 1; 10125 if (vim_isdigit(*eap->arg)) /* get count */ 10126 { 10127 n = getdigits(&eap->arg); 10128 eap->arg = skipwhite(eap->arg); 10129 } 10130 if (*eap->arg == '/') /* Match regexp, not just whole words */ 10131 { 10132 whole = FALSE; 10133 ++eap->arg; 10134 p = skip_regexp(eap->arg, '/', p_magic, NULL); 10135 if (*p) 10136 { 10137 *p++ = NUL; 10138 p = skipwhite(p); 10139 10140 /* Check for trailing illegal characters */ 10141 if (!ends_excmd(*p)) 10142 eap->errmsg = e_trailing; 10143 else 10144 eap->nextcmd = check_nextcmd(p); 10145 } 10146 } 10147 if (!eap->skip) 10148 find_pattern_in_path(eap->arg, 0, (int)STRLEN(eap->arg), 10149 whole, !eap->forceit, 10150 *eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY, 10151 n, action, eap->line1, eap->line2); 10152 } 10153 #endif 10154 10155 #ifdef FEAT_WINDOWS 10156 10157 # ifdef FEAT_QUICKFIX 10158 /* 10159 * ":ptag", ":ptselect", ":ptjump", ":ptnext", etc. 10160 */ 10161 static void 10162 ex_ptag(exarg_T *eap) 10163 { 10164 g_do_tagpreview = p_pvh; /* will be reset to 0 in ex_tag_cmd() */ 10165 ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1); 10166 } 10167 10168 /* 10169 * ":pedit" 10170 */ 10171 static void 10172 ex_pedit(exarg_T *eap) 10173 { 10174 win_T *curwin_save = curwin; 10175 10176 g_do_tagpreview = p_pvh; 10177 prepare_tagpreview(TRUE); 10178 keep_help_flag = curwin_save->w_buffer->b_help; 10179 do_exedit(eap, NULL); 10180 keep_help_flag = FALSE; 10181 if (curwin != curwin_save && win_valid(curwin_save)) 10182 { 10183 /* Return cursor to where we were */ 10184 validate_cursor(); 10185 redraw_later(VALID); 10186 win_enter(curwin_save, TRUE); 10187 } 10188 g_do_tagpreview = 0; 10189 } 10190 # endif 10191 10192 /* 10193 * ":stag", ":stselect" and ":stjump". 10194 */ 10195 static void 10196 ex_stag(exarg_T *eap) 10197 { 10198 postponed_split = -1; 10199 postponed_split_flags = cmdmod.split; 10200 postponed_split_tab = cmdmod.tab; 10201 ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1); 10202 postponed_split_flags = 0; 10203 postponed_split_tab = 0; 10204 } 10205 #endif 10206 10207 /* 10208 * ":tag", ":tselect", ":tjump", ":tnext", etc. 10209 */ 10210 static void 10211 ex_tag(exarg_T *eap) 10212 { 10213 ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name); 10214 } 10215 10216 static void 10217 ex_tag_cmd(exarg_T *eap, char_u *name) 10218 { 10219 int cmd; 10220 10221 switch (name[1]) 10222 { 10223 case 'j': cmd = DT_JUMP; /* ":tjump" */ 10224 break; 10225 case 's': cmd = DT_SELECT; /* ":tselect" */ 10226 break; 10227 case 'p': cmd = DT_PREV; /* ":tprevious" */ 10228 break; 10229 case 'N': cmd = DT_PREV; /* ":tNext" */ 10230 break; 10231 case 'n': cmd = DT_NEXT; /* ":tnext" */ 10232 break; 10233 case 'o': cmd = DT_POP; /* ":pop" */ 10234 break; 10235 case 'f': /* ":tfirst" */ 10236 case 'r': cmd = DT_FIRST; /* ":trewind" */ 10237 break; 10238 case 'l': cmd = DT_LAST; /* ":tlast" */ 10239 break; 10240 default: /* ":tag" */ 10241 #ifdef FEAT_CSCOPE 10242 if (p_cst && *eap->arg != NUL) 10243 { 10244 do_cstag(eap); 10245 return; 10246 } 10247 #endif 10248 cmd = DT_TAG; 10249 break; 10250 } 10251 10252 if (name[0] == 'l') 10253 { 10254 #ifndef FEAT_QUICKFIX 10255 ex_ni(eap); 10256 return; 10257 #else 10258 cmd = DT_LTAG; 10259 #endif 10260 } 10261 10262 do_tag(eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1, 10263 eap->forceit, TRUE); 10264 } 10265 10266 /* 10267 * Check "str" for starting with a special cmdline variable. 10268 * If found return one of the SPEC_ values and set "*usedlen" to the length of 10269 * the variable. Otherwise return -1 and "*usedlen" is unchanged. 10270 */ 10271 int 10272 find_cmdline_var(char_u *src, int *usedlen) 10273 { 10274 int len; 10275 int i; 10276 static char *(spec_str[]) = { 10277 "%", 10278 #define SPEC_PERC 0 10279 "#", 10280 #define SPEC_HASH 1 10281 "<cword>", /* cursor word */ 10282 #define SPEC_CWORD 2 10283 "<cWORD>", /* cursor WORD */ 10284 #define SPEC_CCWORD 3 10285 "<cfile>", /* cursor path name */ 10286 #define SPEC_CFILE 4 10287 "<sfile>", /* ":so" file name */ 10288 #define SPEC_SFILE 5 10289 "<slnum>", /* ":so" file line number */ 10290 #define SPEC_SLNUM 6 10291 #ifdef FEAT_AUTOCMD 10292 "<afile>", /* autocommand file name */ 10293 # define SPEC_AFILE 7 10294 "<abuf>", /* autocommand buffer number */ 10295 # define SPEC_ABUF 8 10296 "<amatch>", /* autocommand match name */ 10297 # define SPEC_AMATCH 9 10298 #endif 10299 #ifdef FEAT_CLIENTSERVER 10300 "<client>" 10301 # ifdef FEAT_AUTOCMD 10302 # define SPEC_CLIENT 10 10303 # else 10304 # define SPEC_CLIENT 7 10305 # endif 10306 #endif 10307 }; 10308 10309 for (i = 0; i < (int)(sizeof(spec_str) / sizeof(char *)); ++i) 10310 { 10311 len = (int)STRLEN(spec_str[i]); 10312 if (STRNCMP(src, spec_str[i], len) == 0) 10313 { 10314 *usedlen = len; 10315 return i; 10316 } 10317 } 10318 return -1; 10319 } 10320 10321 /* 10322 * Evaluate cmdline variables. 10323 * 10324 * change '%' to curbuf->b_ffname 10325 * '#' to curwin->w_altfile 10326 * '<cword>' to word under the cursor 10327 * '<cWORD>' to WORD under the cursor 10328 * '<cfile>' to path name under the cursor 10329 * '<sfile>' to sourced file name 10330 * '<slnum>' to sourced file line number 10331 * '<afile>' to file name for autocommand 10332 * '<abuf>' to buffer number for autocommand 10333 * '<amatch>' to matching name for autocommand 10334 * 10335 * When an error is detected, "errormsg" is set to a non-NULL pointer (may be 10336 * "" for error without a message) and NULL is returned. 10337 * Returns an allocated string if a valid match was found. 10338 * Returns NULL if no match was found. "usedlen" then still contains the 10339 * number of characters to skip. 10340 */ 10341 char_u * 10342 eval_vars( 10343 char_u *src, /* pointer into commandline */ 10344 char_u *srcstart, /* beginning of valid memory for src */ 10345 int *usedlen, /* characters after src that are used */ 10346 linenr_T *lnump, /* line number for :e command, or NULL */ 10347 char_u **errormsg, /* pointer to error message */ 10348 int *escaped) /* return value has escaped white space (can 10349 * be NULL) */ 10350 { 10351 int i; 10352 char_u *s; 10353 char_u *result; 10354 char_u *resultbuf = NULL; 10355 int resultlen; 10356 buf_T *buf; 10357 int valid = VALID_HEAD + VALID_PATH; /* assume valid result */ 10358 int spec_idx; 10359 #ifdef FEAT_MODIFY_FNAME 10360 int skip_mod = FALSE; 10361 #endif 10362 char_u strbuf[30]; 10363 10364 *errormsg = NULL; 10365 if (escaped != NULL) 10366 *escaped = FALSE; 10367 10368 /* 10369 * Check if there is something to do. 10370 */ 10371 spec_idx = find_cmdline_var(src, usedlen); 10372 if (spec_idx < 0) /* no match */ 10373 { 10374 *usedlen = 1; 10375 return NULL; 10376 } 10377 10378 /* 10379 * Skip when preceded with a backslash "\%" and "\#". 10380 * Note: In "\\%" the % is also not recognized! 10381 */ 10382 if (src > srcstart && src[-1] == '\\') 10383 { 10384 *usedlen = 0; 10385 STRMOVE(src - 1, src); /* remove backslash */ 10386 return NULL; 10387 } 10388 10389 /* 10390 * word or WORD under cursor 10391 */ 10392 if (spec_idx == SPEC_CWORD || spec_idx == SPEC_CCWORD) 10393 { 10394 resultlen = find_ident_under_cursor(&result, spec_idx == SPEC_CWORD ? 10395 (FIND_IDENT|FIND_STRING) : FIND_STRING); 10396 if (resultlen == 0) 10397 { 10398 *errormsg = (char_u *)""; 10399 return NULL; 10400 } 10401 } 10402 10403 /* 10404 * '#': Alternate file name 10405 * '%': Current file name 10406 * File name under the cursor 10407 * File name for autocommand 10408 * and following modifiers 10409 */ 10410 else 10411 { 10412 switch (spec_idx) 10413 { 10414 case SPEC_PERC: /* '%': current file */ 10415 if (curbuf->b_fname == NULL) 10416 { 10417 result = (char_u *)""; 10418 valid = 0; /* Must have ":p:h" to be valid */ 10419 } 10420 else 10421 result = curbuf->b_fname; 10422 break; 10423 10424 case SPEC_HASH: /* '#' or "#99": alternate file */ 10425 if (src[1] == '#') /* "##": the argument list */ 10426 { 10427 result = arg_all(); 10428 resultbuf = result; 10429 *usedlen = 2; 10430 if (escaped != NULL) 10431 *escaped = TRUE; 10432 #ifdef FEAT_MODIFY_FNAME 10433 skip_mod = TRUE; 10434 #endif 10435 break; 10436 } 10437 s = src + 1; 10438 if (*s == '<') /* "#<99" uses v:oldfiles */ 10439 ++s; 10440 i = (int)getdigits(&s); 10441 *usedlen = (int)(s - src); /* length of what we expand */ 10442 10443 if (src[1] == '<') 10444 { 10445 if (*usedlen < 2) 10446 { 10447 /* Should we give an error message for #<text? */ 10448 *usedlen = 1; 10449 return NULL; 10450 } 10451 #ifdef FEAT_EVAL 10452 result = list_find_str(get_vim_var_list(VV_OLDFILES), 10453 (long)i); 10454 if (result == NULL) 10455 { 10456 *errormsg = (char_u *)""; 10457 return NULL; 10458 } 10459 #else 10460 *errormsg = (char_u *)_("E809: #< is not available without the +eval feature"); 10461 return NULL; 10462 #endif 10463 } 10464 else 10465 { 10466 buf = buflist_findnr(i); 10467 if (buf == NULL) 10468 { 10469 *errormsg = (char_u *)_("E194: No alternate file name to substitute for '#'"); 10470 return NULL; 10471 } 10472 if (lnump != NULL) 10473 *lnump = ECMD_LAST; 10474 if (buf->b_fname == NULL) 10475 { 10476 result = (char_u *)""; 10477 valid = 0; /* Must have ":p:h" to be valid */ 10478 } 10479 else 10480 result = buf->b_fname; 10481 } 10482 break; 10483 10484 #ifdef FEAT_SEARCHPATH 10485 case SPEC_CFILE: /* file name under cursor */ 10486 result = file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1L, NULL); 10487 if (result == NULL) 10488 { 10489 *errormsg = (char_u *)""; 10490 return NULL; 10491 } 10492 resultbuf = result; /* remember allocated string */ 10493 break; 10494 #endif 10495 10496 #ifdef FEAT_AUTOCMD 10497 case SPEC_AFILE: /* file name for autocommand */ 10498 result = autocmd_fname; 10499 if (result != NULL && !autocmd_fname_full) 10500 { 10501 /* Still need to turn the fname into a full path. It is 10502 * postponed to avoid a delay when <afile> is not used. */ 10503 autocmd_fname_full = TRUE; 10504 result = FullName_save(autocmd_fname, FALSE); 10505 vim_free(autocmd_fname); 10506 autocmd_fname = result; 10507 } 10508 if (result == NULL) 10509 { 10510 *errormsg = (char_u *)_("E495: no autocommand file name to substitute for \"<afile>\""); 10511 return NULL; 10512 } 10513 result = shorten_fname1(result); 10514 break; 10515 10516 case SPEC_ABUF: /* buffer number for autocommand */ 10517 if (autocmd_bufnr <= 0) 10518 { 10519 *errormsg = (char_u *)_("E496: no autocommand buffer number to substitute for \"<abuf>\""); 10520 return NULL; 10521 } 10522 sprintf((char *)strbuf, "%d", autocmd_bufnr); 10523 result = strbuf; 10524 break; 10525 10526 case SPEC_AMATCH: /* match name for autocommand */ 10527 result = autocmd_match; 10528 if (result == NULL) 10529 { 10530 *errormsg = (char_u *)_("E497: no autocommand match name to substitute for \"<amatch>\""); 10531 return NULL; 10532 } 10533 break; 10534 10535 #endif 10536 case SPEC_SFILE: /* file name for ":so" command */ 10537 result = sourcing_name; 10538 if (result == NULL) 10539 { 10540 *errormsg = (char_u *)_("E498: no :source file name to substitute for \"<sfile>\""); 10541 return NULL; 10542 } 10543 break; 10544 case SPEC_SLNUM: /* line in file for ":so" command */ 10545 if (sourcing_name == NULL || sourcing_lnum == 0) 10546 { 10547 *errormsg = (char_u *)_("E842: no line number to use for \"<slnum>\""); 10548 return NULL; 10549 } 10550 sprintf((char *)strbuf, "%ld", (long)sourcing_lnum); 10551 result = strbuf; 10552 break; 10553 #if defined(FEAT_CLIENTSERVER) 10554 case SPEC_CLIENT: /* Source of last submitted input */ 10555 sprintf((char *)strbuf, PRINTF_HEX_LONG_U, 10556 (long_u)clientWindow); 10557 result = strbuf; 10558 break; 10559 #endif 10560 } 10561 10562 resultlen = (int)STRLEN(result); /* length of new string */ 10563 if (src[*usedlen] == '<') /* remove the file name extension */ 10564 { 10565 ++*usedlen; 10566 if ((s = vim_strrchr(result, '.')) != NULL && s >= gettail(result)) 10567 resultlen = (int)(s - result); 10568 } 10569 #ifdef FEAT_MODIFY_FNAME 10570 else if (!skip_mod) 10571 { 10572 valid |= modify_fname(src, usedlen, &result, &resultbuf, 10573 &resultlen); 10574 if (result == NULL) 10575 { 10576 *errormsg = (char_u *)""; 10577 return NULL; 10578 } 10579 } 10580 #endif 10581 } 10582 10583 if (resultlen == 0 || valid != VALID_HEAD + VALID_PATH) 10584 { 10585 if (valid != VALID_HEAD + VALID_PATH) 10586 /* xgettext:no-c-format */ 10587 *errormsg = (char_u *)_("E499: Empty file name for '%' or '#', only works with \":p:h\""); 10588 else 10589 *errormsg = (char_u *)_("E500: Evaluates to an empty string"); 10590 result = NULL; 10591 } 10592 else 10593 result = vim_strnsave(result, resultlen); 10594 vim_free(resultbuf); 10595 return result; 10596 } 10597 10598 /* 10599 * Concatenate all files in the argument list, separated by spaces, and return 10600 * it in one allocated string. 10601 * Spaces and backslashes in the file names are escaped with a backslash. 10602 * Returns NULL when out of memory. 10603 */ 10604 static char_u * 10605 arg_all(void) 10606 { 10607 int len; 10608 int idx; 10609 char_u *retval = NULL; 10610 char_u *p; 10611 10612 /* 10613 * Do this loop two times: 10614 * first time: compute the total length 10615 * second time: concatenate the names 10616 */ 10617 for (;;) 10618 { 10619 len = 0; 10620 for (idx = 0; idx < ARGCOUNT; ++idx) 10621 { 10622 p = alist_name(&ARGLIST[idx]); 10623 if (p != NULL) 10624 { 10625 if (len > 0) 10626 { 10627 /* insert a space in between names */ 10628 if (retval != NULL) 10629 retval[len] = ' '; 10630 ++len; 10631 } 10632 for ( ; *p != NUL; ++p) 10633 { 10634 if (*p == ' ' 10635 #ifndef BACKSLASH_IN_FILENAME 10636 || *p == '\\' 10637 #endif 10638 ) 10639 { 10640 /* insert a backslash */ 10641 if (retval != NULL) 10642 retval[len] = '\\'; 10643 ++len; 10644 } 10645 if (retval != NULL) 10646 retval[len] = *p; 10647 ++len; 10648 } 10649 } 10650 } 10651 10652 /* second time: break here */ 10653 if (retval != NULL) 10654 { 10655 retval[len] = NUL; 10656 break; 10657 } 10658 10659 /* allocate memory */ 10660 retval = alloc((unsigned)len + 1); 10661 if (retval == NULL) 10662 break; 10663 } 10664 10665 return retval; 10666 } 10667 10668 #if defined(FEAT_AUTOCMD) || defined(PROTO) 10669 /* 10670 * Expand the <sfile> string in "arg". 10671 * 10672 * Returns an allocated string, or NULL for any error. 10673 */ 10674 char_u * 10675 expand_sfile(char_u *arg) 10676 { 10677 char_u *errormsg; 10678 int len; 10679 char_u *result; 10680 char_u *newres; 10681 char_u *repl; 10682 int srclen; 10683 char_u *p; 10684 10685 result = vim_strsave(arg); 10686 if (result == NULL) 10687 return NULL; 10688 10689 for (p = result; *p; ) 10690 { 10691 if (STRNCMP(p, "<sfile>", 7) != 0) 10692 ++p; 10693 else 10694 { 10695 /* replace "<sfile>" with the sourced file name, and do ":" stuff */ 10696 repl = eval_vars(p, result, &srclen, NULL, &errormsg, NULL); 10697 if (errormsg != NULL) 10698 { 10699 if (*errormsg) 10700 emsg(errormsg); 10701 vim_free(result); 10702 return NULL; 10703 } 10704 if (repl == NULL) /* no match (cannot happen) */ 10705 { 10706 p += srclen; 10707 continue; 10708 } 10709 len = (int)STRLEN(result) - srclen + (int)STRLEN(repl) + 1; 10710 newres = alloc(len); 10711 if (newres == NULL) 10712 { 10713 vim_free(repl); 10714 vim_free(result); 10715 return NULL; 10716 } 10717 mch_memmove(newres, result, (size_t)(p - result)); 10718 STRCPY(newres + (p - result), repl); 10719 len = (int)STRLEN(newres); 10720 STRCAT(newres, p + srclen); 10721 vim_free(repl); 10722 vim_free(result); 10723 result = newres; 10724 p = newres + len; /* continue after the match */ 10725 } 10726 } 10727 10728 return result; 10729 } 10730 #endif 10731 10732 #ifdef FEAT_SESSION 10733 static int ses_winsizes(FILE *fd, int restore_size, 10734 win_T *tab_firstwin); 10735 static int ses_win_rec(FILE *fd, frame_T *fr); 10736 static frame_T *ses_skipframe(frame_T *fr); 10737 static int ses_do_frame(frame_T *fr); 10738 static int ses_do_win(win_T *wp); 10739 static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, unsigned *flagp); 10740 static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp); 10741 static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp); 10742 10743 /* 10744 * Write openfile commands for the current buffers to an .exrc file. 10745 * Return FAIL on error, OK otherwise. 10746 */ 10747 static int 10748 makeopens( 10749 FILE *fd, 10750 char_u *dirnow) /* Current directory name */ 10751 { 10752 buf_T *buf; 10753 int only_save_windows = TRUE; 10754 int nr; 10755 int restore_size = TRUE; 10756 win_T *wp; 10757 char_u *sname; 10758 win_T *edited_win = NULL; 10759 int tabnr; 10760 int restore_stal = FALSE; 10761 win_T *tab_firstwin; 10762 frame_T *tab_topframe; 10763 int cur_arg_idx = 0; 10764 int next_arg_idx = 0; 10765 10766 if (ssop_flags & SSOP_BUFFERS) 10767 only_save_windows = FALSE; /* Save ALL buffers */ 10768 10769 /* 10770 * Begin by setting the this_session variable, and then other 10771 * sessionable variables. 10772 */ 10773 #ifdef FEAT_EVAL 10774 if (put_line(fd, "let v:this_session=expand(\"<sfile>:p\")") == FAIL) 10775 return FAIL; 10776 if (ssop_flags & SSOP_GLOBALS) 10777 if (store_session_globals(fd) == FAIL) 10778 return FAIL; 10779 #endif 10780 10781 /* 10782 * Close all windows but one. 10783 */ 10784 if (put_line(fd, "silent only") == FAIL) 10785 return FAIL; 10786 10787 /* 10788 * Now a :cd command to the session directory or the current directory 10789 */ 10790 if (ssop_flags & SSOP_SESDIR) 10791 { 10792 if (put_line(fd, "exe \"cd \" . escape(expand(\"<sfile>:p:h\"), ' ')") 10793 == FAIL) 10794 return FAIL; 10795 } 10796 else if (ssop_flags & SSOP_CURDIR) 10797 { 10798 sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow); 10799 if (sname == NULL 10800 || fputs("cd ", fd) < 0 10801 || ses_put_fname(fd, sname, &ssop_flags) == FAIL 10802 || put_eol(fd) == FAIL) 10803 { 10804 vim_free(sname); 10805 return FAIL; 10806 } 10807 vim_free(sname); 10808 } 10809 10810 /* 10811 * If there is an empty, unnamed buffer we will wipe it out later. 10812 * Remember the buffer number. 10813 */ 10814 if (put_line(fd, "if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''") == FAIL) 10815 return FAIL; 10816 if (put_line(fd, " let s:wipebuf = bufnr('%')") == FAIL) 10817 return FAIL; 10818 if (put_line(fd, "endif") == FAIL) 10819 return FAIL; 10820 10821 /* 10822 * Now save the current files, current buffer first. 10823 */ 10824 if (put_line(fd, "set shortmess=aoO") == FAIL) 10825 return FAIL; 10826 10827 /* Now put the other buffers into the buffer list */ 10828 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 10829 { 10830 if (!(only_save_windows && buf->b_nwindows == 0) 10831 && !(buf->b_help && !(ssop_flags & SSOP_HELP)) 10832 && buf->b_fname != NULL 10833 && buf->b_p_bl) 10834 { 10835 if (fprintf(fd, "badd +%ld ", buf->b_wininfo == NULL ? 1L 10836 : buf->b_wininfo->wi_fpos.lnum) < 0 10837 || ses_fname(fd, buf, &ssop_flags) == FAIL) 10838 return FAIL; 10839 } 10840 } 10841 10842 /* the global argument list */ 10843 if (ses_arglist(fd, "argglobal", &global_alist.al_ga, 10844 !(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL) 10845 return FAIL; 10846 10847 if (ssop_flags & SSOP_RESIZE) 10848 { 10849 /* Note: after the restore we still check it worked!*/ 10850 if (fprintf(fd, "set lines=%ld columns=%ld" , Rows, Columns) < 0 10851 || put_eol(fd) == FAIL) 10852 return FAIL; 10853 } 10854 10855 #ifdef FEAT_GUI 10856 if (gui.in_use && (ssop_flags & SSOP_WINPOS)) 10857 { 10858 int x, y; 10859 10860 if (gui_mch_get_winpos(&x, &y) == OK) 10861 { 10862 /* Note: after the restore we still check it worked!*/ 10863 if (fprintf(fd, "winpos %d %d", x, y) < 0 || put_eol(fd) == FAIL) 10864 return FAIL; 10865 } 10866 } 10867 #endif 10868 10869 /* 10870 * When there are two or more tabpages and 'showtabline' is 1 the tabline 10871 * will be displayed when creating the next tab. That resizes the windows 10872 * in the first tab, which may cause problems. Set 'showtabline' to 2 10873 * temporarily to avoid that. 10874 */ 10875 if (p_stal == 1 && first_tabpage->tp_next != NULL) 10876 { 10877 if (put_line(fd, "set stal=2") == FAIL) 10878 return FAIL; 10879 restore_stal = TRUE; 10880 } 10881 10882 /* 10883 * May repeat putting Windows for each tab, when "tabpages" is in 10884 * 'sessionoptions'. 10885 * Don't use goto_tabpage(), it may change directory and trigger 10886 * autocommands. 10887 */ 10888 tab_firstwin = firstwin; /* first window in tab page "tabnr" */ 10889 tab_topframe = topframe; 10890 for (tabnr = 1; ; ++tabnr) 10891 { 10892 int need_tabnew = FALSE; 10893 int cnr = 1; 10894 10895 if ((ssop_flags & SSOP_TABPAGES)) 10896 { 10897 tabpage_T *tp = find_tabpage(tabnr); 10898 10899 if (tp == NULL) 10900 break; /* done all tab pages */ 10901 if (tp == curtab) 10902 { 10903 tab_firstwin = firstwin; 10904 tab_topframe = topframe; 10905 } 10906 else 10907 { 10908 tab_firstwin = tp->tp_firstwin; 10909 tab_topframe = tp->tp_topframe; 10910 } 10911 if (tabnr > 1) 10912 need_tabnew = TRUE; 10913 } 10914 10915 /* 10916 * Before creating the window layout, try loading one file. If this 10917 * is aborted we don't end up with a number of useless windows. 10918 * This may have side effects! (e.g., compressed or network file). 10919 */ 10920 for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) 10921 { 10922 if (ses_do_win(wp) 10923 && wp->w_buffer->b_ffname != NULL 10924 && !wp->w_buffer->b_help 10925 #ifdef FEAT_QUICKFIX 10926 && !bt_nofile(wp->w_buffer) 10927 #endif 10928 ) 10929 { 10930 if (fputs(need_tabnew ? "tabedit " : "edit ", fd) < 0 10931 || ses_fname(fd, wp->w_buffer, &ssop_flags) == FAIL) 10932 return FAIL; 10933 need_tabnew = FALSE; 10934 if (!wp->w_arg_idx_invalid) 10935 edited_win = wp; 10936 break; 10937 } 10938 } 10939 10940 /* If no file got edited create an empty tab page. */ 10941 if (need_tabnew && put_line(fd, "tabnew") == FAIL) 10942 return FAIL; 10943 10944 /* 10945 * Save current window layout. 10946 */ 10947 if (put_line(fd, "set splitbelow splitright") == FAIL) 10948 return FAIL; 10949 if (ses_win_rec(fd, tab_topframe) == FAIL) 10950 return FAIL; 10951 if (!p_sb && put_line(fd, "set nosplitbelow") == FAIL) 10952 return FAIL; 10953 if (!p_spr && put_line(fd, "set nosplitright") == FAIL) 10954 return FAIL; 10955 10956 /* 10957 * Check if window sizes can be restored (no windows omitted). 10958 * Remember the window number of the current window after restoring. 10959 */ 10960 nr = 0; 10961 for (wp = tab_firstwin; wp != NULL; wp = W_NEXT(wp)) 10962 { 10963 if (ses_do_win(wp)) 10964 ++nr; 10965 else 10966 restore_size = FALSE; 10967 if (curwin == wp) 10968 cnr = nr; 10969 } 10970 10971 /* Go to the first window. */ 10972 if (put_line(fd, "wincmd t") == FAIL) 10973 return FAIL; 10974 10975 /* 10976 * If more than one window, see if sizes can be restored. 10977 * First set 'winheight' and 'winwidth' to 1 to avoid the windows being 10978 * resized when moving between windows. 10979 * Do this before restoring the view, so that the topline and the 10980 * cursor can be set. This is done again below. 10981 */ 10982 if (put_line(fd, "set winheight=1 winwidth=1") == FAIL) 10983 return FAIL; 10984 if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) 10985 return FAIL; 10986 10987 /* 10988 * Restore the view of the window (options, file, cursor, etc.). 10989 */ 10990 for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) 10991 { 10992 if (!ses_do_win(wp)) 10993 continue; 10994 if (put_view(fd, wp, wp != edited_win, &ssop_flags, 10995 cur_arg_idx) == FAIL) 10996 return FAIL; 10997 if (nr > 1 && put_line(fd, "wincmd w") == FAIL) 10998 return FAIL; 10999 next_arg_idx = wp->w_arg_idx; 11000 } 11001 11002 /* The argument index in the first tab page is zero, need to set it in 11003 * each window. For further tab pages it's the window where we do 11004 * "tabedit". */ 11005 cur_arg_idx = next_arg_idx; 11006 11007 /* 11008 * Restore cursor to the current window if it's not the first one. 11009 */ 11010 if (cnr > 1 && (fprintf(fd, "%dwincmd w", cnr) < 0 11011 || put_eol(fd) == FAIL)) 11012 return FAIL; 11013 11014 /* 11015 * Restore window sizes again after jumping around in windows, because 11016 * the current window has a minimum size while others may not. 11017 */ 11018 if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) 11019 return FAIL; 11020 11021 /* Don't continue in another tab page when doing only the current one 11022 * or when at the last tab page. */ 11023 if (!(ssop_flags & SSOP_TABPAGES)) 11024 break; 11025 } 11026 11027 if (ssop_flags & SSOP_TABPAGES) 11028 { 11029 if (fprintf(fd, "tabnext %d", tabpage_index(curtab)) < 0 11030 || put_eol(fd) == FAIL) 11031 return FAIL; 11032 } 11033 if (restore_stal && put_line(fd, "set stal=1") == FAIL) 11034 return FAIL; 11035 11036 /* 11037 * Wipe out an empty unnamed buffer we started in. 11038 */ 11039 if (put_line(fd, "if exists('s:wipebuf')") == FAIL) 11040 return FAIL; 11041 if (put_line(fd, " silent exe 'bwipe ' . s:wipebuf") == FAIL) 11042 return FAIL; 11043 if (put_line(fd, "endif") == FAIL) 11044 return FAIL; 11045 if (put_line(fd, "unlet! s:wipebuf") == FAIL) 11046 return FAIL; 11047 11048 /* Re-apply 'winheight', 'winwidth' and 'shortmess'. */ 11049 if (fprintf(fd, "set winheight=%ld winwidth=%ld shortmess=%s", 11050 p_wh, p_wiw, p_shm) < 0 || put_eol(fd) == FAIL) 11051 return FAIL; 11052 11053 /* 11054 * Lastly, execute the x.vim file if it exists. 11055 */ 11056 if (put_line(fd, "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"") == FAIL 11057 || put_line(fd, "if file_readable(s:sx)") == FAIL 11058 || put_line(fd, " exe \"source \" . fnameescape(s:sx)") == FAIL 11059 || put_line(fd, "endif") == FAIL) 11060 return FAIL; 11061 11062 return OK; 11063 } 11064 11065 static int 11066 ses_winsizes( 11067 FILE *fd, 11068 int restore_size, 11069 win_T *tab_firstwin) 11070 { 11071 int n = 0; 11072 win_T *wp; 11073 11074 if (restore_size && (ssop_flags & SSOP_WINSIZE)) 11075 { 11076 for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) 11077 { 11078 if (!ses_do_win(wp)) 11079 continue; 11080 ++n; 11081 11082 /* restore height when not full height */ 11083 if (wp->w_height + wp->w_status_height < topframe->fr_height 11084 && (fprintf(fd, 11085 "exe '%dresize ' . ((&lines * %ld + %ld) / %ld)", 11086 n, (long)wp->w_height, Rows / 2, Rows) < 0 11087 || put_eol(fd) == FAIL)) 11088 return FAIL; 11089 11090 /* restore width when not full width */ 11091 if (wp->w_width < Columns && (fprintf(fd, 11092 "exe 'vert %dresize ' . ((&columns * %ld + %ld) / %ld)", 11093 n, (long)wp->w_width, Columns / 2, Columns) < 0 11094 || put_eol(fd) == FAIL)) 11095 return FAIL; 11096 } 11097 } 11098 else 11099 { 11100 /* Just equalise window sizes */ 11101 if (put_line(fd, "wincmd =") == FAIL) 11102 return FAIL; 11103 } 11104 return OK; 11105 } 11106 11107 /* 11108 * Write commands to "fd" to recursively create windows for frame "fr", 11109 * horizontally and vertically split. 11110 * After the commands the last window in the frame is the current window. 11111 * Returns FAIL when writing the commands to "fd" fails. 11112 */ 11113 static int 11114 ses_win_rec(FILE *fd, frame_T *fr) 11115 { 11116 frame_T *frc; 11117 int count = 0; 11118 11119 if (fr->fr_layout != FR_LEAF) 11120 { 11121 /* Find first frame that's not skipped and then create a window for 11122 * each following one (first frame is already there). */ 11123 frc = ses_skipframe(fr->fr_child); 11124 if (frc != NULL) 11125 while ((frc = ses_skipframe(frc->fr_next)) != NULL) 11126 { 11127 /* Make window as big as possible so that we have lots of room 11128 * to split. */ 11129 if (put_line(fd, "wincmd _ | wincmd |") == FAIL 11130 || put_line(fd, fr->fr_layout == FR_COL 11131 ? "split" : "vsplit") == FAIL) 11132 return FAIL; 11133 ++count; 11134 } 11135 11136 /* Go back to the first window. */ 11137 if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL 11138 ? "%dwincmd k" : "%dwincmd h", count) < 0 11139 || put_eol(fd) == FAIL)) 11140 return FAIL; 11141 11142 /* Recursively create frames/windows in each window of this column or 11143 * row. */ 11144 frc = ses_skipframe(fr->fr_child); 11145 while (frc != NULL) 11146 { 11147 ses_win_rec(fd, frc); 11148 frc = ses_skipframe(frc->fr_next); 11149 /* Go to next window. */ 11150 if (frc != NULL && put_line(fd, "wincmd w") == FAIL) 11151 return FAIL; 11152 } 11153 } 11154 return OK; 11155 } 11156 11157 /* 11158 * Skip frames that don't contain windows we want to save in the Session. 11159 * Returns NULL when there none. 11160 */ 11161 static frame_T * 11162 ses_skipframe(frame_T *fr) 11163 { 11164 frame_T *frc; 11165 11166 for (frc = fr; frc != NULL; frc = frc->fr_next) 11167 if (ses_do_frame(frc)) 11168 break; 11169 return frc; 11170 } 11171 11172 /* 11173 * Return TRUE if frame "fr" has a window somewhere that we want to save in 11174 * the Session. 11175 */ 11176 static int 11177 ses_do_frame(frame_T *fr) 11178 { 11179 frame_T *frc; 11180 11181 if (fr->fr_layout == FR_LEAF) 11182 return ses_do_win(fr->fr_win); 11183 for (frc = fr->fr_child; frc != NULL; frc = frc->fr_next) 11184 if (ses_do_frame(frc)) 11185 return TRUE; 11186 return FALSE; 11187 } 11188 11189 /* 11190 * Return non-zero if window "wp" is to be stored in the Session. 11191 */ 11192 static int 11193 ses_do_win(win_T *wp) 11194 { 11195 if (wp->w_buffer->b_fname == NULL 11196 #ifdef FEAT_QUICKFIX 11197 /* When 'buftype' is "nofile" can't restore the window contents. */ 11198 || bt_nofile(wp->w_buffer) 11199 #endif 11200 ) 11201 return (ssop_flags & SSOP_BLANK); 11202 if (wp->w_buffer->b_help) 11203 return (ssop_flags & SSOP_HELP); 11204 return TRUE; 11205 } 11206 11207 /* 11208 * Write commands to "fd" to restore the view of a window. 11209 * Caller must make sure 'scrolloff' is zero. 11210 */ 11211 static int 11212 put_view( 11213 FILE *fd, 11214 win_T *wp, 11215 int add_edit, /* add ":edit" command to view */ 11216 unsigned *flagp, /* vop_flags or ssop_flags */ 11217 int current_arg_idx) /* current argument index of the window, use 11218 * -1 if unknown */ 11219 { 11220 win_T *save_curwin; 11221 int f; 11222 int do_cursor; 11223 int did_next = FALSE; 11224 11225 /* Always restore cursor position for ":mksession". For ":mkview" only 11226 * when 'viewoptions' contains "cursor". */ 11227 do_cursor = (flagp == &ssop_flags || *flagp & SSOP_CURSOR); 11228 11229 /* 11230 * Local argument list. 11231 */ 11232 if (wp->w_alist == &global_alist) 11233 { 11234 if (put_line(fd, "argglobal") == FAIL) 11235 return FAIL; 11236 } 11237 else 11238 { 11239 if (ses_arglist(fd, "arglocal", &wp->w_alist->al_ga, 11240 flagp == &vop_flags 11241 || !(*flagp & SSOP_CURDIR) 11242 || wp->w_localdir != NULL, flagp) == FAIL) 11243 return FAIL; 11244 } 11245 11246 /* Only when part of a session: restore the argument index. Some 11247 * arguments may have been deleted, check if the index is valid. */ 11248 if (wp->w_arg_idx != current_arg_idx && wp->w_arg_idx < WARGCOUNT(wp) 11249 && flagp == &ssop_flags) 11250 { 11251 if (fprintf(fd, "%ldargu", (long)wp->w_arg_idx + 1) < 0 11252 || put_eol(fd) == FAIL) 11253 return FAIL; 11254 did_next = TRUE; 11255 } 11256 11257 /* Edit the file. Skip this when ":next" already did it. */ 11258 if (add_edit && (!did_next || wp->w_arg_idx_invalid)) 11259 { 11260 /* 11261 * Load the file. 11262 */ 11263 if (wp->w_buffer->b_ffname != NULL 11264 #ifdef FEAT_QUICKFIX 11265 && !bt_nofile(wp->w_buffer) 11266 #endif 11267 ) 11268 { 11269 /* 11270 * Editing a file in this buffer: use ":edit file". 11271 * This may have side effects! (e.g., compressed or network file). 11272 */ 11273 if (fputs("edit ", fd) < 0 11274 || ses_fname(fd, wp->w_buffer, flagp) == FAIL) 11275 return FAIL; 11276 } 11277 else 11278 { 11279 /* No file in this buffer, just make it empty. */ 11280 if (put_line(fd, "enew") == FAIL) 11281 return FAIL; 11282 #ifdef FEAT_QUICKFIX 11283 if (wp->w_buffer->b_ffname != NULL) 11284 { 11285 /* The buffer does have a name, but it's not a file name. */ 11286 if (fputs("file ", fd) < 0 11287 || ses_fname(fd, wp->w_buffer, flagp) == FAIL) 11288 return FAIL; 11289 } 11290 #endif 11291 do_cursor = FALSE; 11292 } 11293 } 11294 11295 /* 11296 * Local mappings and abbreviations. 11297 */ 11298 if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) 11299 && makemap(fd, wp->w_buffer) == FAIL) 11300 return FAIL; 11301 11302 /* 11303 * Local options. Need to go to the window temporarily. 11304 * Store only local values when using ":mkview" and when ":mksession" is 11305 * used and 'sessionoptions' doesn't include "options". 11306 * Some folding options are always stored when "folds" is included, 11307 * otherwise the folds would not be restored correctly. 11308 */ 11309 save_curwin = curwin; 11310 curwin = wp; 11311 curbuf = curwin->w_buffer; 11312 if (*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS)) 11313 f = makeset(fd, OPT_LOCAL, 11314 flagp == &vop_flags || !(*flagp & SSOP_OPTIONS)); 11315 #ifdef FEAT_FOLDING 11316 else if (*flagp & SSOP_FOLDS) 11317 f = makefoldset(fd); 11318 #endif 11319 else 11320 f = OK; 11321 curwin = save_curwin; 11322 curbuf = curwin->w_buffer; 11323 if (f == FAIL) 11324 return FAIL; 11325 11326 #ifdef FEAT_FOLDING 11327 /* 11328 * Save Folds when 'buftype' is empty and for help files. 11329 */ 11330 if ((*flagp & SSOP_FOLDS) 11331 && wp->w_buffer->b_ffname != NULL 11332 # ifdef FEAT_QUICKFIX 11333 && (*wp->w_buffer->b_p_bt == NUL || wp->w_buffer->b_help) 11334 # endif 11335 ) 11336 { 11337 if (put_folds(fd, wp) == FAIL) 11338 return FAIL; 11339 } 11340 #endif 11341 11342 /* 11343 * Set the cursor after creating folds, since that moves the cursor. 11344 */ 11345 if (do_cursor) 11346 { 11347 11348 /* Restore the cursor line in the file and relatively in the 11349 * window. Don't use "G", it changes the jumplist. */ 11350 if (fprintf(fd, "let s:l = %ld - ((%ld * winheight(0) + %ld) / %ld)", 11351 (long)wp->w_cursor.lnum, 11352 (long)(wp->w_cursor.lnum - wp->w_topline), 11353 (long)wp->w_height / 2, (long)wp->w_height) < 0 11354 || put_eol(fd) == FAIL 11355 || put_line(fd, "if s:l < 1 | let s:l = 1 | endif") == FAIL 11356 || put_line(fd, "exe s:l") == FAIL 11357 || put_line(fd, "normal! zt") == FAIL 11358 || fprintf(fd, "%ld", (long)wp->w_cursor.lnum) < 0 11359 || put_eol(fd) == FAIL) 11360 return FAIL; 11361 /* Restore the cursor column and left offset when not wrapping. */ 11362 if (wp->w_cursor.col == 0) 11363 { 11364 if (put_line(fd, "normal! 0") == FAIL) 11365 return FAIL; 11366 } 11367 else 11368 { 11369 if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0) 11370 { 11371 if (fprintf(fd, 11372 "let s:c = %ld - ((%ld * winwidth(0) + %ld) / %ld)", 11373 (long)wp->w_virtcol + 1, 11374 (long)(wp->w_virtcol - wp->w_leftcol), 11375 (long)wp->w_width / 2, (long)wp->w_width) < 0 11376 || put_eol(fd) == FAIL 11377 || put_line(fd, "if s:c > 0") == FAIL 11378 || fprintf(fd, 11379 " exe 'normal! ' . s:c . '|zs' . %ld . '|'", 11380 (long)wp->w_virtcol + 1) < 0 11381 || put_eol(fd) == FAIL 11382 || put_line(fd, "else") == FAIL 11383 || fprintf(fd, " normal! 0%d|", wp->w_virtcol + 1) < 0 11384 || put_eol(fd) == FAIL 11385 || put_line(fd, "endif") == FAIL) 11386 return FAIL; 11387 } 11388 else 11389 { 11390 if (fprintf(fd, "normal! 0%d|", wp->w_virtcol + 1) < 0 11391 || put_eol(fd) == FAIL) 11392 return FAIL; 11393 } 11394 } 11395 } 11396 11397 /* 11398 * Local directory. 11399 */ 11400 if (wp->w_localdir != NULL) 11401 { 11402 if (fputs("lcd ", fd) < 0 11403 || ses_put_fname(fd, wp->w_localdir, flagp) == FAIL 11404 || put_eol(fd) == FAIL) 11405 return FAIL; 11406 did_lcd = TRUE; 11407 } 11408 11409 return OK; 11410 } 11411 11412 /* 11413 * Write an argument list to the session file. 11414 * Returns FAIL if writing fails. 11415 */ 11416 static int 11417 ses_arglist( 11418 FILE *fd, 11419 char *cmd, 11420 garray_T *gap, 11421 int fullname, /* TRUE: use full path name */ 11422 unsigned *flagp) 11423 { 11424 int i; 11425 char_u *buf = NULL; 11426 char_u *s; 11427 11428 if (fputs(cmd, fd) < 0 || put_eol(fd) == FAIL) 11429 return FAIL; 11430 if (put_line(fd, "silent! argdel *") == FAIL) 11431 return FAIL; 11432 for (i = 0; i < gap->ga_len; ++i) 11433 { 11434 /* NULL file names are skipped (only happens when out of memory). */ 11435 s = alist_name(&((aentry_T *)gap->ga_data)[i]); 11436 if (s != NULL) 11437 { 11438 if (fullname) 11439 { 11440 buf = alloc(MAXPATHL); 11441 if (buf != NULL) 11442 { 11443 (void)vim_FullName(s, buf, MAXPATHL, FALSE); 11444 s = buf; 11445 } 11446 } 11447 if (fputs("argadd ", fd) < 0 11448 || ses_put_fname(fd, s, flagp) == FAIL 11449 || put_eol(fd) == FAIL) 11450 { 11451 vim_free(buf); 11452 return FAIL; 11453 } 11454 vim_free(buf); 11455 } 11456 } 11457 return OK; 11458 } 11459 11460 /* 11461 * Write a buffer name to the session file. 11462 * Also ends the line. 11463 * Returns FAIL if writing fails. 11464 */ 11465 static int 11466 ses_fname(FILE *fd, buf_T *buf, unsigned *flagp) 11467 { 11468 char_u *name; 11469 11470 /* Use the short file name if the current directory is known at the time 11471 * the session file will be sourced. 11472 * Don't do this for ":mkview", we don't know the current directory. 11473 * Don't do this after ":lcd", we don't keep track of what the current 11474 * directory is. */ 11475 if (buf->b_sfname != NULL 11476 && flagp == &ssop_flags 11477 && (ssop_flags & (SSOP_CURDIR | SSOP_SESDIR)) 11478 #ifdef FEAT_AUTOCHDIR 11479 && !p_acd 11480 #endif 11481 && !did_lcd) 11482 name = buf->b_sfname; 11483 else 11484 name = buf->b_ffname; 11485 if (ses_put_fname(fd, name, flagp) == FAIL || put_eol(fd) == FAIL) 11486 return FAIL; 11487 return OK; 11488 } 11489 11490 /* 11491 * Write a file name to the session file. 11492 * Takes care of the "slash" option in 'sessionoptions' and escapes special 11493 * characters. 11494 * Returns FAIL if writing fails or out of memory. 11495 */ 11496 static int 11497 ses_put_fname(FILE *fd, char_u *name, unsigned *flagp) 11498 { 11499 char_u *sname; 11500 char_u *p; 11501 int retval = OK; 11502 11503 sname = home_replace_save(NULL, name); 11504 if (sname == NULL) 11505 return FAIL; 11506 11507 if (*flagp & SSOP_SLASH) 11508 { 11509 /* change all backslashes to forward slashes */ 11510 for (p = sname; *p != NUL; mb_ptr_adv(p)) 11511 if (*p == '\\') 11512 *p = '/'; 11513 } 11514 11515 /* escape special characters */ 11516 p = vim_strsave_fnameescape(sname, FALSE); 11517 vim_free(sname); 11518 if (p == NULL) 11519 return FAIL; 11520 11521 /* write the result */ 11522 if (fputs((char *)p, fd) < 0) 11523 retval = FAIL; 11524 11525 vim_free(p); 11526 return retval; 11527 } 11528 11529 /* 11530 * ":loadview [nr]" 11531 */ 11532 static void 11533 ex_loadview(exarg_T *eap) 11534 { 11535 char_u *fname; 11536 11537 fname = get_view_file(*eap->arg); 11538 if (fname != NULL) 11539 { 11540 do_source(fname, FALSE, DOSO_NONE); 11541 vim_free(fname); 11542 } 11543 } 11544 11545 /* 11546 * Get the name of the view file for the current buffer. 11547 */ 11548 static char_u * 11549 get_view_file(int c) 11550 { 11551 int len = 0; 11552 char_u *p, *s; 11553 char_u *retval; 11554 char_u *sname; 11555 11556 if (curbuf->b_ffname == NULL) 11557 { 11558 EMSG(_(e_noname)); 11559 return NULL; 11560 } 11561 sname = home_replace_save(NULL, curbuf->b_ffname); 11562 if (sname == NULL) 11563 return NULL; 11564 11565 /* 11566 * We want a file name without separators, because we're not going to make 11567 * a directory. 11568 * "normal" path separator -> "=+" 11569 * "=" -> "==" 11570 * ":" path separator -> "=-" 11571 */ 11572 for (p = sname; *p; ++p) 11573 if (*p == '=' || vim_ispathsep(*p)) 11574 ++len; 11575 retval = alloc((unsigned)(STRLEN(sname) + len + STRLEN(p_vdir) + 9)); 11576 if (retval != NULL) 11577 { 11578 STRCPY(retval, p_vdir); 11579 add_pathsep(retval); 11580 s = retval + STRLEN(retval); 11581 for (p = sname; *p; ++p) 11582 { 11583 if (*p == '=') 11584 { 11585 *s++ = '='; 11586 *s++ = '='; 11587 } 11588 else if (vim_ispathsep(*p)) 11589 { 11590 *s++ = '='; 11591 #if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA) || defined(VMS) 11592 if (*p == ':') 11593 *s++ = '-'; 11594 else 11595 #endif 11596 *s++ = '+'; 11597 } 11598 else 11599 *s++ = *p; 11600 } 11601 *s++ = '='; 11602 *s++ = c; 11603 STRCPY(s, ".vim"); 11604 } 11605 11606 vim_free(sname); 11607 return retval; 11608 } 11609 11610 #endif /* FEAT_SESSION */ 11611 11612 /* 11613 * Write end-of-line character(s) for ":mkexrc", ":mkvimrc" and ":mksession". 11614 * Return FAIL for a write error. 11615 */ 11616 int 11617 put_eol(FILE *fd) 11618 { 11619 if ( 11620 #ifdef USE_CRNL 11621 ( 11622 # ifdef MKSESSION_NL 11623 !mksession_nl && 11624 # endif 11625 (putc('\r', fd) < 0)) || 11626 #endif 11627 (putc('\n', fd) < 0)) 11628 return FAIL; 11629 return OK; 11630 } 11631 11632 /* 11633 * Write a line to "fd". 11634 * Return FAIL for a write error. 11635 */ 11636 int 11637 put_line(FILE *fd, char *s) 11638 { 11639 if (fputs(s, fd) < 0 || put_eol(fd) == FAIL) 11640 return FAIL; 11641 return OK; 11642 } 11643 11644 #ifdef FEAT_VIMINFO 11645 /* 11646 * ":rviminfo" and ":wviminfo". 11647 */ 11648 static void 11649 ex_viminfo( 11650 exarg_T *eap) 11651 { 11652 char_u *save_viminfo; 11653 11654 save_viminfo = p_viminfo; 11655 if (*p_viminfo == NUL) 11656 p_viminfo = (char_u *)"'100"; 11657 if (eap->cmdidx == CMD_rviminfo) 11658 { 11659 if (read_viminfo(eap->arg, VIF_WANT_INFO | VIF_WANT_MARKS 11660 | (eap->forceit ? VIF_FORCEIT : 0)) == FAIL) 11661 EMSG(_("E195: Cannot open viminfo file for reading")); 11662 } 11663 else 11664 write_viminfo(eap->arg, eap->forceit); 11665 p_viminfo = save_viminfo; 11666 } 11667 #endif 11668 11669 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO) 11670 /* 11671 * Make a dialog message in "buff[DIALOG_MSG_SIZE]". 11672 * "format" must contain "%s". 11673 */ 11674 void 11675 dialog_msg(char_u *buff, char *format, char_u *fname) 11676 { 11677 if (fname == NULL) 11678 fname = (char_u *)_("Untitled"); 11679 vim_snprintf((char *)buff, DIALOG_MSG_SIZE, format, fname); 11680 } 11681 #endif 11682 11683 /* 11684 * ":behave {mswin,xterm}" 11685 */ 11686 static void 11687 ex_behave(exarg_T *eap) 11688 { 11689 if (STRCMP(eap->arg, "mswin") == 0) 11690 { 11691 set_option_value((char_u *)"selection", 0L, (char_u *)"exclusive", 0); 11692 set_option_value((char_u *)"selectmode", 0L, (char_u *)"mouse,key", 0); 11693 set_option_value((char_u *)"mousemodel", 0L, (char_u *)"popup", 0); 11694 set_option_value((char_u *)"keymodel", 0L, 11695 (char_u *)"startsel,stopsel", 0); 11696 } 11697 else if (STRCMP(eap->arg, "xterm") == 0) 11698 { 11699 set_option_value((char_u *)"selection", 0L, (char_u *)"inclusive", 0); 11700 set_option_value((char_u *)"selectmode", 0L, (char_u *)"", 0); 11701 set_option_value((char_u *)"mousemodel", 0L, (char_u *)"extend", 0); 11702 set_option_value((char_u *)"keymodel", 0L, (char_u *)"", 0); 11703 } 11704 else 11705 EMSG2(_(e_invarg2), eap->arg); 11706 } 11707 11708 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 11709 /* 11710 * Function given to ExpandGeneric() to obtain the possible arguments of the 11711 * ":behave {mswin,xterm}" command. 11712 */ 11713 char_u * 11714 get_behave_arg(expand_T *xp UNUSED, int idx) 11715 { 11716 if (idx == 0) 11717 return (char_u *)"mswin"; 11718 if (idx == 1) 11719 return (char_u *)"xterm"; 11720 return NULL; 11721 } 11722 #endif 11723 11724 #ifdef FEAT_AUTOCMD 11725 static int filetype_detect = FALSE; 11726 static int filetype_plugin = FALSE; 11727 static int filetype_indent = FALSE; 11728 11729 /* 11730 * ":filetype [plugin] [indent] {on,off,detect}" 11731 * on: Load the filetype.vim file to install autocommands for file types. 11732 * off: Load the ftoff.vim file to remove all autocommands for file types. 11733 * plugin on: load filetype.vim and ftplugin.vim 11734 * plugin off: load ftplugof.vim 11735 * indent on: load filetype.vim and indent.vim 11736 * indent off: load indoff.vim 11737 */ 11738 static void 11739 ex_filetype(exarg_T *eap) 11740 { 11741 char_u *arg = eap->arg; 11742 int plugin = FALSE; 11743 int indent = FALSE; 11744 11745 if (*eap->arg == NUL) 11746 { 11747 /* Print current status. */ 11748 smsg((char_u *)"filetype detection:%s plugin:%s indent:%s", 11749 filetype_detect ? "ON" : "OFF", 11750 filetype_plugin ? (filetype_detect ? "ON" : "(on)") : "OFF", 11751 filetype_indent ? (filetype_detect ? "ON" : "(on)") : "OFF"); 11752 return; 11753 } 11754 11755 /* Accept "plugin" and "indent" in any order. */ 11756 for (;;) 11757 { 11758 if (STRNCMP(arg, "plugin", 6) == 0) 11759 { 11760 plugin = TRUE; 11761 arg = skipwhite(arg + 6); 11762 continue; 11763 } 11764 if (STRNCMP(arg, "indent", 6) == 0) 11765 { 11766 indent = TRUE; 11767 arg = skipwhite(arg + 6); 11768 continue; 11769 } 11770 break; 11771 } 11772 if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0) 11773 { 11774 if (*arg == 'o' || !filetype_detect) 11775 { 11776 source_runtime((char_u *)FILETYPE_FILE, DIP_ALL); 11777 filetype_detect = TRUE; 11778 if (plugin) 11779 { 11780 source_runtime((char_u *)FTPLUGIN_FILE, DIP_ALL); 11781 filetype_plugin = TRUE; 11782 } 11783 if (indent) 11784 { 11785 source_runtime((char_u *)INDENT_FILE, DIP_ALL); 11786 filetype_indent = TRUE; 11787 } 11788 } 11789 if (*arg == 'd') 11790 { 11791 (void)do_doautocmd((char_u *)"filetypedetect BufRead", TRUE); 11792 do_modelines(0); 11793 } 11794 } 11795 else if (STRCMP(arg, "off") == 0) 11796 { 11797 if (plugin || indent) 11798 { 11799 if (plugin) 11800 { 11801 source_runtime((char_u *)FTPLUGOF_FILE, DIP_ALL); 11802 filetype_plugin = FALSE; 11803 } 11804 if (indent) 11805 { 11806 source_runtime((char_u *)INDOFF_FILE, DIP_ALL); 11807 filetype_indent = FALSE; 11808 } 11809 } 11810 else 11811 { 11812 source_runtime((char_u *)FTOFF_FILE, DIP_ALL); 11813 filetype_detect = FALSE; 11814 } 11815 } 11816 else 11817 EMSG2(_(e_invarg2), arg); 11818 } 11819 11820 /* 11821 * ":setfiletype {name}" 11822 */ 11823 static void 11824 ex_setfiletype(exarg_T *eap) 11825 { 11826 if (!did_filetype) 11827 set_option_value((char_u *)"filetype", 0L, eap->arg, OPT_LOCAL); 11828 } 11829 #endif 11830 11831 static void 11832 ex_digraphs(exarg_T *eap UNUSED) 11833 { 11834 #ifdef FEAT_DIGRAPHS 11835 if (*eap->arg != NUL) 11836 putdigraph(eap->arg); 11837 else 11838 listdigraphs(); 11839 #else 11840 EMSG(_("E196: No digraphs in this version")); 11841 #endif 11842 } 11843 11844 static void 11845 ex_set(exarg_T *eap) 11846 { 11847 int flags = 0; 11848 11849 if (eap->cmdidx == CMD_setlocal) 11850 flags = OPT_LOCAL; 11851 else if (eap->cmdidx == CMD_setglobal) 11852 flags = OPT_GLOBAL; 11853 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD) && defined(FEAT_BROWSE) 11854 if (cmdmod.browse && flags == 0) 11855 ex_options(eap); 11856 else 11857 #endif 11858 (void)do_set(eap->arg, flags); 11859 } 11860 11861 #ifdef FEAT_SEARCH_EXTRA 11862 /* 11863 * ":nohlsearch" 11864 */ 11865 static void 11866 ex_nohlsearch(exarg_T *eap UNUSED) 11867 { 11868 SET_NO_HLSEARCH(TRUE); 11869 redraw_all_later(SOME_VALID); 11870 } 11871 11872 /* 11873 * ":[N]match {group} {pattern}" 11874 * Sets nextcmd to the start of the next command, if any. Also called when 11875 * skipping commands to find the next command. 11876 */ 11877 static void 11878 ex_match(exarg_T *eap) 11879 { 11880 char_u *p; 11881 char_u *g = NULL; 11882 char_u *end; 11883 int c; 11884 int id; 11885 11886 if (eap->line2 <= 3) 11887 id = eap->line2; 11888 else 11889 { 11890 EMSG(e_invcmd); 11891 return; 11892 } 11893 11894 /* First clear any old pattern. */ 11895 if (!eap->skip) 11896 match_delete(curwin, id, FALSE); 11897 11898 if (ends_excmd(*eap->arg)) 11899 end = eap->arg; 11900 else if ((STRNICMP(eap->arg, "none", 4) == 0 11901 && (vim_iswhite(eap->arg[4]) || ends_excmd(eap->arg[4])))) 11902 end = eap->arg + 4; 11903 else 11904 { 11905 p = skiptowhite(eap->arg); 11906 if (!eap->skip) 11907 g = vim_strnsave(eap->arg, (int)(p - eap->arg)); 11908 p = skipwhite(p); 11909 if (*p == NUL) 11910 { 11911 /* There must be two arguments. */ 11912 vim_free(g); 11913 EMSG2(_(e_invarg2), eap->arg); 11914 return; 11915 } 11916 end = skip_regexp(p + 1, *p, TRUE, NULL); 11917 if (!eap->skip) 11918 { 11919 if (*end != NUL && !ends_excmd(*skipwhite(end + 1))) 11920 { 11921 vim_free(g); 11922 eap->errmsg = e_trailing; 11923 return; 11924 } 11925 if (*end != *p) 11926 { 11927 vim_free(g); 11928 EMSG2(_(e_invarg2), p); 11929 return; 11930 } 11931 11932 c = *end; 11933 *end = NUL; 11934 match_add(curwin, g, p + 1, 10, id, NULL, NULL); 11935 vim_free(g); 11936 *end = c; 11937 } 11938 } 11939 eap->nextcmd = find_nextcmd(end); 11940 } 11941 #endif 11942 11943 #ifdef FEAT_CRYPT 11944 /* 11945 * ":X": Get crypt key 11946 */ 11947 static void 11948 ex_X(exarg_T *eap UNUSED) 11949 { 11950 crypt_check_current_method(); 11951 (void)crypt_get_key(TRUE, TRUE); 11952 } 11953 #endif 11954 11955 #ifdef FEAT_FOLDING 11956 static void 11957 ex_fold(exarg_T *eap) 11958 { 11959 if (foldManualAllowed(TRUE)) 11960 foldCreate(eap->line1, eap->line2); 11961 } 11962 11963 static void 11964 ex_foldopen(exarg_T *eap) 11965 { 11966 opFoldRange(eap->line1, eap->line2, eap->cmdidx == CMD_foldopen, 11967 eap->forceit, FALSE); 11968 } 11969 11970 static void 11971 ex_folddo(exarg_T *eap) 11972 { 11973 linenr_T lnum; 11974 11975 #ifdef FEAT_CLIPBOARD 11976 start_global_changes(); 11977 #endif 11978 11979 /* First set the marks for all lines closed/open. */ 11980 for (lnum = eap->line1; lnum <= eap->line2; ++lnum) 11981 if (hasFolding(lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed)) 11982 ml_setmarked(lnum); 11983 11984 /* Execute the command on the marked lines. */ 11985 global_exe(eap->arg); 11986 ml_clearmarked(); /* clear rest of the marks */ 11987 #ifdef FEAT_CLIPBOARD 11988 end_global_changes(); 11989 #endif 11990 } 11991 #endif 11992