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