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