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