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_cmds2.c: some more functions for command line commands 12 */ 13 14#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64) 15# include "vimio.h" /* for mch_open(), must be before vim.h */ 16#endif 17 18#include "vim.h" 19#include "version.h" 20 21static void cmd_source __ARGS((char_u *fname, exarg_T *eap)); 22 23#ifdef FEAT_EVAL 24/* Growarray to store info about already sourced scripts. 25 * For Unix also store the dev/ino, so that we don't have to stat() each 26 * script when going through the list. */ 27typedef struct scriptitem_S 28{ 29 char_u *sn_name; 30# ifdef UNIX 31 int sn_dev_valid; 32 dev_t sn_dev; 33 ino_t sn_ino; 34# endif 35# ifdef FEAT_PROFILE 36 int sn_prof_on; /* TRUE when script is/was profiled */ 37 int sn_pr_force; /* forceit: profile functions in this script */ 38 proftime_T sn_pr_child; /* time set when going into first child */ 39 int sn_pr_nest; /* nesting for sn_pr_child */ 40 /* profiling the script as a whole */ 41 int sn_pr_count; /* nr of times sourced */ 42 proftime_T sn_pr_total; /* time spent in script + children */ 43 proftime_T sn_pr_self; /* time spent in script itself */ 44 proftime_T sn_pr_start; /* time at script start */ 45 proftime_T sn_pr_children; /* time in children after script start */ 46 /* profiling the script per line */ 47 garray_T sn_prl_ga; /* things stored for every line */ 48 proftime_T sn_prl_start; /* start time for current line */ 49 proftime_T sn_prl_children; /* time spent in children for this line */ 50 proftime_T sn_prl_wait; /* wait start time for current line */ 51 int sn_prl_idx; /* index of line being timed; -1 if none */ 52 int sn_prl_execed; /* line being timed was executed */ 53# endif 54} scriptitem_T; 55 56static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL}; 57#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1]) 58 59# ifdef FEAT_PROFILE 60/* Struct used in sn_prl_ga for every line of a script. */ 61typedef struct sn_prl_S 62{ 63 int snp_count; /* nr of times line was executed */ 64 proftime_T sn_prl_total; /* time spent in a line + children */ 65 proftime_T sn_prl_self; /* time spent in a line itself */ 66} sn_prl_T; 67 68# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)]) 69# endif 70#endif 71 72#if defined(FEAT_EVAL) || defined(PROTO) 73static int debug_greedy = FALSE; /* batch mode debugging: don't save 74 and restore typeahead. */ 75 76/* 77 * do_debug(): Debug mode. 78 * Repeatedly get Ex commands, until told to continue normal execution. 79 */ 80 void 81do_debug(cmd) 82 char_u *cmd; 83{ 84 int save_msg_scroll = msg_scroll; 85 int save_State = State; 86 int save_did_emsg = did_emsg; 87 int save_cmd_silent = cmd_silent; 88 int save_msg_silent = msg_silent; 89 int save_emsg_silent = emsg_silent; 90 int save_redir_off = redir_off; 91 tasave_T typeaheadbuf; 92 int typeahead_saved = FALSE; 93 int save_ignore_script = 0; 94# ifdef FEAT_EX_EXTRA 95 int save_ex_normal_busy; 96# endif 97 int n; 98 char_u *cmdline = NULL; 99 char_u *p; 100 char *tail = NULL; 101 static int last_cmd = 0; 102#define CMD_CONT 1 103#define CMD_NEXT 2 104#define CMD_STEP 3 105#define CMD_FINISH 4 106#define CMD_QUIT 5 107#define CMD_INTERRUPT 6 108 109#ifdef ALWAYS_USE_GUI 110 /* Can't do this when there is no terminal for input/output. */ 111 if (!gui.in_use) 112 { 113 /* Break as soon as possible. */ 114 debug_break_level = 9999; 115 return; 116 } 117#endif 118 119 /* Make sure we are in raw mode and start termcap mode. Might have side 120 * effects... */ 121 settmode(TMODE_RAW); 122 starttermcap(); 123 124 ++RedrawingDisabled; /* don't redisplay the window */ 125 ++no_wait_return; /* don't wait for return */ 126 did_emsg = FALSE; /* don't use error from debugged stuff */ 127 cmd_silent = FALSE; /* display commands */ 128 msg_silent = FALSE; /* display messages */ 129 emsg_silent = FALSE; /* display error messages */ 130 redir_off = TRUE; /* don't redirect debug commands */ 131 132 State = NORMAL; 133#ifdef FEAT_SNIFF 134 want_sniff_request = 0; /* No K_SNIFF wanted */ 135#endif 136 137 if (!debug_did_msg) 138 MSG(_("Entering Debug mode. Type \"cont\" to continue.")); 139 if (sourcing_name != NULL) 140 msg(sourcing_name); 141 if (sourcing_lnum != 0) 142 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd); 143 else 144 smsg((char_u *)_("cmd: %s"), cmd); 145 146 /* 147 * Repeat getting a command and executing it. 148 */ 149 for (;;) 150 { 151 msg_scroll = TRUE; 152 need_wait_return = FALSE; 153#ifdef FEAT_SNIFF 154 ProcessSniffRequests(); 155#endif 156 /* Save the current typeahead buffer and replace it with an empty one. 157 * This makes sure we get input from the user here and don't interfere 158 * with the commands being executed. Reset "ex_normal_busy" to avoid 159 * the side effects of using ":normal". Save the stuff buffer and make 160 * it empty. Set ignore_script to avoid reading from script input. */ 161# ifdef FEAT_EX_EXTRA 162 save_ex_normal_busy = ex_normal_busy; 163 ex_normal_busy = 0; 164# endif 165 if (!debug_greedy) 166 { 167 save_typeahead(&typeaheadbuf); 168 typeahead_saved = TRUE; 169 save_ignore_script = ignore_script; 170 ignore_script = TRUE; 171 } 172 173 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL); 174 175 if (typeahead_saved) 176 { 177 restore_typeahead(&typeaheadbuf); 178 ignore_script = save_ignore_script; 179 } 180# ifdef FEAT_EX_EXTRA 181 ex_normal_busy = save_ex_normal_busy; 182# endif 183 184 cmdline_row = msg_row; 185 if (cmdline != NULL) 186 { 187 /* If this is a debug command, set "last_cmd". 188 * If not, reset "last_cmd". 189 * For a blank line use previous command. */ 190 p = skipwhite(cmdline); 191 if (*p != NUL) 192 { 193 switch (*p) 194 { 195 case 'c': last_cmd = CMD_CONT; 196 tail = "ont"; 197 break; 198 case 'n': last_cmd = CMD_NEXT; 199 tail = "ext"; 200 break; 201 case 's': last_cmd = CMD_STEP; 202 tail = "tep"; 203 break; 204 case 'f': last_cmd = CMD_FINISH; 205 tail = "inish"; 206 break; 207 case 'q': last_cmd = CMD_QUIT; 208 tail = "uit"; 209 break; 210 case 'i': last_cmd = CMD_INTERRUPT; 211 tail = "nterrupt"; 212 break; 213 default: last_cmd = 0; 214 } 215 if (last_cmd != 0) 216 { 217 /* Check that the tail matches. */ 218 ++p; 219 while (*p != NUL && *p == *tail) 220 { 221 ++p; 222 ++tail; 223 } 224 if (ASCII_ISALPHA(*p)) 225 last_cmd = 0; 226 } 227 } 228 229 if (last_cmd != 0) 230 { 231 /* Execute debug command: decided where to break next and 232 * return. */ 233 switch (last_cmd) 234 { 235 case CMD_CONT: 236 debug_break_level = -1; 237 break; 238 case CMD_NEXT: 239 debug_break_level = ex_nesting_level; 240 break; 241 case CMD_STEP: 242 debug_break_level = 9999; 243 break; 244 case CMD_FINISH: 245 debug_break_level = ex_nesting_level - 1; 246 break; 247 case CMD_QUIT: 248 got_int = TRUE; 249 debug_break_level = -1; 250 break; 251 case CMD_INTERRUPT: 252 got_int = TRUE; 253 debug_break_level = 9999; 254 /* Do not repeat ">interrupt" cmd, continue stepping. */ 255 last_cmd = CMD_STEP; 256 break; 257 } 258 break; 259 } 260 261 /* don't debug this command */ 262 n = debug_break_level; 263 debug_break_level = -1; 264 (void)do_cmdline(cmdline, getexline, NULL, 265 DOCMD_VERBOSE|DOCMD_EXCRESET); 266 debug_break_level = n; 267 268 vim_free(cmdline); 269 } 270 lines_left = Rows - 1; 271 } 272 vim_free(cmdline); 273 274 --RedrawingDisabled; 275 --no_wait_return; 276 redraw_all_later(NOT_VALID); 277 need_wait_return = FALSE; 278 msg_scroll = save_msg_scroll; 279 lines_left = Rows - 1; 280 State = save_State; 281 did_emsg = save_did_emsg; 282 cmd_silent = save_cmd_silent; 283 msg_silent = save_msg_silent; 284 emsg_silent = save_emsg_silent; 285 redir_off = save_redir_off; 286 287 /* Only print the message again when typing a command before coming back 288 * here. */ 289 debug_did_msg = TRUE; 290} 291 292/* 293 * ":debug". 294 */ 295 void 296ex_debug(eap) 297 exarg_T *eap; 298{ 299 int debug_break_level_save = debug_break_level; 300 301 debug_break_level = 9999; 302 do_cmdline_cmd(eap->arg); 303 debug_break_level = debug_break_level_save; 304} 305 306static char_u *debug_breakpoint_name = NULL; 307static linenr_T debug_breakpoint_lnum; 308 309/* 310 * When debugging or a breakpoint is set on a skipped command, no debug prompt 311 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and 312 * debug_skipped_name is then set to the source name in the breakpoint case. If 313 * a skipped command decides itself that a debug prompt should be displayed, it 314 * can do so by calling dbg_check_skipped(). 315 */ 316static int debug_skipped; 317static char_u *debug_skipped_name; 318 319/* 320 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is 321 * at or below the break level. But only when the line is actually 322 * executed. Return TRUE and set breakpoint_name for skipped commands that 323 * decide to execute something themselves. 324 * Called from do_one_cmd() before executing a command. 325 */ 326 void 327dbg_check_breakpoint(eap) 328 exarg_T *eap; 329{ 330 char_u *p; 331 332 debug_skipped = FALSE; 333 if (debug_breakpoint_name != NULL) 334 { 335 if (!eap->skip) 336 { 337 /* replace K_SNR with "<SNR>" */ 338 if (debug_breakpoint_name[0] == K_SPECIAL 339 && debug_breakpoint_name[1] == KS_EXTRA 340 && debug_breakpoint_name[2] == (int)KE_SNR) 341 p = (char_u *)"<SNR>"; 342 else 343 p = (char_u *)""; 344 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"), 345 p, 346 debug_breakpoint_name + (*p == NUL ? 0 : 3), 347 (long)debug_breakpoint_lnum); 348 debug_breakpoint_name = NULL; 349 do_debug(eap->cmd); 350 } 351 else 352 { 353 debug_skipped = TRUE; 354 debug_skipped_name = debug_breakpoint_name; 355 debug_breakpoint_name = NULL; 356 } 357 } 358 else if (ex_nesting_level <= debug_break_level) 359 { 360 if (!eap->skip) 361 do_debug(eap->cmd); 362 else 363 { 364 debug_skipped = TRUE; 365 debug_skipped_name = NULL; 366 } 367 } 368} 369 370/* 371 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was 372 * set. Return TRUE when the debug mode is entered this time. 373 */ 374 int 375dbg_check_skipped(eap) 376 exarg_T *eap; 377{ 378 int prev_got_int; 379 380 if (debug_skipped) 381 { 382 /* 383 * Save the value of got_int and reset it. We don't want a previous 384 * interruption cause flushing the input buffer. 385 */ 386 prev_got_int = got_int; 387 got_int = FALSE; 388 debug_breakpoint_name = debug_skipped_name; 389 /* eap->skip is TRUE */ 390 eap->skip = FALSE; 391 (void)dbg_check_breakpoint(eap); 392 eap->skip = TRUE; 393 got_int |= prev_got_int; 394 return TRUE; 395 } 396 return FALSE; 397} 398 399/* 400 * The list of breakpoints: dbg_breakp. 401 * This is a grow-array of structs. 402 */ 403struct debuggy 404{ 405 int dbg_nr; /* breakpoint number */ 406 int dbg_type; /* DBG_FUNC or DBG_FILE */ 407 char_u *dbg_name; /* function or file name */ 408 regprog_T *dbg_prog; /* regexp program */ 409 linenr_T dbg_lnum; /* line number in function or file */ 410 int dbg_forceit; /* ! used */ 411}; 412 413static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL}; 414#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx]) 415#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx]) 416static int last_breakp = 0; /* nr of last defined breakpoint */ 417 418#ifdef FEAT_PROFILE 419/* Profiling uses file and func names similar to breakpoints. */ 420static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL}; 421#endif 422#define DBG_FUNC 1 423#define DBG_FILE 2 424 425static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap)); 426static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, garray_T *gap, int *fp)); 427 428/* 429 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them 430 * in the entry just after the last one in dbg_breakp. Note that "dbg_name" 431 * is allocated. 432 * Returns FAIL for failure. 433 */ 434 static int 435dbg_parsearg(arg, gap) 436 char_u *arg; 437 garray_T *gap; /* either &dbg_breakp or &prof_ga */ 438{ 439 char_u *p = arg; 440 char_u *q; 441 struct debuggy *bp; 442 int here = FALSE; 443 444 if (ga_grow(gap, 1) == FAIL) 445 return FAIL; 446 bp = &DEBUGGY(gap, gap->ga_len); 447 448 /* Find "func" or "file". */ 449 if (STRNCMP(p, "func", 4) == 0) 450 bp->dbg_type = DBG_FUNC; 451 else if (STRNCMP(p, "file", 4) == 0) 452 bp->dbg_type = DBG_FILE; 453 else if ( 454#ifdef FEAT_PROFILE 455 gap != &prof_ga && 456#endif 457 STRNCMP(p, "here", 4) == 0) 458 { 459 if (curbuf->b_ffname == NULL) 460 { 461 EMSG(_(e_noname)); 462 return FAIL; 463 } 464 bp->dbg_type = DBG_FILE; 465 here = TRUE; 466 } 467 else 468 { 469 EMSG2(_(e_invarg2), p); 470 return FAIL; 471 } 472 p = skipwhite(p + 4); 473 474 /* Find optional line number. */ 475 if (here) 476 bp->dbg_lnum = curwin->w_cursor.lnum; 477 else if ( 478#ifdef FEAT_PROFILE 479 gap != &prof_ga && 480#endif 481 VIM_ISDIGIT(*p)) 482 { 483 bp->dbg_lnum = getdigits(&p); 484 p = skipwhite(p); 485 } 486 else 487 bp->dbg_lnum = 0; 488 489 /* Find the function or file name. Don't accept a function name with (). */ 490 if ((!here && *p == NUL) 491 || (here && *p != NUL) 492 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL)) 493 { 494 EMSG2(_(e_invarg2), arg); 495 return FAIL; 496 } 497 498 if (bp->dbg_type == DBG_FUNC) 499 bp->dbg_name = vim_strsave(p); 500 else if (here) 501 bp->dbg_name = vim_strsave(curbuf->b_ffname); 502 else 503 { 504 /* Expand the file name in the same way as do_source(). This means 505 * doing it twice, so that $DIR/file gets expanded when $DIR is 506 * "~/dir". */ 507#ifdef RISCOS 508 q = mch_munge_fname(p); 509#else 510 q = expand_env_save(p); 511#endif 512 if (q == NULL) 513 return FAIL; 514#ifdef RISCOS 515 p = mch_munge_fname(q); 516#else 517 p = expand_env_save(q); 518#endif 519 vim_free(q); 520 if (p == NULL) 521 return FAIL; 522 if (*p != '*') 523 { 524 bp->dbg_name = fix_fname(p); 525 vim_free(p); 526 } 527 else 528 bp->dbg_name = p; 529 } 530 531 if (bp->dbg_name == NULL) 532 return FAIL; 533 return OK; 534} 535 536/* 537 * ":breakadd". 538 */ 539 void 540ex_breakadd(eap) 541 exarg_T *eap; 542{ 543 struct debuggy *bp; 544 char_u *pat; 545 garray_T *gap; 546 547 gap = &dbg_breakp; 548#ifdef FEAT_PROFILE 549 if (eap->cmdidx == CMD_profile) 550 gap = &prof_ga; 551#endif 552 553 if (dbg_parsearg(eap->arg, gap) == OK) 554 { 555 bp = &DEBUGGY(gap, gap->ga_len); 556 bp->dbg_forceit = eap->forceit; 557 558 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE); 559 if (pat != NULL) 560 { 561 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 562 vim_free(pat); 563 } 564 if (pat == NULL || bp->dbg_prog == NULL) 565 vim_free(bp->dbg_name); 566 else 567 { 568 if (bp->dbg_lnum == 0) /* default line number is 1 */ 569 bp->dbg_lnum = 1; 570#ifdef FEAT_PROFILE 571 if (eap->cmdidx != CMD_profile) 572#endif 573 { 574 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp; 575 ++debug_tick; 576 } 577 ++gap->ga_len; 578 } 579 } 580} 581 582/* 583 * ":debuggreedy". 584 */ 585 void 586ex_debuggreedy(eap) 587 exarg_T *eap; 588{ 589 if (eap->addr_count == 0 || eap->line2 != 0) 590 debug_greedy = TRUE; 591 else 592 debug_greedy = FALSE; 593} 594 595/* 596 * ":breakdel" and ":profdel". 597 */ 598 void 599ex_breakdel(eap) 600 exarg_T *eap; 601{ 602 struct debuggy *bp, *bpi; 603 int nr; 604 int todel = -1; 605 int del_all = FALSE; 606 int i; 607 linenr_T best_lnum = 0; 608 garray_T *gap; 609 610 gap = &dbg_breakp; 611#ifdef FEAT_PROFILE 612 if (eap->cmdidx == CMD_profdel) 613 gap = &prof_ga; 614#endif 615 616 if (vim_isdigit(*eap->arg)) 617 { 618 /* ":breakdel {nr}" */ 619 nr = atol((char *)eap->arg); 620 for (i = 0; i < gap->ga_len; ++i) 621 if (DEBUGGY(gap, i).dbg_nr == nr) 622 { 623 todel = i; 624 break; 625 } 626 } 627 else if (*eap->arg == '*') 628 { 629 todel = 0; 630 del_all = TRUE; 631 } 632 else 633 { 634 /* ":breakdel {func|file} [lnum] {name}" */ 635 if (dbg_parsearg(eap->arg, gap) == FAIL) 636 return; 637 bp = &DEBUGGY(gap, gap->ga_len); 638 for (i = 0; i < gap->ga_len; ++i) 639 { 640 bpi = &DEBUGGY(gap, i); 641 if (bp->dbg_type == bpi->dbg_type 642 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0 643 && (bp->dbg_lnum == bpi->dbg_lnum 644 || (bp->dbg_lnum == 0 645 && (best_lnum == 0 646 || bpi->dbg_lnum < best_lnum)))) 647 { 648 todel = i; 649 best_lnum = bpi->dbg_lnum; 650 } 651 } 652 vim_free(bp->dbg_name); 653 } 654 655 if (todel < 0) 656 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg); 657 else 658 { 659 while (gap->ga_len > 0) 660 { 661 vim_free(DEBUGGY(gap, todel).dbg_name); 662 vim_free(DEBUGGY(gap, todel).dbg_prog); 663 --gap->ga_len; 664 if (todel < gap->ga_len) 665 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1), 666 (gap->ga_len - todel) * sizeof(struct debuggy)); 667#ifdef FEAT_PROFILE 668 if (eap->cmdidx == CMD_breakdel) 669#endif 670 ++debug_tick; 671 if (!del_all) 672 break; 673 } 674 675 /* If all breakpoints were removed clear the array. */ 676 if (gap->ga_len == 0) 677 ga_clear(gap); 678 } 679} 680 681/* 682 * ":breaklist". 683 */ 684 void 685ex_breaklist(eap) 686 exarg_T *eap UNUSED; 687{ 688 struct debuggy *bp; 689 int i; 690 691 if (dbg_breakp.ga_len == 0) 692 MSG(_("No breakpoints defined")); 693 else 694 for (i = 0; i < dbg_breakp.ga_len; ++i) 695 { 696 bp = &BREAKP(i); 697 smsg((char_u *)_("%3d %s %s line %ld"), 698 bp->dbg_nr, 699 bp->dbg_type == DBG_FUNC ? "func" : "file", 700 bp->dbg_name, 701 (long)bp->dbg_lnum); 702 } 703} 704 705/* 706 * Find a breakpoint for a function or sourced file. 707 * Returns line number at which to break; zero when no matching breakpoint. 708 */ 709 linenr_T 710dbg_find_breakpoint(file, fname, after) 711 int file; /* TRUE for a file, FALSE for a function */ 712 char_u *fname; /* file or function name */ 713 linenr_T after; /* after this line number */ 714{ 715 return debuggy_find(file, fname, after, &dbg_breakp, NULL); 716} 717 718#if defined(FEAT_PROFILE) || defined(PROTO) 719/* 720 * Return TRUE if profiling is on for a function or sourced file. 721 */ 722 int 723has_profiling(file, fname, fp) 724 int file; /* TRUE for a file, FALSE for a function */ 725 char_u *fname; /* file or function name */ 726 int *fp; /* return: forceit */ 727{ 728 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp) 729 != (linenr_T)0); 730} 731#endif 732 733/* 734 * Common code for dbg_find_breakpoint() and has_profiling(). 735 */ 736 static linenr_T 737debuggy_find(file, fname, after, gap, fp) 738 int file; /* TRUE for a file, FALSE for a function */ 739 char_u *fname; /* file or function name */ 740 linenr_T after; /* after this line number */ 741 garray_T *gap; /* either &dbg_breakp or &prof_ga */ 742 int *fp; /* if not NULL: return forceit */ 743{ 744 struct debuggy *bp; 745 int i; 746 linenr_T lnum = 0; 747 regmatch_T regmatch; 748 char_u *name = fname; 749 int prev_got_int; 750 751 /* Return quickly when there are no breakpoints. */ 752 if (gap->ga_len == 0) 753 return (linenr_T)0; 754 755 /* Replace K_SNR in function name with "<SNR>". */ 756 if (!file && fname[0] == K_SPECIAL) 757 { 758 name = alloc((unsigned)STRLEN(fname) + 3); 759 if (name == NULL) 760 name = fname; 761 else 762 { 763 STRCPY(name, "<SNR>"); 764 STRCPY(name + 5, fname + 3); 765 } 766 } 767 768 for (i = 0; i < gap->ga_len; ++i) 769 { 770 /* Skip entries that are not useful or are for a line that is beyond 771 * an already found breakpoint. */ 772 bp = &DEBUGGY(gap, i); 773 if (((bp->dbg_type == DBG_FILE) == file && ( 774#ifdef FEAT_PROFILE 775 gap == &prof_ga || 776#endif 777 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum))))) 778 { 779 regmatch.regprog = bp->dbg_prog; 780 regmatch.rm_ic = FALSE; 781 /* 782 * Save the value of got_int and reset it. We don't want a 783 * previous interruption cancel matching, only hitting CTRL-C 784 * while matching should abort it. 785 */ 786 prev_got_int = got_int; 787 got_int = FALSE; 788 if (vim_regexec(®match, name, (colnr_T)0)) 789 { 790 lnum = bp->dbg_lnum; 791 if (fp != NULL) 792 *fp = bp->dbg_forceit; 793 } 794 got_int |= prev_got_int; 795 } 796 } 797 if (name != fname) 798 vim_free(name); 799 800 return lnum; 801} 802 803/* 804 * Called when a breakpoint was encountered. 805 */ 806 void 807dbg_breakpoint(name, lnum) 808 char_u *name; 809 linenr_T lnum; 810{ 811 /* We need to check if this line is actually executed in do_one_cmd() */ 812 debug_breakpoint_name = name; 813 debug_breakpoint_lnum = lnum; 814} 815 816 817# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO) 818/* 819 * Store the current time in "tm". 820 */ 821 void 822profile_start(tm) 823 proftime_T *tm; 824{ 825# ifdef WIN3264 826 QueryPerformanceCounter(tm); 827# else 828 gettimeofday(tm, NULL); 829# endif 830} 831 832/* 833 * Compute the elapsed time from "tm" till now and store in "tm". 834 */ 835 void 836profile_end(tm) 837 proftime_T *tm; 838{ 839 proftime_T now; 840 841# ifdef WIN3264 842 QueryPerformanceCounter(&now); 843 tm->QuadPart = now.QuadPart - tm->QuadPart; 844# else 845 gettimeofday(&now, NULL); 846 tm->tv_usec = now.tv_usec - tm->tv_usec; 847 tm->tv_sec = now.tv_sec - tm->tv_sec; 848 if (tm->tv_usec < 0) 849 { 850 tm->tv_usec += 1000000; 851 --tm->tv_sec; 852 } 853# endif 854} 855 856/* 857 * Subtract the time "tm2" from "tm". 858 */ 859 void 860profile_sub(tm, tm2) 861 proftime_T *tm, *tm2; 862{ 863# ifdef WIN3264 864 tm->QuadPart -= tm2->QuadPart; 865# else 866 tm->tv_usec -= tm2->tv_usec; 867 tm->tv_sec -= tm2->tv_sec; 868 if (tm->tv_usec < 0) 869 { 870 tm->tv_usec += 1000000; 871 --tm->tv_sec; 872 } 873# endif 874} 875 876/* 877 * Return a string that represents the time in "tm". 878 * Uses a static buffer! 879 */ 880 char * 881profile_msg(tm) 882 proftime_T *tm; 883{ 884 static char buf[50]; 885 886# ifdef WIN3264 887 LARGE_INTEGER fr; 888 889 QueryPerformanceFrequency(&fr); 890 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart); 891# else 892 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec); 893# endif 894 return buf; 895} 896 897/* 898 * Put the time "msec" past now in "tm". 899 */ 900 void 901profile_setlimit(msec, tm) 902 long msec; 903 proftime_T *tm; 904{ 905 if (msec <= 0) /* no limit */ 906 profile_zero(tm); 907 else 908 { 909# ifdef WIN3264 910 LARGE_INTEGER fr; 911 912 QueryPerformanceCounter(tm); 913 QueryPerformanceFrequency(&fr); 914 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart); 915# else 916 long usec; 917 918 gettimeofday(tm, NULL); 919 usec = (long)tm->tv_usec + (long)msec * 1000; 920 tm->tv_usec = usec % 1000000L; 921 tm->tv_sec += usec / 1000000L; 922# endif 923 } 924} 925 926/* 927 * Return TRUE if the current time is past "tm". 928 */ 929 int 930profile_passed_limit(tm) 931 proftime_T *tm; 932{ 933 proftime_T now; 934 935# ifdef WIN3264 936 if (tm->QuadPart == 0) /* timer was not set */ 937 return FALSE; 938 QueryPerformanceCounter(&now); 939 return (now.QuadPart > tm->QuadPart); 940# else 941 if (tm->tv_sec == 0) /* timer was not set */ 942 return FALSE; 943 gettimeofday(&now, NULL); 944 return (now.tv_sec > tm->tv_sec 945 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec)); 946# endif 947} 948 949/* 950 * Set the time in "tm" to zero. 951 */ 952 void 953profile_zero(tm) 954 proftime_T *tm; 955{ 956# ifdef WIN3264 957 tm->QuadPart = 0; 958# else 959 tm->tv_usec = 0; 960 tm->tv_sec = 0; 961# endif 962} 963 964# endif /* FEAT_PROFILE || FEAT_RELTIME */ 965 966# if defined(FEAT_PROFILE) || defined(PROTO) 967/* 968 * Functions for profiling. 969 */ 970static void script_do_profile __ARGS((scriptitem_T *si)); 971static void script_dump_profile __ARGS((FILE *fd)); 972static proftime_T prof_wait_time; 973 974/* 975 * Add the time "tm2" to "tm". 976 */ 977 void 978profile_add(tm, tm2) 979 proftime_T *tm, *tm2; 980{ 981# ifdef WIN3264 982 tm->QuadPart += tm2->QuadPart; 983# else 984 tm->tv_usec += tm2->tv_usec; 985 tm->tv_sec += tm2->tv_sec; 986 if (tm->tv_usec >= 1000000) 987 { 988 tm->tv_usec -= 1000000; 989 ++tm->tv_sec; 990 } 991# endif 992} 993 994/* 995 * Add the "self" time from the total time and the children's time. 996 */ 997 void 998profile_self(self, total, children) 999 proftime_T *self, *total, *children; 1000{ 1001 /* Check that the result won't be negative. Can happen with recursive 1002 * calls. */ 1003#ifdef WIN3264 1004 if (total->QuadPart <= children->QuadPart) 1005 return; 1006#else 1007 if (total->tv_sec < children->tv_sec 1008 || (total->tv_sec == children->tv_sec 1009 && total->tv_usec <= children->tv_usec)) 1010 return; 1011#endif 1012 profile_add(self, total); 1013 profile_sub(self, children); 1014} 1015 1016/* 1017 * Get the current waittime. 1018 */ 1019 void 1020profile_get_wait(tm) 1021 proftime_T *tm; 1022{ 1023 *tm = prof_wait_time; 1024} 1025 1026/* 1027 * Subtract the passed waittime since "tm" from "tma". 1028 */ 1029 void 1030profile_sub_wait(tm, tma) 1031 proftime_T *tm, *tma; 1032{ 1033 proftime_T tm3 = prof_wait_time; 1034 1035 profile_sub(&tm3, tm); 1036 profile_sub(tma, &tm3); 1037} 1038 1039/* 1040 * Return TRUE if "tm1" and "tm2" are equal. 1041 */ 1042 int 1043profile_equal(tm1, tm2) 1044 proftime_T *tm1, *tm2; 1045{ 1046# ifdef WIN3264 1047 return (tm1->QuadPart == tm2->QuadPart); 1048# else 1049 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec); 1050# endif 1051} 1052 1053/* 1054 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2" 1055 */ 1056 int 1057profile_cmp(tm1, tm2) 1058 proftime_T *tm1, *tm2; 1059{ 1060# ifdef WIN3264 1061 return (int)(tm2->QuadPart - tm1->QuadPart); 1062# else 1063 if (tm1->tv_sec == tm2->tv_sec) 1064 return tm2->tv_usec - tm1->tv_usec; 1065 return tm2->tv_sec - tm1->tv_sec; 1066# endif 1067} 1068 1069static char_u *profile_fname = NULL; 1070static proftime_T pause_time; 1071 1072/* 1073 * ":profile cmd args" 1074 */ 1075 void 1076ex_profile(eap) 1077 exarg_T *eap; 1078{ 1079 char_u *e; 1080 int len; 1081 1082 e = skiptowhite(eap->arg); 1083 len = (int)(e - eap->arg); 1084 e = skipwhite(e); 1085 1086 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL) 1087 { 1088 vim_free(profile_fname); 1089 profile_fname = vim_strsave(e); 1090 do_profiling = PROF_YES; 1091 profile_zero(&prof_wait_time); 1092 set_vim_var_nr(VV_PROFILING, 1L); 1093 } 1094 else if (do_profiling == PROF_NONE) 1095 EMSG(_("E750: First use \":profile start {fname}\"")); 1096 else if (STRCMP(eap->arg, "pause") == 0) 1097 { 1098 if (do_profiling == PROF_YES) 1099 profile_start(&pause_time); 1100 do_profiling = PROF_PAUSED; 1101 } 1102 else if (STRCMP(eap->arg, "continue") == 0) 1103 { 1104 if (do_profiling == PROF_PAUSED) 1105 { 1106 profile_end(&pause_time); 1107 profile_add(&prof_wait_time, &pause_time); 1108 } 1109 do_profiling = PROF_YES; 1110 } 1111 else 1112 { 1113 /* The rest is similar to ":breakadd". */ 1114 ex_breakadd(eap); 1115 } 1116} 1117 1118/* Command line expansion for :profile. */ 1119static enum 1120{ 1121 PEXP_SUBCMD, /* expand :profile sub-commands */ 1122 PEXP_FUNC, /* expand :profile func {funcname} */ 1123} pexpand_what; 1124 1125static char *pexpand_cmds[] = { 1126 "start", 1127#define PROFCMD_START 0 1128 "pause", 1129#define PROFCMD_PAUSE 1 1130 "continue", 1131#define PROFCMD_CONTINUE 2 1132 "func", 1133#define PROFCMD_FUNC 3 1134 "file", 1135#define PROFCMD_FILE 4 1136 NULL 1137#define PROFCMD_LAST 5 1138}; 1139 1140/* 1141 * Function given to ExpandGeneric() to obtain the profile command 1142 * specific expansion. 1143 */ 1144 char_u * 1145get_profile_name(xp, idx) 1146 expand_T *xp UNUSED; 1147 int idx; 1148{ 1149 switch (pexpand_what) 1150 { 1151 case PEXP_SUBCMD: 1152 return (char_u *)pexpand_cmds[idx]; 1153 /* case PEXP_FUNC: TODO */ 1154 default: 1155 return NULL; 1156 } 1157} 1158 1159/* 1160 * Handle command line completion for :profile command. 1161 */ 1162 void 1163set_context_in_profile_cmd(xp, arg) 1164 expand_T *xp; 1165 char_u *arg; 1166{ 1167 char_u *end_subcmd; 1168 1169 /* Default: expand subcommands. */ 1170 xp->xp_context = EXPAND_PROFILE; 1171 pexpand_what = PEXP_SUBCMD; 1172 xp->xp_pattern = arg; 1173 1174 end_subcmd = skiptowhite(arg); 1175 if (*end_subcmd == NUL) 1176 return; 1177 1178 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0) 1179 { 1180 xp->xp_context = EXPAND_FILES; 1181 xp->xp_pattern = skipwhite(end_subcmd); 1182 return; 1183 } 1184 1185 /* TODO: expand function names after "func" */ 1186 xp->xp_context = EXPAND_NOTHING; 1187} 1188 1189/* 1190 * Dump the profiling info. 1191 */ 1192 void 1193profile_dump() 1194{ 1195 FILE *fd; 1196 1197 if (profile_fname != NULL) 1198 { 1199 fd = mch_fopen((char *)profile_fname, "w"); 1200 if (fd == NULL) 1201 EMSG2(_(e_notopen), profile_fname); 1202 else 1203 { 1204 script_dump_profile(fd); 1205 func_dump_profile(fd); 1206 fclose(fd); 1207 } 1208 } 1209} 1210 1211/* 1212 * Start profiling script "fp". 1213 */ 1214 static void 1215script_do_profile(si) 1216 scriptitem_T *si; 1217{ 1218 si->sn_pr_count = 0; 1219 profile_zero(&si->sn_pr_total); 1220 profile_zero(&si->sn_pr_self); 1221 1222 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100); 1223 si->sn_prl_idx = -1; 1224 si->sn_prof_on = TRUE; 1225 si->sn_pr_nest = 0; 1226} 1227 1228/* 1229 * save time when starting to invoke another script or function. 1230 */ 1231 void 1232script_prof_save(tm) 1233 proftime_T *tm; /* place to store wait time */ 1234{ 1235 scriptitem_T *si; 1236 1237 if (current_SID > 0 && current_SID <= script_items.ga_len) 1238 { 1239 si = &SCRIPT_ITEM(current_SID); 1240 if (si->sn_prof_on && si->sn_pr_nest++ == 0) 1241 profile_start(&si->sn_pr_child); 1242 } 1243 profile_get_wait(tm); 1244} 1245 1246/* 1247 * Count time spent in children after invoking another script or function. 1248 */ 1249 void 1250script_prof_restore(tm) 1251 proftime_T *tm; 1252{ 1253 scriptitem_T *si; 1254 1255 if (current_SID > 0 && current_SID <= script_items.ga_len) 1256 { 1257 si = &SCRIPT_ITEM(current_SID); 1258 if (si->sn_prof_on && --si->sn_pr_nest == 0) 1259 { 1260 profile_end(&si->sn_pr_child); 1261 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */ 1262 profile_add(&si->sn_pr_children, &si->sn_pr_child); 1263 profile_add(&si->sn_prl_children, &si->sn_pr_child); 1264 } 1265 } 1266} 1267 1268static proftime_T inchar_time; 1269 1270/* 1271 * Called when starting to wait for the user to type a character. 1272 */ 1273 void 1274prof_inchar_enter() 1275{ 1276 profile_start(&inchar_time); 1277} 1278 1279/* 1280 * Called when finished waiting for the user to type a character. 1281 */ 1282 void 1283prof_inchar_exit() 1284{ 1285 profile_end(&inchar_time); 1286 profile_add(&prof_wait_time, &inchar_time); 1287} 1288 1289/* 1290 * Dump the profiling results for all scripts in file "fd". 1291 */ 1292 static void 1293script_dump_profile(fd) 1294 FILE *fd; 1295{ 1296 int id; 1297 scriptitem_T *si; 1298 int i; 1299 FILE *sfd; 1300 sn_prl_T *pp; 1301 1302 for (id = 1; id <= script_items.ga_len; ++id) 1303 { 1304 si = &SCRIPT_ITEM(id); 1305 if (si->sn_prof_on) 1306 { 1307 fprintf(fd, "SCRIPT %s\n", si->sn_name); 1308 if (si->sn_pr_count == 1) 1309 fprintf(fd, "Sourced 1 time\n"); 1310 else 1311 fprintf(fd, "Sourced %d times\n", si->sn_pr_count); 1312 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total)); 1313 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self)); 1314 fprintf(fd, "\n"); 1315 fprintf(fd, "count total (s) self (s)\n"); 1316 1317 sfd = mch_fopen((char *)si->sn_name, "r"); 1318 if (sfd == NULL) 1319 fprintf(fd, "Cannot open file!\n"); 1320 else 1321 { 1322 for (i = 0; i < si->sn_prl_ga.ga_len; ++i) 1323 { 1324 if (vim_fgets(IObuff, IOSIZE, sfd)) 1325 break; 1326 pp = &PRL_ITEM(si, i); 1327 if (pp->snp_count > 0) 1328 { 1329 fprintf(fd, "%5d ", pp->snp_count); 1330 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self)) 1331 fprintf(fd, " "); 1332 else 1333 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total)); 1334 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self)); 1335 } 1336 else 1337 fprintf(fd, " "); 1338 fprintf(fd, "%s", IObuff); 1339 } 1340 fclose(sfd); 1341 } 1342 fprintf(fd, "\n"); 1343 } 1344 } 1345} 1346 1347/* 1348 * Return TRUE when a function defined in the current script should be 1349 * profiled. 1350 */ 1351 int 1352prof_def_func() 1353{ 1354 if (current_SID > 0) 1355 return SCRIPT_ITEM(current_SID).sn_pr_force; 1356 return FALSE; 1357} 1358 1359# endif 1360#endif 1361 1362/* 1363 * If 'autowrite' option set, try to write the file. 1364 * Careful: autocommands may make "buf" invalid! 1365 * 1366 * return FAIL for failure, OK otherwise 1367 */ 1368 int 1369autowrite(buf, forceit) 1370 buf_T *buf; 1371 int forceit; 1372{ 1373 int r; 1374 1375 if (!(p_aw || p_awa) || !p_write 1376#ifdef FEAT_QUICKFIX 1377 /* never autowrite a "nofile" or "nowrite" buffer */ 1378 || bt_dontwrite(buf) 1379#endif 1380 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL) 1381 return FAIL; 1382 r = buf_write_all(buf, forceit); 1383 1384 /* Writing may succeed but the buffer still changed, e.g., when there is a 1385 * conversion error. We do want to return FAIL then. */ 1386 if (buf_valid(buf) && bufIsChanged(buf)) 1387 r = FAIL; 1388 return r; 1389} 1390 1391/* 1392 * flush all buffers, except the ones that are readonly 1393 */ 1394 void 1395autowrite_all() 1396{ 1397 buf_T *buf; 1398 1399 if (!(p_aw || p_awa) || !p_write) 1400 return; 1401 for (buf = firstbuf; buf; buf = buf->b_next) 1402 if (bufIsChanged(buf) && !buf->b_p_ro) 1403 { 1404 (void)buf_write_all(buf, FALSE); 1405#ifdef FEAT_AUTOCMD 1406 /* an autocommand may have deleted the buffer */ 1407 if (!buf_valid(buf)) 1408 buf = firstbuf; 1409#endif 1410 } 1411} 1412 1413/* 1414 * return TRUE if buffer was changed and cannot be abandoned. 1415 */ 1416 int 1417check_changed(buf, checkaw, mult_win, forceit, allbuf) 1418 buf_T *buf; 1419 int checkaw; /* do autowrite if buffer was changed */ 1420 int mult_win; /* check also when several wins for the buf */ 1421 int forceit; 1422 int allbuf UNUSED; /* may write all buffers */ 1423{ 1424 if ( !forceit 1425 && bufIsChanged(buf) 1426 && (mult_win || buf->b_nwindows <= 1) 1427 && (!checkaw || autowrite(buf, forceit) == FAIL)) 1428 { 1429#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 1430 if ((p_confirm || cmdmod.confirm) && p_write) 1431 { 1432 buf_T *buf2; 1433 int count = 0; 1434 1435 if (allbuf) 1436 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next) 1437 if (bufIsChanged(buf2) 1438 && (buf2->b_ffname != NULL 1439# ifdef FEAT_BROWSE 1440 || cmdmod.browse 1441# endif 1442 )) 1443 ++count; 1444# ifdef FEAT_AUTOCMD 1445 if (!buf_valid(buf)) 1446 /* Autocommand deleted buffer, oops! It's not changed now. */ 1447 return FALSE; 1448# endif 1449 dialog_changed(buf, count > 1); 1450# ifdef FEAT_AUTOCMD 1451 if (!buf_valid(buf)) 1452 /* Autocommand deleted buffer, oops! It's not changed now. */ 1453 return FALSE; 1454# endif 1455 return bufIsChanged(buf); 1456 } 1457#endif 1458 EMSG(_(e_nowrtmsg)); 1459 return TRUE; 1460 } 1461 return FALSE; 1462} 1463 1464#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO) 1465 1466#if defined(FEAT_BROWSE) || defined(PROTO) 1467/* 1468 * When wanting to write a file without a file name, ask the user for a name. 1469 */ 1470 void 1471browse_save_fname(buf) 1472 buf_T *buf; 1473{ 1474 if (buf->b_fname == NULL) 1475 { 1476 char_u *fname; 1477 1478 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"), 1479 NULL, NULL, NULL, NULL, buf); 1480 if (fname != NULL) 1481 { 1482 if (setfname(buf, fname, NULL, TRUE) == OK) 1483 buf->b_flags |= BF_NOTEDITED; 1484 vim_free(fname); 1485 } 1486 } 1487} 1488#endif 1489 1490/* 1491 * Ask the user what to do when abondoning a changed buffer. 1492 * Must check 'write' option first! 1493 */ 1494 void 1495dialog_changed(buf, checkall) 1496 buf_T *buf; 1497 int checkall; /* may abandon all changed buffers */ 1498{ 1499 char_u buff[IOSIZE]; 1500 int ret; 1501 buf_T *buf2; 1502 1503 dialog_msg(buff, _("Save changes to \"%s\"?"), 1504 (buf->b_fname != NULL) ? 1505 buf->b_fname : (char_u *)_("Untitled")); 1506 if (checkall) 1507 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1); 1508 else 1509 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1); 1510 1511 if (ret == VIM_YES) 1512 { 1513#ifdef FEAT_BROWSE 1514 /* May get file name, when there is none */ 1515 browse_save_fname(buf); 1516#endif 1517 if (buf->b_fname != NULL) /* didn't hit Cancel */ 1518 (void)buf_write_all(buf, FALSE); 1519 } 1520 else if (ret == VIM_NO) 1521 { 1522 unchanged(buf, TRUE); 1523 } 1524 else if (ret == VIM_ALL) 1525 { 1526 /* 1527 * Write all modified files that can be written. 1528 * Skip readonly buffers, these need to be confirmed 1529 * individually. 1530 */ 1531 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next) 1532 { 1533 if (bufIsChanged(buf2) 1534 && (buf2->b_ffname != NULL 1535#ifdef FEAT_BROWSE 1536 || cmdmod.browse 1537#endif 1538 ) 1539 && !buf2->b_p_ro) 1540 { 1541#ifdef FEAT_BROWSE 1542 /* May get file name, when there is none */ 1543 browse_save_fname(buf2); 1544#endif 1545 if (buf2->b_fname != NULL) /* didn't hit Cancel */ 1546 (void)buf_write_all(buf2, FALSE); 1547#ifdef FEAT_AUTOCMD 1548 /* an autocommand may have deleted the buffer */ 1549 if (!buf_valid(buf2)) 1550 buf2 = firstbuf; 1551#endif 1552 } 1553 } 1554 } 1555 else if (ret == VIM_DISCARDALL) 1556 { 1557 /* 1558 * mark all buffers as unchanged 1559 */ 1560 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next) 1561 unchanged(buf2, TRUE); 1562 } 1563} 1564#endif 1565 1566/* 1567 * Return TRUE if the buffer "buf" can be abandoned, either by making it 1568 * hidden, autowriting it or unloading it. 1569 */ 1570 int 1571can_abandon(buf, forceit) 1572 buf_T *buf; 1573 int forceit; 1574{ 1575 return ( P_HID(buf) 1576 || !bufIsChanged(buf) 1577 || buf->b_nwindows > 1 1578 || autowrite(buf, forceit) == OK 1579 || forceit); 1580} 1581 1582/* 1583 * Return TRUE if any buffer was changed and cannot be abandoned. 1584 * That changed buffer becomes the current buffer. 1585 */ 1586 int 1587check_changed_any(hidden) 1588 int hidden; /* Only check hidden buffers */ 1589{ 1590 buf_T *buf; 1591 int save; 1592#ifdef FEAT_WINDOWS 1593 win_T *wp; 1594#endif 1595 1596 for (;;) 1597 { 1598 /* check curbuf first: if it was changed we can't abandon it */ 1599 if (!hidden && curbufIsChanged()) 1600 buf = curbuf; 1601 else 1602 { 1603 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 1604 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf)) 1605 break; 1606 } 1607 if (buf == NULL) /* No buffers changed */ 1608 return FALSE; 1609 1610 /* Try auto-writing the buffer. If this fails but the buffer no 1611 * longer exists it's not changed, that's OK. */ 1612 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf)) 1613 break; /* didn't save - still changes */ 1614 } 1615 1616 exiting = FALSE; 1617#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 1618 /* 1619 * When ":confirm" used, don't give an error message. 1620 */ 1621 if (!(p_confirm || cmdmod.confirm)) 1622#endif 1623 { 1624 /* There must be a wait_return for this message, do_buffer() 1625 * may cause a redraw. But wait_return() is a no-op when vgetc() 1626 * is busy (Quit used from window menu), then make sure we don't 1627 * cause a scroll up. */ 1628 if (vgetc_busy > 0) 1629 { 1630 msg_row = cmdline_row; 1631 msg_col = 0; 1632 msg_didout = FALSE; 1633 } 1634 if (EMSG2(_("E162: No write since last change for buffer \"%s\""), 1635 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) : 1636 buf->b_fname)) 1637 { 1638 save = no_wait_return; 1639 no_wait_return = FALSE; 1640 wait_return(FALSE); 1641 no_wait_return = save; 1642 } 1643 } 1644 1645#ifdef FEAT_WINDOWS 1646 /* Try to find a window that contains the buffer. */ 1647 if (buf != curbuf) 1648 for (wp = firstwin; wp != NULL; wp = wp->w_next) 1649 if (wp->w_buffer == buf) 1650 { 1651 win_goto(wp); 1652# ifdef FEAT_AUTOCMD 1653 /* Paranoia: did autocms wipe out the buffer with changes? */ 1654 if (!buf_valid(buf)) 1655 return TRUE; 1656# endif 1657 break; 1658 } 1659#endif 1660 1661 /* Open the changed buffer in the current window. */ 1662 if (buf != curbuf) 1663 set_curbuf(buf, DOBUF_GOTO); 1664 1665 return TRUE; 1666} 1667 1668/* 1669 * return FAIL if there is no file name, OK if there is one 1670 * give error message for FAIL 1671 */ 1672 int 1673check_fname() 1674{ 1675 if (curbuf->b_ffname == NULL) 1676 { 1677 EMSG(_(e_noname)); 1678 return FAIL; 1679 } 1680 return OK; 1681} 1682 1683/* 1684 * flush the contents of a buffer, unless it has no file name 1685 * 1686 * return FAIL for failure, OK otherwise 1687 */ 1688 int 1689buf_write_all(buf, forceit) 1690 buf_T *buf; 1691 int forceit; 1692{ 1693 int retval; 1694#ifdef FEAT_AUTOCMD 1695 buf_T *old_curbuf = curbuf; 1696#endif 1697 1698 retval = (buf_write(buf, buf->b_ffname, buf->b_fname, 1699 (linenr_T)1, buf->b_ml.ml_line_count, NULL, 1700 FALSE, forceit, TRUE, FALSE)); 1701#ifdef FEAT_AUTOCMD 1702 if (curbuf != old_curbuf) 1703 { 1704 msg_source(hl_attr(HLF_W)); 1705 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)")); 1706 } 1707#endif 1708 return retval; 1709} 1710 1711/* 1712 * Code to handle the argument list. 1713 */ 1714 1715static char_u *do_one_arg __ARGS((char_u *str)); 1716static int do_arglist __ARGS((char_u *str, int what, int after)); 1717static void alist_check_arg_idx __ARGS((void)); 1718static int editing_arg_idx __ARGS((win_T *win)); 1719#ifdef FEAT_LISTCMDS 1720static int alist_add_list __ARGS((int count, char_u **files, int after)); 1721#endif 1722#define AL_SET 1 1723#define AL_ADD 2 1724#define AL_DEL 3 1725 1726/* 1727 * Isolate one argument, taking backticks. 1728 * Changes the argument in-place, puts a NUL after it. Backticks remain. 1729 * Return a pointer to the start of the next argument. 1730 */ 1731 static char_u * 1732do_one_arg(str) 1733 char_u *str; 1734{ 1735 char_u *p; 1736 int inbacktick; 1737 1738 inbacktick = FALSE; 1739 for (p = str; *str; ++str) 1740 { 1741 /* When the backslash is used for escaping the special meaning of a 1742 * character we need to keep it until wildcard expansion. */ 1743 if (rem_backslash(str)) 1744 { 1745 *p++ = *str++; 1746 *p++ = *str; 1747 } 1748 else 1749 { 1750 /* An item ends at a space not in backticks */ 1751 if (!inbacktick && vim_isspace(*str)) 1752 break; 1753 if (*str == '`') 1754 inbacktick ^= TRUE; 1755 *p++ = *str; 1756 } 1757 } 1758 str = skipwhite(str); 1759 *p = NUL; 1760 1761 return str; 1762} 1763 1764/* 1765 * Separate the arguments in "str" and return a list of pointers in the 1766 * growarray "gap". 1767 */ 1768 int 1769get_arglist(gap, str) 1770 garray_T *gap; 1771 char_u *str; 1772{ 1773 ga_init2(gap, (int)sizeof(char_u *), 20); 1774 while (*str != NUL) 1775 { 1776 if (ga_grow(gap, 1) == FAIL) 1777 { 1778 ga_clear(gap); 1779 return FAIL; 1780 } 1781 ((char_u **)gap->ga_data)[gap->ga_len++] = str; 1782 1783 /* Isolate one argument, change it in-place, put a NUL after it. */ 1784 str = do_one_arg(str); 1785 } 1786 return OK; 1787} 1788 1789#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO) 1790/* 1791 * Parse a list of arguments (file names), expand them and return in 1792 * "fnames[fcountp]". 1793 * Return FAIL or OK. 1794 */ 1795 int 1796get_arglist_exp(str, fcountp, fnamesp) 1797 char_u *str; 1798 int *fcountp; 1799 char_u ***fnamesp; 1800{ 1801 garray_T ga; 1802 int i; 1803 1804 if (get_arglist(&ga, str) == FAIL) 1805 return FAIL; 1806 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data, 1807 fcountp, fnamesp, EW_FILE|EW_NOTFOUND); 1808 ga_clear(&ga); 1809 return i; 1810} 1811#endif 1812 1813#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO) 1814/* 1815 * Redefine the argument list. 1816 */ 1817 void 1818set_arglist(str) 1819 char_u *str; 1820{ 1821 do_arglist(str, AL_SET, 0); 1822} 1823#endif 1824 1825/* 1826 * "what" == AL_SET: Redefine the argument list to 'str'. 1827 * "what" == AL_ADD: add files in 'str' to the argument list after "after". 1828 * "what" == AL_DEL: remove files in 'str' from the argument list. 1829 * 1830 * Return FAIL for failure, OK otherwise. 1831 */ 1832 static int 1833do_arglist(str, what, after) 1834 char_u *str; 1835 int what UNUSED; 1836 int after UNUSED; /* 0 means before first one */ 1837{ 1838 garray_T new_ga; 1839 int exp_count; 1840 char_u **exp_files; 1841 int i; 1842#ifdef FEAT_LISTCMDS 1843 char_u *p; 1844 int match; 1845#endif 1846 1847 /* 1848 * Collect all file name arguments in "new_ga". 1849 */ 1850 if (get_arglist(&new_ga, str) == FAIL) 1851 return FAIL; 1852 1853#ifdef FEAT_LISTCMDS 1854 if (what == AL_DEL) 1855 { 1856 regmatch_T regmatch; 1857 int didone; 1858 1859 /* 1860 * Delete the items: use each item as a regexp and find a match in the 1861 * argument list. 1862 */ 1863#ifdef CASE_INSENSITIVE_FILENAME 1864 regmatch.rm_ic = TRUE; /* Always ignore case */ 1865#else 1866 regmatch.rm_ic = FALSE; /* Never ignore case */ 1867#endif 1868 for (i = 0; i < new_ga.ga_len && !got_int; ++i) 1869 { 1870 p = ((char_u **)new_ga.ga_data)[i]; 1871 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE); 1872 if (p == NULL) 1873 break; 1874 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0); 1875 if (regmatch.regprog == NULL) 1876 { 1877 vim_free(p); 1878 break; 1879 } 1880 1881 didone = FALSE; 1882 for (match = 0; match < ARGCOUNT; ++match) 1883 if (vim_regexec(®match, alist_name(&ARGLIST[match]), 1884 (colnr_T)0)) 1885 { 1886 didone = TRUE; 1887 vim_free(ARGLIST[match].ae_fname); 1888 mch_memmove(ARGLIST + match, ARGLIST + match + 1, 1889 (ARGCOUNT - match - 1) * sizeof(aentry_T)); 1890 --ALIST(curwin)->al_ga.ga_len; 1891 if (curwin->w_arg_idx > match) 1892 --curwin->w_arg_idx; 1893 --match; 1894 } 1895 1896 vim_free(regmatch.regprog); 1897 vim_free(p); 1898 if (!didone) 1899 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]); 1900 } 1901 ga_clear(&new_ga); 1902 } 1903 else 1904#endif 1905 { 1906 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data, 1907 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND); 1908 ga_clear(&new_ga); 1909 if (i == FAIL) 1910 return FAIL; 1911 if (exp_count == 0) 1912 { 1913 EMSG(_(e_nomatch)); 1914 return FAIL; 1915 } 1916 1917#ifdef FEAT_LISTCMDS 1918 if (what == AL_ADD) 1919 { 1920 (void)alist_add_list(exp_count, exp_files, after); 1921 vim_free(exp_files); 1922 } 1923 else /* what == AL_SET */ 1924#endif 1925 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0); 1926 } 1927 1928 alist_check_arg_idx(); 1929 1930 return OK; 1931} 1932 1933/* 1934 * Check the validity of the arg_idx for each other window. 1935 */ 1936 static void 1937alist_check_arg_idx() 1938{ 1939#ifdef FEAT_WINDOWS 1940 win_T *win; 1941 tabpage_T *tp; 1942 1943 FOR_ALL_TAB_WINDOWS(tp, win) 1944 if (win->w_alist == curwin->w_alist) 1945 check_arg_idx(win); 1946#else 1947 check_arg_idx(curwin); 1948#endif 1949} 1950 1951/* 1952 * Return TRUE if window "win" is editing then file at the current argument 1953 * index. 1954 */ 1955 static int 1956editing_arg_idx(win) 1957 win_T *win; 1958{ 1959 return !(win->w_arg_idx >= WARGCOUNT(win) 1960 || (win->w_buffer->b_fnum 1961 != WARGLIST(win)[win->w_arg_idx].ae_fnum 1962 && (win->w_buffer->b_ffname == NULL 1963 || !(fullpathcmp( 1964 alist_name(&WARGLIST(win)[win->w_arg_idx]), 1965 win->w_buffer->b_ffname, TRUE) & FPC_SAME)))); 1966} 1967 1968/* 1969 * Check if window "win" is editing the w_arg_idx file in its argument list. 1970 */ 1971 void 1972check_arg_idx(win) 1973 win_T *win; 1974{ 1975 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win)) 1976 { 1977 /* We are not editing the current entry in the argument list. 1978 * Set "arg_had_last" if we are editing the last one. */ 1979 win->w_arg_idx_invalid = TRUE; 1980 if (win->w_arg_idx != WARGCOUNT(win) - 1 1981 && arg_had_last == FALSE 1982#ifdef FEAT_WINDOWS 1983 && ALIST(win) == &global_alist 1984#endif 1985 && GARGCOUNT > 0 1986 && win->w_arg_idx < GARGCOUNT 1987 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum 1988 || (win->w_buffer->b_ffname != NULL 1989 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]), 1990 win->w_buffer->b_ffname, TRUE) & FPC_SAME)))) 1991 arg_had_last = TRUE; 1992 } 1993 else 1994 { 1995 /* We are editing the current entry in the argument list. 1996 * Set "arg_had_last" if it's also the last one */ 1997 win->w_arg_idx_invalid = FALSE; 1998 if (win->w_arg_idx == WARGCOUNT(win) - 1 1999#ifdef FEAT_WINDOWS 2000 && win->w_alist == &global_alist 2001#endif 2002 ) 2003 arg_had_last = TRUE; 2004 } 2005} 2006 2007/* 2008 * ":args", ":argslocal" and ":argsglobal". 2009 */ 2010 void 2011ex_args(eap) 2012 exarg_T *eap; 2013{ 2014 int i; 2015 2016 if (eap->cmdidx != CMD_args) 2017 { 2018#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS) 2019 alist_unlink(ALIST(curwin)); 2020 if (eap->cmdidx == CMD_argglobal) 2021 ALIST(curwin) = &global_alist; 2022 else /* eap->cmdidx == CMD_arglocal */ 2023 alist_new(); 2024#else 2025 ex_ni(eap); 2026 return; 2027#endif 2028 } 2029 2030 if (!ends_excmd(*eap->arg)) 2031 { 2032 /* 2033 * ":args file ..": define new argument list, handle like ":next" 2034 * Also for ":argslocal file .." and ":argsglobal file ..". 2035 */ 2036 ex_next(eap); 2037 } 2038 else 2039#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS) 2040 if (eap->cmdidx == CMD_args) 2041#endif 2042 { 2043 /* 2044 * ":args": list arguments. 2045 */ 2046 if (ARGCOUNT > 0) 2047 { 2048 /* Overwrite the command, for a short list there is no scrolling 2049 * required and no wait_return(). */ 2050 gotocmdline(TRUE); 2051 for (i = 0; i < ARGCOUNT; ++i) 2052 { 2053 if (i == curwin->w_arg_idx) 2054 msg_putchar('['); 2055 msg_outtrans(alist_name(&ARGLIST[i])); 2056 if (i == curwin->w_arg_idx) 2057 msg_putchar(']'); 2058 msg_putchar(' '); 2059 } 2060 } 2061 } 2062#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS) 2063 else if (eap->cmdidx == CMD_arglocal) 2064 { 2065 garray_T *gap = &curwin->w_alist->al_ga; 2066 2067 /* 2068 * ":argslocal": make a local copy of the global argument list. 2069 */ 2070 if (ga_grow(gap, GARGCOUNT) == OK) 2071 for (i = 0; i < GARGCOUNT; ++i) 2072 if (GARGLIST[i].ae_fname != NULL) 2073 { 2074 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname = 2075 vim_strsave(GARGLIST[i].ae_fname); 2076 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum = 2077 GARGLIST[i].ae_fnum; 2078 ++gap->ga_len; 2079 } 2080 } 2081#endif 2082} 2083 2084/* 2085 * ":previous", ":sprevious", ":Next" and ":sNext". 2086 */ 2087 void 2088ex_previous(eap) 2089 exarg_T *eap; 2090{ 2091 /* If past the last one already, go to the last one. */ 2092 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT) 2093 do_argfile(eap, ARGCOUNT - 1); 2094 else 2095 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2); 2096} 2097 2098/* 2099 * ":rewind", ":first", ":sfirst" and ":srewind". 2100 */ 2101 void 2102ex_rewind(eap) 2103 exarg_T *eap; 2104{ 2105 do_argfile(eap, 0); 2106} 2107 2108/* 2109 * ":last" and ":slast". 2110 */ 2111 void 2112ex_last(eap) 2113 exarg_T *eap; 2114{ 2115 do_argfile(eap, ARGCOUNT - 1); 2116} 2117 2118/* 2119 * ":argument" and ":sargument". 2120 */ 2121 void 2122ex_argument(eap) 2123 exarg_T *eap; 2124{ 2125 int i; 2126 2127 if (eap->addr_count > 0) 2128 i = eap->line2 - 1; 2129 else 2130 i = curwin->w_arg_idx; 2131 do_argfile(eap, i); 2132} 2133 2134/* 2135 * Edit file "argn" of the argument lists. 2136 */ 2137 void 2138do_argfile(eap, argn) 2139 exarg_T *eap; 2140 int argn; 2141{ 2142 int other; 2143 char_u *p; 2144 int old_arg_idx = curwin->w_arg_idx; 2145 2146 if (argn < 0 || argn >= ARGCOUNT) 2147 { 2148 if (ARGCOUNT <= 1) 2149 EMSG(_("E163: There is only one file to edit")); 2150 else if (argn < 0) 2151 EMSG(_("E164: Cannot go before first file")); 2152 else 2153 EMSG(_("E165: Cannot go beyond last file")); 2154 } 2155 else 2156 { 2157 setpcmark(); 2158#ifdef FEAT_GUI 2159 need_mouse_correct = TRUE; 2160#endif 2161 2162#ifdef FEAT_WINDOWS 2163 /* split window or create new tab page first */ 2164 if (*eap->cmd == 's' || cmdmod.tab != 0) 2165 { 2166 if (win_split(0, 0) == FAIL) 2167 return; 2168# ifdef FEAT_SCROLLBIND 2169 curwin->w_p_scb = FALSE; 2170# endif 2171 } 2172 else 2173#endif 2174 { 2175 /* 2176 * if 'hidden' set, only check for changed file when re-editing 2177 * the same buffer 2178 */ 2179 other = TRUE; 2180 if (P_HID(curbuf)) 2181 { 2182 p = fix_fname(alist_name(&ARGLIST[argn])); 2183 other = otherfile(p); 2184 vim_free(p); 2185 } 2186 if ((!P_HID(curbuf) || !other) 2187 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE)) 2188 return; 2189 } 2190 2191 curwin->w_arg_idx = argn; 2192 if (argn == ARGCOUNT - 1 2193#ifdef FEAT_WINDOWS 2194 && curwin->w_alist == &global_alist 2195#endif 2196 ) 2197 arg_had_last = TRUE; 2198 2199 /* Edit the file; always use the last known line number. 2200 * When it fails (e.g. Abort for already edited file) restore the 2201 * argument index. */ 2202 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL, 2203 eap, ECMD_LAST, 2204 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) 2205 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) 2206 curwin->w_arg_idx = old_arg_idx; 2207 /* like Vi: set the mark where the cursor is in the file. */ 2208 else if (eap->cmdidx != CMD_argdo) 2209 setmark('\''); 2210 } 2211} 2212 2213/* 2214 * ":next", and commands that behave like it. 2215 */ 2216 void 2217ex_next(eap) 2218 exarg_T *eap; 2219{ 2220 int i; 2221 2222 /* 2223 * check for changed buffer now, if this fails the argument list is not 2224 * redefined. 2225 */ 2226 if ( P_HID(curbuf) 2227 || eap->cmdidx == CMD_snext 2228 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE)) 2229 { 2230 if (*eap->arg != NUL) /* redefine file list */ 2231 { 2232 if (do_arglist(eap->arg, AL_SET, 0) == FAIL) 2233 return; 2234 i = 0; 2235 } 2236 else 2237 i = curwin->w_arg_idx + (int)eap->line2; 2238 do_argfile(eap, i); 2239 } 2240} 2241 2242#ifdef FEAT_LISTCMDS 2243/* 2244 * ":argedit" 2245 */ 2246 void 2247ex_argedit(eap) 2248 exarg_T *eap; 2249{ 2250 int fnum; 2251 int i; 2252 char_u *s; 2253 2254 /* Add the argument to the buffer list and get the buffer number. */ 2255 fnum = buflist_add(eap->arg, BLN_LISTED); 2256 2257 /* Check if this argument is already in the argument list. */ 2258 for (i = 0; i < ARGCOUNT; ++i) 2259 if (ARGLIST[i].ae_fnum == fnum) 2260 break; 2261 if (i == ARGCOUNT) 2262 { 2263 /* Can't find it, add it to the argument list. */ 2264 s = vim_strsave(eap->arg); 2265 if (s == NULL) 2266 return; 2267 i = alist_add_list(1, &s, 2268 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1); 2269 if (i < 0) 2270 return; 2271 curwin->w_arg_idx = i; 2272 } 2273 2274 alist_check_arg_idx(); 2275 2276 /* Edit the argument. */ 2277 do_argfile(eap, i); 2278} 2279 2280/* 2281 * ":argadd" 2282 */ 2283 void 2284ex_argadd(eap) 2285 exarg_T *eap; 2286{ 2287 do_arglist(eap->arg, AL_ADD, 2288 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1); 2289#ifdef FEAT_TITLE 2290 maketitle(); 2291#endif 2292} 2293 2294/* 2295 * ":argdelete" 2296 */ 2297 void 2298ex_argdelete(eap) 2299 exarg_T *eap; 2300{ 2301 int i; 2302 int n; 2303 2304 if (eap->addr_count > 0) 2305 { 2306 /* ":1,4argdel": Delete all arguments in the range. */ 2307 if (eap->line2 > ARGCOUNT) 2308 eap->line2 = ARGCOUNT; 2309 n = eap->line2 - eap->line1 + 1; 2310 if (*eap->arg != NUL || n <= 0) 2311 EMSG(_(e_invarg)); 2312 else 2313 { 2314 for (i = eap->line1; i <= eap->line2; ++i) 2315 vim_free(ARGLIST[i - 1].ae_fname); 2316 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2, 2317 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T))); 2318 ALIST(curwin)->al_ga.ga_len -= n; 2319 if (curwin->w_arg_idx >= eap->line2) 2320 curwin->w_arg_idx -= n; 2321 else if (curwin->w_arg_idx > eap->line1) 2322 curwin->w_arg_idx = eap->line1; 2323 } 2324 } 2325 else if (*eap->arg == NUL) 2326 EMSG(_(e_argreq)); 2327 else 2328 do_arglist(eap->arg, AL_DEL, 0); 2329#ifdef FEAT_TITLE 2330 maketitle(); 2331#endif 2332} 2333 2334/* 2335 * ":argdo", ":windo", ":bufdo", ":tabdo" 2336 */ 2337 void 2338ex_listdo(eap) 2339 exarg_T *eap; 2340{ 2341 int i; 2342#ifdef FEAT_WINDOWS 2343 win_T *wp; 2344 tabpage_T *tp; 2345#endif 2346 buf_T *buf; 2347 int next_fnum = 0; 2348#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 2349 char_u *save_ei = NULL; 2350#endif 2351 char_u *p_shm_save; 2352 2353#ifndef FEAT_WINDOWS 2354 if (eap->cmdidx == CMD_windo) 2355 { 2356 ex_ni(eap); 2357 return; 2358 } 2359#endif 2360 2361#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 2362 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo) 2363 /* Don't do syntax HL autocommands. Skipping the syntax file is a 2364 * great speed improvement. */ 2365 save_ei = au_event_disable(",Syntax"); 2366#endif 2367 2368 if (eap->cmdidx == CMD_windo 2369 || eap->cmdidx == CMD_tabdo 2370 || P_HID(curbuf) 2371 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE)) 2372 { 2373 /* start at the first argument/window/buffer */ 2374 i = 0; 2375#ifdef FEAT_WINDOWS 2376 wp = firstwin; 2377 tp = first_tabpage; 2378#endif 2379 /* set pcmark now */ 2380 if (eap->cmdidx == CMD_bufdo) 2381 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0); 2382 else 2383 setpcmark(); 2384 listcmd_busy = TRUE; /* avoids setting pcmark below */ 2385 2386 while (!got_int) 2387 { 2388 if (eap->cmdidx == CMD_argdo) 2389 { 2390 /* go to argument "i" */ 2391 if (i == ARGCOUNT) 2392 break; 2393 /* Don't call do_argfile() when already there, it will try 2394 * reloading the file. */ 2395 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin)) 2396 { 2397 /* Clear 'shm' to avoid that the file message overwrites 2398 * any output from the command. */ 2399 p_shm_save = vim_strsave(p_shm); 2400 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0); 2401 do_argfile(eap, i); 2402 set_option_value((char_u *)"shm", 0L, p_shm_save, 0); 2403 vim_free(p_shm_save); 2404 } 2405 if (curwin->w_arg_idx != i) 2406 break; 2407 ++i; 2408 } 2409#ifdef FEAT_WINDOWS 2410 else if (eap->cmdidx == CMD_windo) 2411 { 2412 /* go to window "wp" */ 2413 if (!win_valid(wp)) 2414 break; 2415 win_goto(wp); 2416 if (curwin != wp) 2417 break; /* something must be wrong */ 2418 wp = curwin->w_next; 2419 } 2420 else if (eap->cmdidx == CMD_tabdo) 2421 { 2422 /* go to window "tp" */ 2423 if (!valid_tabpage(tp)) 2424 break; 2425 goto_tabpage_tp(tp); 2426 tp = tp->tp_next; 2427 } 2428#endif 2429 else if (eap->cmdidx == CMD_bufdo) 2430 { 2431 /* Remember the number of the next listed buffer, in case 2432 * ":bwipe" is used or autocommands do something strange. */ 2433 next_fnum = -1; 2434 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next) 2435 if (buf->b_p_bl) 2436 { 2437 next_fnum = buf->b_fnum; 2438 break; 2439 } 2440 } 2441 2442 /* execute the command */ 2443 do_cmdline(eap->arg, eap->getline, eap->cookie, 2444 DOCMD_VERBOSE + DOCMD_NOWAIT); 2445 2446 if (eap->cmdidx == CMD_bufdo) 2447 { 2448 /* Done? */ 2449 if (next_fnum < 0) 2450 break; 2451 /* Check if the buffer still exists. */ 2452 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 2453 if (buf->b_fnum == next_fnum) 2454 break; 2455 if (buf == NULL) 2456 break; 2457 2458 /* Go to the next buffer. Clear 'shm' to avoid that the file 2459 * message overwrites any output from the command. */ 2460 p_shm_save = vim_strsave(p_shm); 2461 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0); 2462 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum); 2463 set_option_value((char_u *)"shm", 0L, p_shm_save, 0); 2464 vim_free(p_shm_save); 2465 2466 /* If autocommands took us elsewhere, quit here */ 2467 if (curbuf->b_fnum != next_fnum) 2468 break; 2469 } 2470 2471 if (eap->cmdidx == CMD_windo) 2472 { 2473 validate_cursor(); /* cursor may have moved */ 2474#ifdef FEAT_SCROLLBIND 2475 /* required when 'scrollbind' has been set */ 2476 if (curwin->w_p_scb) 2477 do_check_scrollbind(TRUE); 2478#endif 2479 } 2480 } 2481 listcmd_busy = FALSE; 2482 } 2483 2484#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 2485 if (save_ei != NULL) 2486 { 2487 au_event_restore(save_ei); 2488 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, 2489 curbuf->b_fname, TRUE, curbuf); 2490 } 2491#endif 2492} 2493 2494/* 2495 * Add files[count] to the arglist of the current window after arg "after". 2496 * The file names in files[count] must have been allocated and are taken over. 2497 * Files[] itself is not taken over. 2498 * Returns index of first added argument. Returns -1 when failed (out of mem). 2499 */ 2500 static int 2501alist_add_list(count, files, after) 2502 int count; 2503 char_u **files; 2504 int after; /* where to add: 0 = before first one */ 2505{ 2506 int i; 2507 2508 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK) 2509 { 2510 if (after < 0) 2511 after = 0; 2512 if (after > ARGCOUNT) 2513 after = ARGCOUNT; 2514 if (after < ARGCOUNT) 2515 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), 2516 (ARGCOUNT - after) * sizeof(aentry_T)); 2517 for (i = 0; i < count; ++i) 2518 { 2519 ARGLIST[after + i].ae_fname = files[i]; 2520 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED); 2521 } 2522 ALIST(curwin)->al_ga.ga_len += count; 2523 if (curwin->w_arg_idx >= after) 2524 ++curwin->w_arg_idx; 2525 return after; 2526 } 2527 2528 for (i = 0; i < count; ++i) 2529 vim_free(files[i]); 2530 return -1; 2531} 2532 2533#endif /* FEAT_LISTCMDS */ 2534 2535#ifdef FEAT_EVAL 2536/* 2537 * ":compiler[!] {name}" 2538 */ 2539 void 2540ex_compiler(eap) 2541 exarg_T *eap; 2542{ 2543 char_u *buf; 2544 char_u *old_cur_comp = NULL; 2545 char_u *p; 2546 2547 if (*eap->arg == NUL) 2548 { 2549 /* List all compiler scripts. */ 2550 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')"); 2551 /* ) keep the indenter happy... */ 2552 } 2553 else 2554 { 2555 buf = alloc((unsigned)(STRLEN(eap->arg) + 14)); 2556 if (buf != NULL) 2557 { 2558 if (eap->forceit) 2559 { 2560 /* ":compiler! {name}" sets global options */ 2561 do_cmdline_cmd((char_u *) 2562 "command -nargs=* CompilerSet set <args>"); 2563 } 2564 else 2565 { 2566 /* ":compiler! {name}" sets local options. 2567 * To remain backwards compatible "current_compiler" is always 2568 * used. A user's compiler plugin may set it, the distributed 2569 * plugin will then skip the settings. Afterwards set 2570 * "b:current_compiler" and restore "current_compiler". 2571 * Explicitly prepend "g:" to make it work in a function. */ 2572 old_cur_comp = get_var_value((char_u *)"g:current_compiler"); 2573 if (old_cur_comp != NULL) 2574 old_cur_comp = vim_strsave(old_cur_comp); 2575 do_cmdline_cmd((char_u *) 2576 "command -nargs=* CompilerSet setlocal <args>"); 2577 } 2578 do_unlet((char_u *)"g:current_compiler", TRUE); 2579 do_unlet((char_u *)"b:current_compiler", TRUE); 2580 2581 sprintf((char *)buf, "compiler/%s.vim", eap->arg); 2582 if (source_runtime(buf, TRUE) == FAIL) 2583 EMSG2(_("E666: compiler not supported: %s"), eap->arg); 2584 vim_free(buf); 2585 2586 do_cmdline_cmd((char_u *)":delcommand CompilerSet"); 2587 2588 /* Set "b:current_compiler" from "current_compiler". */ 2589 p = get_var_value((char_u *)"g:current_compiler"); 2590 if (p != NULL) 2591 set_internal_string_var((char_u *)"b:current_compiler", p); 2592 2593 /* Restore "current_compiler" for ":compiler {name}". */ 2594 if (!eap->forceit) 2595 { 2596 if (old_cur_comp != NULL) 2597 { 2598 set_internal_string_var((char_u *)"g:current_compiler", 2599 old_cur_comp); 2600 vim_free(old_cur_comp); 2601 } 2602 else 2603 do_unlet((char_u *)"g:current_compiler", TRUE); 2604 } 2605 } 2606 } 2607} 2608#endif 2609 2610/* 2611 * ":runtime {name}" 2612 */ 2613 void 2614ex_runtime(eap) 2615 exarg_T *eap; 2616{ 2617 source_runtime(eap->arg, eap->forceit); 2618} 2619 2620static void source_callback __ARGS((char_u *fname, void *cookie)); 2621 2622 static void 2623source_callback(fname, cookie) 2624 char_u *fname; 2625 void *cookie UNUSED; 2626{ 2627 (void)do_source(fname, FALSE, DOSO_NONE); 2628} 2629 2630/* 2631 * Source the file "name" from all directories in 'runtimepath'. 2632 * "name" can contain wildcards. 2633 * When "all" is TRUE, source all files, otherwise only the first one. 2634 * return FAIL when no file could be sourced, OK otherwise. 2635 */ 2636 int 2637source_runtime(name, all) 2638 char_u *name; 2639 int all; 2640{ 2641 return do_in_runtimepath(name, all, source_callback, NULL); 2642} 2643 2644/* 2645 * Find "name" in 'runtimepath'. When found, invoke the callback function for 2646 * it: callback(fname, "cookie") 2647 * When "all" is TRUE repeat for all matches, otherwise only the first one is 2648 * used. 2649 * Returns OK when at least one match found, FAIL otherwise. 2650 */ 2651 int 2652do_in_runtimepath(name, all, callback, cookie) 2653 char_u *name; 2654 int all; 2655 void (*callback)__ARGS((char_u *fname, void *ck)); 2656 void *cookie; 2657{ 2658 char_u *rtp; 2659 char_u *np; 2660 char_u *buf; 2661 char_u *rtp_copy; 2662 char_u *tail; 2663 int num_files; 2664 char_u **files; 2665 int i; 2666 int did_one = FALSE; 2667#ifdef AMIGA 2668 struct Process *proc = (struct Process *)FindTask(0L); 2669 APTR save_winptr = proc->pr_WindowPtr; 2670 2671 /* Avoid a requester here for a volume that doesn't exist. */ 2672 proc->pr_WindowPtr = (APTR)-1L; 2673#endif 2674 2675 /* Make a copy of 'runtimepath'. Invoking the callback may change the 2676 * value. */ 2677 rtp_copy = vim_strsave(p_rtp); 2678 buf = alloc(MAXPATHL); 2679 if (buf != NULL && rtp_copy != NULL) 2680 { 2681 if (p_verbose > 1) 2682 { 2683 verbose_enter(); 2684 smsg((char_u *)_("Searching for \"%s\" in \"%s\""), 2685 (char *)name, (char *)p_rtp); 2686 verbose_leave(); 2687 } 2688 2689 /* Loop over all entries in 'runtimepath'. */ 2690 rtp = rtp_copy; 2691 while (*rtp != NUL && (all || !did_one)) 2692 { 2693 /* Copy the path from 'runtimepath' to buf[]. */ 2694 copy_option_part(&rtp, buf, MAXPATHL, ","); 2695 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL) 2696 { 2697 add_pathsep(buf); 2698 tail = buf + STRLEN(buf); 2699 2700 /* Loop over all patterns in "name" */ 2701 np = name; 2702 while (*np != NUL && (all || !did_one)) 2703 { 2704 /* Append the pattern from "name" to buf[]. */ 2705 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)), 2706 "\t "); 2707 2708 if (p_verbose > 2) 2709 { 2710 verbose_enter(); 2711 smsg((char_u *)_("Searching for \"%s\""), buf); 2712 verbose_leave(); 2713 } 2714 2715 /* Expand wildcards, invoke the callback for each match. */ 2716 if (gen_expand_wildcards(1, &buf, &num_files, &files, 2717 EW_FILE) == OK) 2718 { 2719 for (i = 0; i < num_files; ++i) 2720 { 2721 (*callback)(files[i], cookie); 2722 did_one = TRUE; 2723 if (!all) 2724 break; 2725 } 2726 FreeWild(num_files, files); 2727 } 2728 } 2729 } 2730 } 2731 } 2732 vim_free(buf); 2733 vim_free(rtp_copy); 2734 if (p_verbose > 0 && !did_one) 2735 { 2736 verbose_enter(); 2737 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name); 2738 verbose_leave(); 2739 } 2740 2741#ifdef AMIGA 2742 proc->pr_WindowPtr = save_winptr; 2743#endif 2744 2745 return did_one ? OK : FAIL; 2746} 2747 2748#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD) 2749/* 2750 * ":options" 2751 */ 2752 void 2753ex_options(eap) 2754 exarg_T *eap UNUSED; 2755{ 2756 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL); 2757} 2758#endif 2759 2760/* 2761 * ":source {fname}" 2762 */ 2763 void 2764ex_source(eap) 2765 exarg_T *eap; 2766{ 2767#ifdef FEAT_BROWSE 2768 if (cmdmod.browse) 2769 { 2770 char_u *fname = NULL; 2771 2772 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg, 2773 NULL, NULL, BROWSE_FILTER_MACROS, NULL); 2774 if (fname != NULL) 2775 { 2776 cmd_source(fname, eap); 2777 vim_free(fname); 2778 } 2779 } 2780 else 2781#endif 2782 cmd_source(eap->arg, eap); 2783} 2784 2785 static void 2786cmd_source(fname, eap) 2787 char_u *fname; 2788 exarg_T *eap; 2789{ 2790 if (*fname == NUL) 2791 EMSG(_(e_argreq)); 2792 2793 else if (eap != NULL && eap->forceit) 2794 /* ":source!": read Normal mdoe commands 2795 * Need to execute the commands directly. This is required at least 2796 * for: 2797 * - ":g" command busy 2798 * - after ":argdo", ":windo" or ":bufdo" 2799 * - another command follows 2800 * - inside a loop 2801 */ 2802 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL 2803#ifdef FEAT_EVAL 2804 || eap->cstack->cs_idx >= 0 2805#endif 2806 ); 2807 2808 /* ":source" read ex commands */ 2809 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL) 2810 EMSG2(_(e_notopen), fname); 2811} 2812 2813/* 2814 * ":source" and associated commands. 2815 */ 2816/* 2817 * Structure used to store info for each sourced file. 2818 * It is shared between do_source() and getsourceline(). 2819 * This is required, because it needs to be handed to do_cmdline() and 2820 * sourcing can be done recursively. 2821 */ 2822struct source_cookie 2823{ 2824 FILE *fp; /* opened file for sourcing */ 2825 char_u *nextline; /* if not NULL: line that was read ahead */ 2826 int finished; /* ":finish" used */ 2827#if defined(USE_CRNL) || defined(USE_CR) 2828 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */ 2829 int error; /* TRUE if LF found after CR-LF */ 2830#endif 2831#ifdef FEAT_EVAL 2832 linenr_T breakpoint; /* next line with breakpoint or zero */ 2833 char_u *fname; /* name of sourced file */ 2834 int dbg_tick; /* debug_tick when breakpoint was set */ 2835 int level; /* top nesting level of sourced file */ 2836#endif 2837#ifdef FEAT_MBYTE 2838 vimconv_T conv; /* type of conversion */ 2839#endif 2840}; 2841 2842#ifdef FEAT_EVAL 2843/* 2844 * Return the address holding the next breakpoint line for a source cookie. 2845 */ 2846 linenr_T * 2847source_breakpoint(cookie) 2848 void *cookie; 2849{ 2850 return &((struct source_cookie *)cookie)->breakpoint; 2851} 2852 2853/* 2854 * Return the address holding the debug tick for a source cookie. 2855 */ 2856 int * 2857source_dbg_tick(cookie) 2858 void *cookie; 2859{ 2860 return &((struct source_cookie *)cookie)->dbg_tick; 2861} 2862 2863/* 2864 * Return the nesting level for a source cookie. 2865 */ 2866 int 2867source_level(cookie) 2868 void *cookie; 2869{ 2870 return ((struct source_cookie *)cookie)->level; 2871} 2872#endif 2873 2874static char_u *get_one_sourceline __ARGS((struct source_cookie *sp)); 2875 2876#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC) 2877# define USE_FOPEN_NOINH 2878static FILE *fopen_noinh_readbin __ARGS((char *filename)); 2879 2880/* 2881 * Special function to open a file without handle inheritance. 2882 * When possible the handle is closed on exec(). 2883 */ 2884 static FILE * 2885fopen_noinh_readbin(filename) 2886 char *filename; 2887{ 2888# ifdef WIN32 2889 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0); 2890# else 2891 int fd_tmp = mch_open(filename, O_RDONLY, 0); 2892# endif 2893 2894 if (fd_tmp == -1) 2895 return NULL; 2896 2897# ifdef HAVE_FD_CLOEXEC 2898 { 2899 int fdflags = fcntl(fd_tmp, F_GETFD); 2900 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) 2901 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC); 2902 } 2903# endif 2904 2905 return fdopen(fd_tmp, READBIN); 2906} 2907#endif 2908 2909 2910/* 2911 * do_source: Read the file "fname" and execute its lines as EX commands. 2912 * 2913 * This function may be called recursively! 2914 * 2915 * return FAIL if file could not be opened, OK otherwise 2916 */ 2917 int 2918do_source(fname, check_other, is_vimrc) 2919 char_u *fname; 2920 int check_other; /* check for .vimrc and _vimrc */ 2921 int is_vimrc; /* DOSO_ value */ 2922{ 2923 struct source_cookie cookie; 2924 char_u *save_sourcing_name; 2925 linenr_T save_sourcing_lnum; 2926 char_u *p; 2927 char_u *fname_exp; 2928 char_u *firstline = NULL; 2929 int retval = FAIL; 2930#ifdef FEAT_EVAL 2931 scid_T save_current_SID; 2932 static scid_T last_current_SID = 0; 2933 void *save_funccalp; 2934 int save_debug_break_level = debug_break_level; 2935 scriptitem_T *si = NULL; 2936# ifdef UNIX 2937 struct stat st; 2938 int stat_ok; 2939# endif 2940#endif 2941#ifdef STARTUPTIME 2942 struct timeval tv_rel; 2943 struct timeval tv_start; 2944#endif 2945#ifdef FEAT_PROFILE 2946 proftime_T wait_start; 2947#endif 2948 2949#ifdef RISCOS 2950 p = mch_munge_fname(fname); 2951#else 2952 p = expand_env_save(fname); 2953#endif 2954 if (p == NULL) 2955 return retval; 2956 fname_exp = fix_fname(p); 2957 vim_free(p); 2958 if (fname_exp == NULL) 2959 return retval; 2960 if (mch_isdir(fname_exp)) 2961 { 2962 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname); 2963 goto theend; 2964 } 2965 2966#ifdef FEAT_AUTOCMD 2967 /* Apply SourceCmd autocommands, they should get the file and source it. */ 2968 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL) 2969 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp, 2970 FALSE, curbuf)) 2971 { 2972# ifdef FEAT_EVAL 2973 retval = aborting() ? FAIL : OK; 2974# else 2975 retval = OK; 2976# endif 2977 goto theend; 2978 } 2979 2980 /* Apply SourcePre autocommands, they may get the file. */ 2981 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf); 2982#endif 2983 2984#ifdef __APPLE__ 2985 if(Unix2003_compat) { 2986 int remaining; 2987 char * filepart = strrchr((char *)fname_exp,'/'); 2988 if (filepart) filepart++; 2989 else filepart = (char *)fname_exp; 2990 remaining = STRLEN(filepart); 2991 if ((remaining==5) && (STRNCMP(filepart,".exrc",5)==0)) { 2992 /* only check this one file: ex_02 test 72 */ 2993 if (mch_am_i_owner((char *)fname_exp)!=OK) goto theend; 2994 } 2995 } 2996#endif /* __APPLE__ */ 2997 2998#ifdef USE_FOPEN_NOINH 2999 cookie.fp = fopen_noinh_readbin((char *)fname_exp); 3000#else 3001 cookie.fp = mch_fopen((char *)fname_exp, READBIN); 3002#endif 3003 if (cookie.fp == NULL && check_other) 3004 { 3005 /* 3006 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa, 3007 * and ".exrc" by "_exrc" or vice versa. 3008 */ 3009 p = gettail(fname_exp); 3010 if ((*p == '.' || *p == '_') 3011 && (STRICMP(p + 1, "vimrc") == 0 3012 || STRICMP(p + 1, "gvimrc") == 0 3013 || STRICMP(p + 1, "exrc") == 0)) 3014 { 3015 if (*p == '_') 3016 *p = '.'; 3017 else 3018 *p = '_'; 3019#ifdef USE_FOPEN_NOINH 3020 cookie.fp = fopen_noinh_readbin((char *)fname_exp); 3021#else 3022 cookie.fp = mch_fopen((char *)fname_exp, READBIN); 3023#endif 3024 } 3025 } 3026 3027 if (cookie.fp == NULL) 3028 { 3029 if (p_verbose > 0) 3030 { 3031 verbose_enter(); 3032 if (sourcing_name == NULL) 3033 smsg((char_u *)_("could not source \"%s\""), fname); 3034 else 3035 smsg((char_u *)_("line %ld: could not source \"%s\""), 3036 sourcing_lnum, fname); 3037 verbose_leave(); 3038 } 3039 goto theend; 3040 } 3041 3042 /* 3043 * The file exists. 3044 * - In verbose mode, give a message. 3045 * - For a vimrc file, may want to set 'compatible', call vimrc_found(). 3046 */ 3047 if (p_verbose > 1) 3048 { 3049 verbose_enter(); 3050 if (sourcing_name == NULL) 3051 smsg((char_u *)_("sourcing \"%s\""), fname); 3052 else 3053 smsg((char_u *)_("line %ld: sourcing \"%s\""), 3054 sourcing_lnum, fname); 3055 verbose_leave(); 3056 } 3057 if (is_vimrc == DOSO_VIMRC) 3058 vimrc_found(fname_exp, (char_u *)"MYVIMRC"); 3059 else if (is_vimrc == DOSO_GVIMRC) 3060 vimrc_found(fname_exp, (char_u *)"MYGVIMRC"); 3061 3062#ifdef USE_CRNL 3063 /* If no automatic file format: Set default to CR-NL. */ 3064 if (*p_ffs == NUL) 3065 cookie.fileformat = EOL_DOS; 3066 else 3067 cookie.fileformat = EOL_UNKNOWN; 3068 cookie.error = FALSE; 3069#endif 3070 3071#ifdef USE_CR 3072 /* If no automatic file format: Set default to CR. */ 3073 if (*p_ffs == NUL) 3074 cookie.fileformat = EOL_MAC; 3075 else 3076 cookie.fileformat = EOL_UNKNOWN; 3077 cookie.error = FALSE; 3078#endif 3079 3080 cookie.nextline = NULL; 3081 cookie.finished = FALSE; 3082 3083#ifdef FEAT_EVAL 3084 /* 3085 * Check if this script has a breakpoint. 3086 */ 3087 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0); 3088 cookie.fname = fname_exp; 3089 cookie.dbg_tick = debug_tick; 3090 3091 cookie.level = ex_nesting_level; 3092#endif 3093 3094 /* 3095 * Keep the sourcing name/lnum, for recursive calls. 3096 */ 3097 save_sourcing_name = sourcing_name; 3098 sourcing_name = fname_exp; 3099 save_sourcing_lnum = sourcing_lnum; 3100 sourcing_lnum = 0; 3101 3102#ifdef FEAT_MBYTE 3103 cookie.conv.vc_type = CONV_NONE; /* no conversion */ 3104 3105 /* Read the first line so we can check for a UTF-8 BOM. */ 3106 firstline = getsourceline(0, (void *)&cookie, 0); 3107 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef 3108 && firstline[1] == 0xbb && firstline[2] == 0xbf) 3109 { 3110 /* Found BOM; setup conversion, skip over BOM and recode the line. */ 3111 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc); 3112 p = string_convert(&cookie.conv, firstline + 3, NULL); 3113 if (p == NULL) 3114 p = vim_strsave(firstline + 3); 3115 if (p != NULL) 3116 { 3117 vim_free(firstline); 3118 firstline = p; 3119 } 3120 } 3121#endif 3122 3123#ifdef STARTUPTIME 3124 if (time_fd != NULL) 3125 time_push(&tv_rel, &tv_start); 3126#endif 3127 3128#ifdef FEAT_EVAL 3129# ifdef FEAT_PROFILE 3130 if (do_profiling == PROF_YES) 3131 prof_child_enter(&wait_start); /* entering a child now */ 3132# endif 3133 3134 /* Don't use local function variables, if called from a function. 3135 * Also starts profiling timer for nested script. */ 3136 save_funccalp = save_funccal(); 3137 3138 /* 3139 * Check if this script was sourced before to finds its SID. 3140 * If it's new, generate a new SID. 3141 */ 3142 save_current_SID = current_SID; 3143# ifdef UNIX 3144 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0); 3145# endif 3146 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID) 3147 { 3148 si = &SCRIPT_ITEM(current_SID); 3149 if (si->sn_name != NULL 3150 && ( 3151# ifdef UNIX 3152 /* Compare dev/ino when possible, it catches symbolic 3153 * links. Also compare file names, the inode may change 3154 * when the file was edited. */ 3155 ((stat_ok && si->sn_dev_valid) 3156 && (si->sn_dev == st.st_dev 3157 && si->sn_ino == st.st_ino)) || 3158# endif 3159 fnamecmp(si->sn_name, fname_exp) == 0)) 3160 break; 3161 } 3162 if (current_SID == 0) 3163 { 3164 current_SID = ++last_current_SID; 3165 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len)) 3166 == FAIL) 3167 goto almosttheend; 3168 while (script_items.ga_len < current_SID) 3169 { 3170 ++script_items.ga_len; 3171 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL; 3172# ifdef FEAT_PROFILE 3173 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE; 3174# endif 3175 } 3176 si = &SCRIPT_ITEM(current_SID); 3177 si->sn_name = fname_exp; 3178 fname_exp = NULL; 3179# ifdef UNIX 3180 if (stat_ok) 3181 { 3182 si->sn_dev_valid = TRUE; 3183 si->sn_dev = st.st_dev; 3184 si->sn_ino = st.st_ino; 3185 } 3186 else 3187 si->sn_dev_valid = FALSE; 3188# endif 3189 3190 /* Allocate the local script variables to use for this script. */ 3191 new_script_vars(current_SID); 3192 } 3193 3194# ifdef FEAT_PROFILE 3195 if (do_profiling == PROF_YES) 3196 { 3197 int forceit; 3198 3199 /* Check if we do profiling for this script. */ 3200 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit)) 3201 { 3202 script_do_profile(si); 3203 si->sn_pr_force = forceit; 3204 } 3205 if (si->sn_prof_on) 3206 { 3207 ++si->sn_pr_count; 3208 profile_start(&si->sn_pr_start); 3209 profile_zero(&si->sn_pr_children); 3210 } 3211 } 3212# endif 3213#endif 3214 3215 /* 3216 * Call do_cmdline, which will call getsourceline() to get the lines. 3217 */ 3218 do_cmdline(firstline, getsourceline, (void *)&cookie, 3219 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT); 3220 retval = OK; 3221 3222#ifdef FEAT_PROFILE 3223 if (do_profiling == PROF_YES) 3224 { 3225 /* Get "si" again, "script_items" may have been reallocated. */ 3226 si = &SCRIPT_ITEM(current_SID); 3227 if (si->sn_prof_on) 3228 { 3229 profile_end(&si->sn_pr_start); 3230 profile_sub_wait(&wait_start, &si->sn_pr_start); 3231 profile_add(&si->sn_pr_total, &si->sn_pr_start); 3232 profile_self(&si->sn_pr_self, &si->sn_pr_start, 3233 &si->sn_pr_children); 3234 } 3235 } 3236#endif 3237 3238 if (got_int) 3239 EMSG(_(e_interr)); 3240 sourcing_name = save_sourcing_name; 3241 sourcing_lnum = save_sourcing_lnum; 3242 if (p_verbose > 1) 3243 { 3244 verbose_enter(); 3245 smsg((char_u *)_("finished sourcing %s"), fname); 3246 if (sourcing_name != NULL) 3247 smsg((char_u *)_("continuing in %s"), sourcing_name); 3248 verbose_leave(); 3249 } 3250#ifdef STARTUPTIME 3251 if (time_fd != NULL) 3252 { 3253 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname); 3254 time_msg((char *)IObuff, &tv_start); 3255 time_pop(&tv_rel); 3256 } 3257#endif 3258 3259#ifdef FEAT_EVAL 3260 /* 3261 * After a "finish" in debug mode, need to break at first command of next 3262 * sourced file. 3263 */ 3264 if (save_debug_break_level > ex_nesting_level 3265 && debug_break_level == ex_nesting_level) 3266 ++debug_break_level; 3267#endif 3268 3269#ifdef FEAT_EVAL 3270almosttheend: 3271 current_SID = save_current_SID; 3272 restore_funccal(save_funccalp); 3273# ifdef FEAT_PROFILE 3274 if (do_profiling == PROF_YES) 3275 prof_child_exit(&wait_start); /* leaving a child now */ 3276# endif 3277#endif 3278 fclose(cookie.fp); 3279 vim_free(cookie.nextline); 3280 vim_free(firstline); 3281#ifdef FEAT_MBYTE 3282 convert_setup(&cookie.conv, NULL, NULL); 3283#endif 3284 3285theend: 3286 vim_free(fname_exp); 3287 return retval; 3288} 3289 3290#if defined(FEAT_EVAL) || defined(PROTO) 3291 3292/* 3293 * ":scriptnames" 3294 */ 3295 void 3296ex_scriptnames(eap) 3297 exarg_T *eap UNUSED; 3298{ 3299 int i; 3300 3301 for (i = 1; i <= script_items.ga_len && !got_int; ++i) 3302 if (SCRIPT_ITEM(i).sn_name != NULL) 3303 smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name); 3304} 3305 3306# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) 3307/* 3308 * Fix slashes in the list of script names for 'shellslash'. 3309 */ 3310 void 3311scriptnames_slash_adjust() 3312{ 3313 int i; 3314 3315 for (i = 1; i <= script_items.ga_len; ++i) 3316 if (SCRIPT_ITEM(i).sn_name != NULL) 3317 slash_adjust(SCRIPT_ITEM(i).sn_name); 3318} 3319# endif 3320 3321/* 3322 * Get a pointer to a script name. Used for ":verbose set". 3323 */ 3324 char_u * 3325get_scriptname(id) 3326 scid_T id; 3327{ 3328 if (id == SID_MODELINE) 3329 return (char_u *)_("modeline"); 3330 if (id == SID_CMDARG) 3331 return (char_u *)_("--cmd argument"); 3332 if (id == SID_CARG) 3333 return (char_u *)_("-c argument"); 3334 if (id == SID_ENV) 3335 return (char_u *)_("environment variable"); 3336 if (id == SID_ERROR) 3337 return (char_u *)_("error handler"); 3338 return SCRIPT_ITEM(id).sn_name; 3339} 3340 3341# if defined(EXITFREE) || defined(PROTO) 3342 void 3343free_scriptnames() 3344{ 3345 int i; 3346 3347 for (i = script_items.ga_len; i > 0; --i) 3348 vim_free(SCRIPT_ITEM(i).sn_name); 3349 ga_clear(&script_items); 3350} 3351# endif 3352 3353#endif 3354 3355#if defined(USE_CR) || defined(PROTO) 3356 3357# if defined(__MSL__) && (__MSL__ >= 22) 3358/* 3359 * Newer version of the Metrowerks library handle DOS and UNIX files 3360 * without help. 3361 * Test with earlier versions, MSL 2.2 is the library supplied with 3362 * Codewarrior Pro 2. 3363 */ 3364 char * 3365fgets_cr(s, n, stream) 3366 char *s; 3367 int n; 3368 FILE *stream; 3369{ 3370 return fgets(s, n, stream); 3371} 3372# else 3373/* 3374 * Version of fgets() which also works for lines ending in a <CR> only 3375 * (Macintosh format). 3376 * For older versions of the Metrowerks library. 3377 * At least CodeWarrior 9 needed this code. 3378 */ 3379 char * 3380fgets_cr(s, n, stream) 3381 char *s; 3382 int n; 3383 FILE *stream; 3384{ 3385 int c = 0; 3386 int char_read = 0; 3387 3388 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1) 3389 { 3390 c = fgetc(stream); 3391 s[char_read++] = c; 3392 /* If the file is in DOS format, we need to skip a NL after a CR. I 3393 * thought it was the other way around, but this appears to work... */ 3394 if (c == '\n') 3395 { 3396 c = fgetc(stream); 3397 if (c != '\r') 3398 ungetc(c, stream); 3399 } 3400 } 3401 3402 s[char_read] = 0; 3403 if (char_read == 0) 3404 return NULL; 3405 3406 if (feof(stream) && char_read == 1) 3407 return NULL; 3408 3409 return s; 3410} 3411# endif 3412#endif 3413 3414/* 3415 * Get one full line from a sourced file. 3416 * Called by do_cmdline() when it's called from do_source(). 3417 * 3418 * Return a pointer to the line in allocated memory. 3419 * Return NULL for end-of-file or some error. 3420 */ 3421 char_u * 3422getsourceline(c, cookie, indent) 3423 int c UNUSED; 3424 void *cookie; 3425 int indent UNUSED; 3426{ 3427 struct source_cookie *sp = (struct source_cookie *)cookie; 3428 char_u *line; 3429 char_u *p, *s; 3430 3431#ifdef FEAT_EVAL 3432 /* If breakpoints have been added/deleted need to check for it. */ 3433 if (sp->dbg_tick < debug_tick) 3434 { 3435 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum); 3436 sp->dbg_tick = debug_tick; 3437 } 3438# ifdef FEAT_PROFILE 3439 if (do_profiling == PROF_YES) 3440 script_line_end(); 3441# endif 3442#endif 3443 /* 3444 * Get current line. If there is a read-ahead line, use it, otherwise get 3445 * one now. 3446 */ 3447 if (sp->finished) 3448 line = NULL; 3449 else if (sp->nextline == NULL) 3450 line = get_one_sourceline(sp); 3451 else 3452 { 3453 line = sp->nextline; 3454 sp->nextline = NULL; 3455 ++sourcing_lnum; 3456 } 3457#ifdef FEAT_PROFILE 3458 if (line != NULL && do_profiling == PROF_YES) 3459 script_line_start(); 3460#endif 3461 3462 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't 3463 * contain the 'C' flag. */ 3464 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) 3465 { 3466 /* compensate for the one line read-ahead */ 3467 --sourcing_lnum; 3468 for (;;) 3469 { 3470 sp->nextline = get_one_sourceline(sp); 3471 if (sp->nextline == NULL) 3472 break; 3473 p = skipwhite(sp->nextline); 3474 if (*p != '\\') 3475 break; 3476 s = alloc((unsigned)(STRLEN(line) + STRLEN(p))); 3477 if (s == NULL) /* out of memory */ 3478 break; 3479 STRCPY(s, line); 3480 STRCAT(s, p + 1); 3481 vim_free(line); 3482 line = s; 3483 vim_free(sp->nextline); 3484 } 3485 } 3486 3487#ifdef FEAT_MBYTE 3488 if (line != NULL && sp->conv.vc_type != CONV_NONE) 3489 { 3490 /* Convert the encoding of the script line. */ 3491 s = string_convert(&sp->conv, line, NULL); 3492 if (s != NULL) 3493 { 3494 vim_free(line); 3495 line = s; 3496 } 3497 } 3498#endif 3499 3500#ifdef FEAT_EVAL 3501 /* Did we encounter a breakpoint? */ 3502 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum) 3503 { 3504 dbg_breakpoint(sp->fname, sourcing_lnum); 3505 /* Find next breakpoint. */ 3506 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum); 3507 sp->dbg_tick = debug_tick; 3508 } 3509#endif 3510 3511 return line; 3512} 3513 3514 static char_u * 3515get_one_sourceline(sp) 3516 struct source_cookie *sp; 3517{ 3518 garray_T ga; 3519 int len; 3520 int c; 3521 char_u *buf; 3522#ifdef USE_CRNL 3523 int has_cr; /* CR-LF found */ 3524#endif 3525#ifdef USE_CR 3526 char_u *scan; 3527#endif 3528 int have_read = FALSE; 3529 3530 /* use a growarray to store the sourced line */ 3531 ga_init2(&ga, 1, 250); 3532 3533 /* 3534 * Loop until there is a finished line (or end-of-file). 3535 */ 3536 sourcing_lnum++; 3537 for (;;) 3538 { 3539 /* make room to read at least 120 (more) characters */ 3540 if (ga_grow(&ga, 120) == FAIL) 3541 break; 3542 buf = (char_u *)ga.ga_data; 3543 3544#ifdef USE_CR 3545 if (sp->fileformat == EOL_MAC) 3546 { 3547 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len, 3548 sp->fp) == NULL) 3549 break; 3550 } 3551 else 3552#endif 3553 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len, 3554 sp->fp) == NULL) 3555 break; 3556 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len); 3557#ifdef USE_CRNL 3558 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the 3559 * CTRL-Z by its own, or after a NL. */ 3560 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n')) 3561 && sp->fileformat == EOL_DOS 3562 && buf[len - 1] == Ctrl_Z) 3563 { 3564 buf[len - 1] = NUL; 3565 break; 3566 } 3567#endif 3568 3569#ifdef USE_CR 3570 /* If the read doesn't stop on a new line, and there's 3571 * some CR then we assume a Mac format */ 3572 if (sp->fileformat == EOL_UNKNOWN) 3573 { 3574 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL) 3575 sp->fileformat = EOL_MAC; 3576 else 3577 sp->fileformat = EOL_UNIX; 3578 } 3579 3580 if (sp->fileformat == EOL_MAC) 3581 { 3582 scan = vim_strchr(buf, '\r'); 3583 3584 if (scan != NULL) 3585 { 3586 *scan = '\n'; 3587 if (*(scan + 1) != 0) 3588 { 3589 *(scan + 1) = 0; 3590 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR); 3591 } 3592 } 3593 len = STRLEN(buf); 3594 } 3595#endif 3596 3597 have_read = TRUE; 3598 ga.ga_len = len; 3599 3600 /* If the line was longer than the buffer, read more. */ 3601 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n') 3602 continue; 3603 3604 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */ 3605 { 3606#ifdef USE_CRNL 3607 has_cr = (len >= 2 && buf[len - 2] == '\r'); 3608 if (sp->fileformat == EOL_UNKNOWN) 3609 { 3610 if (has_cr) 3611 sp->fileformat = EOL_DOS; 3612 else 3613 sp->fileformat = EOL_UNIX; 3614 } 3615 3616 if (sp->fileformat == EOL_DOS) 3617 { 3618 if (has_cr) /* replace trailing CR */ 3619 { 3620 buf[len - 2] = '\n'; 3621 --len; 3622 --ga.ga_len; 3623 } 3624 else /* lines like ":map xx yy^M" will have failed */ 3625 { 3626 if (!sp->error) 3627 { 3628 msg_source(hl_attr(HLF_W)); 3629 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing")); 3630 } 3631 sp->error = TRUE; 3632 sp->fileformat = EOL_UNIX; 3633 } 3634 } 3635#endif 3636 /* The '\n' is escaped if there is an odd number of ^V's just 3637 * before it, first set "c" just before the 'V's and then check 3638 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */ 3639 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--) 3640 ; 3641 if ((len & 1) != (c & 1)) /* escaped NL, read more */ 3642 { 3643 sourcing_lnum++; 3644 continue; 3645 } 3646 3647 buf[len - 1] = NUL; /* remove the NL */ 3648 } 3649 3650 /* 3651 * Check for ^C here now and then, so recursive :so can be broken. 3652 */ 3653 line_breakcheck(); 3654 break; 3655 } 3656 3657 if (have_read) 3658 return (char_u *)ga.ga_data; 3659 3660 vim_free(ga.ga_data); 3661 return NULL; 3662} 3663 3664#if defined(FEAT_PROFILE) || defined(PROTO) 3665/* 3666 * Called when starting to read a script line. 3667 * "sourcing_lnum" must be correct! 3668 * When skipping lines it may not actually be executed, but we won't find out 3669 * until later and we need to store the time now. 3670 */ 3671 void 3672script_line_start() 3673{ 3674 scriptitem_T *si; 3675 sn_prl_T *pp; 3676 3677 if (current_SID <= 0 || current_SID > script_items.ga_len) 3678 return; 3679 si = &SCRIPT_ITEM(current_SID); 3680 if (si->sn_prof_on && sourcing_lnum >= 1) 3681 { 3682 /* Grow the array before starting the timer, so that the time spent 3683 * here isn't counted. */ 3684 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len)); 3685 si->sn_prl_idx = sourcing_lnum - 1; 3686 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx 3687 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen) 3688 { 3689 /* Zero counters for a line that was not used before. */ 3690 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len); 3691 pp->snp_count = 0; 3692 profile_zero(&pp->sn_prl_total); 3693 profile_zero(&pp->sn_prl_self); 3694 ++si->sn_prl_ga.ga_len; 3695 } 3696 si->sn_prl_execed = FALSE; 3697 profile_start(&si->sn_prl_start); 3698 profile_zero(&si->sn_prl_children); 3699 profile_get_wait(&si->sn_prl_wait); 3700 } 3701} 3702 3703/* 3704 * Called when actually executing a function line. 3705 */ 3706 void 3707script_line_exec() 3708{ 3709 scriptitem_T *si; 3710 3711 if (current_SID <= 0 || current_SID > script_items.ga_len) 3712 return; 3713 si = &SCRIPT_ITEM(current_SID); 3714 if (si->sn_prof_on && si->sn_prl_idx >= 0) 3715 si->sn_prl_execed = TRUE; 3716} 3717 3718/* 3719 * Called when done with a function line. 3720 */ 3721 void 3722script_line_end() 3723{ 3724 scriptitem_T *si; 3725 sn_prl_T *pp; 3726 3727 if (current_SID <= 0 || current_SID > script_items.ga_len) 3728 return; 3729 si = &SCRIPT_ITEM(current_SID); 3730 if (si->sn_prof_on && si->sn_prl_idx >= 0 3731 && si->sn_prl_idx < si->sn_prl_ga.ga_len) 3732 { 3733 if (si->sn_prl_execed) 3734 { 3735 pp = &PRL_ITEM(si, si->sn_prl_idx); 3736 ++pp->snp_count; 3737 profile_end(&si->sn_prl_start); 3738 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start); 3739 profile_add(&pp->sn_prl_total, &si->sn_prl_start); 3740 profile_self(&pp->sn_prl_self, &si->sn_prl_start, 3741 &si->sn_prl_children); 3742 } 3743 si->sn_prl_idx = -1; 3744 } 3745} 3746#endif 3747 3748/* 3749 * ":scriptencoding": Set encoding conversion for a sourced script. 3750 * Without the multi-byte feature it's simply ignored. 3751 */ 3752 void 3753ex_scriptencoding(eap) 3754 exarg_T *eap UNUSED; 3755{ 3756#ifdef FEAT_MBYTE 3757 struct source_cookie *sp; 3758 char_u *name; 3759 3760 if (!getline_equal(eap->getline, eap->cookie, getsourceline)) 3761 { 3762 EMSG(_("E167: :scriptencoding used outside of a sourced file")); 3763 return; 3764 } 3765 3766 if (*eap->arg != NUL) 3767 { 3768 name = enc_canonize(eap->arg); 3769 if (name == NULL) /* out of memory */ 3770 return; 3771 } 3772 else 3773 name = eap->arg; 3774 3775 /* Setup for conversion from the specified encoding to 'encoding'. */ 3776 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie); 3777 convert_setup(&sp->conv, name, p_enc); 3778 3779 if (name != eap->arg) 3780 vim_free(name); 3781#endif 3782} 3783 3784#if defined(FEAT_EVAL) || defined(PROTO) 3785/* 3786 * ":finish": Mark a sourced file as finished. 3787 */ 3788 void 3789ex_finish(eap) 3790 exarg_T *eap; 3791{ 3792 if (getline_equal(eap->getline, eap->cookie, getsourceline)) 3793 do_finish(eap, FALSE); 3794 else 3795 EMSG(_("E168: :finish used outside of a sourced file")); 3796} 3797 3798/* 3799 * Mark a sourced file as finished. Possibly makes the ":finish" pending. 3800 * Also called for a pending finish at the ":endtry" or after returning from 3801 * an extra do_cmdline(). "reanimate" is used in the latter case. 3802 */ 3803 void 3804do_finish(eap, reanimate) 3805 exarg_T *eap; 3806 int reanimate; 3807{ 3808 int idx; 3809 3810 if (reanimate) 3811 ((struct source_cookie *)getline_cookie(eap->getline, 3812 eap->cookie))->finished = FALSE; 3813 3814 /* 3815 * Cleanup (and inactivate) conditionals, but stop when a try conditional 3816 * not in its finally clause (which then is to be executed next) is found. 3817 * In this case, make the ":finish" pending for execution at the ":endtry". 3818 * Otherwise, finish normally. 3819 */ 3820 idx = cleanup_conditionals(eap->cstack, 0, TRUE); 3821 if (idx >= 0) 3822 { 3823 eap->cstack->cs_pending[idx] = CSTP_FINISH; 3824 report_make_pending(CSTP_FINISH, NULL); 3825 } 3826 else 3827 ((struct source_cookie *)getline_cookie(eap->getline, 3828 eap->cookie))->finished = TRUE; 3829} 3830 3831 3832/* 3833 * Return TRUE when a sourced file had the ":finish" command: Don't give error 3834 * message for missing ":endif". 3835 * Return FALSE when not sourcing a file. 3836 */ 3837 int 3838source_finished(fgetline, cookie) 3839 char_u *(*fgetline) __ARGS((int, void *, int)); 3840 void *cookie; 3841{ 3842 return (getline_equal(fgetline, cookie, getsourceline) 3843 && ((struct source_cookie *)getline_cookie( 3844 fgetline, cookie))->finished); 3845} 3846#endif 3847 3848#if defined(FEAT_LISTCMDS) || defined(PROTO) 3849/* 3850 * ":checktime [buffer]" 3851 */ 3852 void 3853ex_checktime(eap) 3854 exarg_T *eap; 3855{ 3856 buf_T *buf; 3857 int save_no_check_timestamps = no_check_timestamps; 3858 3859 no_check_timestamps = 0; 3860 if (eap->addr_count == 0) /* default is all buffers */ 3861 check_timestamps(FALSE); 3862 else 3863 { 3864 buf = buflist_findnr((int)eap->line2); 3865 if (buf != NULL) /* cannot happen? */ 3866 (void)buf_check_timestamp(buf, FALSE); 3867 } 3868 no_check_timestamps = save_no_check_timestamps; 3869} 3870#endif 3871 3872#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 3873 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG)) 3874# define HAVE_GET_LOCALE_VAL 3875static char *get_locale_val __ARGS((int what)); 3876 3877 static char * 3878get_locale_val(what) 3879 int what; 3880{ 3881 char *loc; 3882 3883 /* Obtain the locale value from the libraries. For DJGPP this is 3884 * redefined and it doesn't use the arguments. */ 3885 loc = setlocale(what, NULL); 3886 3887# ifdef WIN32 3888 if (loc != NULL) 3889 { 3890 char_u *p; 3891 3892 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when 3893 * one of the values (e.g., LC_CTYPE) differs. */ 3894 p = vim_strchr(loc, '='); 3895 if (p != NULL) 3896 { 3897 loc = ++p; 3898 while (*p != NUL) /* remove trailing newline */ 3899 { 3900 if (*p < ' ' || *p == ';') 3901 { 3902 *p = NUL; 3903 break; 3904 } 3905 ++p; 3906 } 3907 } 3908 } 3909# endif 3910 3911 return loc; 3912} 3913#endif 3914 3915 3916#ifdef WIN32 3917/* 3918 * On MS-Windows locale names are strings like "German_Germany.1252", but 3919 * gettext expects "de". Try to translate one into another here for a few 3920 * supported languages. 3921 */ 3922 static char_u * 3923gettext_lang(char_u *name) 3924{ 3925 int i; 3926 static char *(mtable[]) = { 3927 "afrikaans", "af", 3928 "czech", "cs", 3929 "dutch", "nl", 3930 "german", "de", 3931 "english_united kingdom", "en_GB", 3932 "spanish", "es", 3933 "french", "fr", 3934 "italian", "it", 3935 "japanese", "ja", 3936 "korean", "ko", 3937 "norwegian", "no", 3938 "polish", "pl", 3939 "russian", "ru", 3940 "slovak", "sk", 3941 "swedish", "sv", 3942 "ukrainian", "uk", 3943 "chinese_china", "zh_CN", 3944 "chinese_taiwan", "zh_TW", 3945 NULL}; 3946 3947 for (i = 0; mtable[i] != NULL; i += 2) 3948 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0) 3949 return mtable[i + 1]; 3950 return name; 3951} 3952#endif 3953 3954#if defined(FEAT_MULTI_LANG) || defined(PROTO) 3955/* 3956 * Obtain the current messages language. Used to set the default for 3957 * 'helplang'. May return NULL or an empty string. 3958 */ 3959 char_u * 3960get_mess_lang() 3961{ 3962 char_u *p; 3963 3964# ifdef HAVE_GET_LOCALE_VAL 3965# if defined(LC_MESSAGES) 3966 p = (char_u *)get_locale_val(LC_MESSAGES); 3967# else 3968 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG 3969 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME 3970 * and LC_MONETARY may be set differently for a Japanese working in the 3971 * US. */ 3972 p = (char_u *)get_locale_val(LC_COLLATE); 3973# endif 3974# else 3975 p = mch_getenv((char_u *)"LC_ALL"); 3976 if (p == NULL || *p == NUL) 3977 { 3978 p = mch_getenv((char_u *)"LC_MESSAGES"); 3979 if (p == NULL || *p == NUL) 3980 p = mch_getenv((char_u *)"LANG"); 3981 } 3982# endif 3983# ifdef WIN32 3984 p = gettext_lang(p); 3985# endif 3986 return p; 3987} 3988#endif 3989 3990/* Complicated #if; matches with where get_mess_env() is used below. */ 3991#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 3992 && defined(LC_MESSAGES))) \ 3993 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 3994 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \ 3995 && !defined(LC_MESSAGES)) 3996static char_u *get_mess_env __ARGS((void)); 3997 3998/* 3999 * Get the language used for messages from the environment. 4000 */ 4001 static char_u * 4002get_mess_env() 4003{ 4004 char_u *p; 4005 4006 p = mch_getenv((char_u *)"LC_ALL"); 4007 if (p == NULL || *p == NUL) 4008 { 4009 p = mch_getenv((char_u *)"LC_MESSAGES"); 4010 if (p == NULL || *p == NUL) 4011 { 4012 p = mch_getenv((char_u *)"LANG"); 4013 if (p != NULL && VIM_ISDIGIT(*p)) 4014 p = NULL; /* ignore something like "1043" */ 4015# ifdef HAVE_GET_LOCALE_VAL 4016 if (p == NULL || *p == NUL) 4017 p = (char_u *)get_locale_val(LC_CTYPE); 4018# endif 4019 } 4020 } 4021 return p; 4022} 4023#endif 4024 4025#if defined(FEAT_EVAL) || defined(PROTO) 4026 4027/* 4028 * Set the "v:lang" variable according to the current locale setting. 4029 * Also do "v:lc_time"and "v:ctype". 4030 */ 4031 void 4032set_lang_var() 4033{ 4034 char_u *loc; 4035 4036# ifdef HAVE_GET_LOCALE_VAL 4037 loc = (char_u *)get_locale_val(LC_CTYPE); 4038# else 4039 /* setlocale() not supported: use the default value */ 4040 loc = (char_u *)"C"; 4041# endif 4042 set_vim_var_string(VV_CTYPE, loc, -1); 4043 4044 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall 4045 * back to LC_CTYPE if it's empty. */ 4046# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES) 4047 loc = (char_u *)get_locale_val(LC_MESSAGES); 4048# else 4049 loc = get_mess_env(); 4050# endif 4051 set_vim_var_string(VV_LANG, loc, -1); 4052 4053# ifdef HAVE_GET_LOCALE_VAL 4054 loc = (char_u *)get_locale_val(LC_TIME); 4055# endif 4056 set_vim_var_string(VV_LC_TIME, loc, -1); 4057} 4058#endif 4059 4060#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 4061 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) 4062/* 4063 * ":language": Set the language (locale). 4064 */ 4065 void 4066ex_language(eap) 4067 exarg_T *eap; 4068{ 4069 char *loc; 4070 char_u *p; 4071 char_u *name; 4072 int what = LC_ALL; 4073 char *whatstr = ""; 4074#ifdef LC_MESSAGES 4075# define VIM_LC_MESSAGES LC_MESSAGES 4076#else 4077# define VIM_LC_MESSAGES 6789 4078#endif 4079 4080 name = eap->arg; 4081 4082 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument. 4083 * Allow abbreviation, but require at least 3 characters to avoid 4084 * confusion with a two letter language name "me" or "ct". */ 4085 p = skiptowhite(eap->arg); 4086 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3) 4087 { 4088 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0) 4089 { 4090 what = VIM_LC_MESSAGES; 4091 name = skipwhite(p); 4092 whatstr = "messages "; 4093 } 4094 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0) 4095 { 4096 what = LC_CTYPE; 4097 name = skipwhite(p); 4098 whatstr = "ctype "; 4099 } 4100 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0) 4101 { 4102 what = LC_TIME; 4103 name = skipwhite(p); 4104 whatstr = "time "; 4105 } 4106 } 4107 4108 if (*name == NUL) 4109 { 4110#ifndef LC_MESSAGES 4111 if (what == VIM_LC_MESSAGES) 4112 p = get_mess_env(); 4113 else 4114#endif 4115 p = (char_u *)setlocale(what, NULL); 4116 if (p == NULL || *p == NUL) 4117 p = (char_u *)"Unknown"; 4118 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p); 4119 } 4120 else 4121 { 4122#ifndef LC_MESSAGES 4123 if (what == VIM_LC_MESSAGES) 4124 loc = ""; 4125 else 4126#endif 4127 { 4128 loc = setlocale(what, (char *)name); 4129#if defined(FEAT_FLOAT) && defined(LC_NUMERIC) 4130 /* Make sure strtod() uses a decimal point, not a comma. */ 4131 setlocale(LC_NUMERIC, "C"); 4132#endif 4133 } 4134 if (loc == NULL) 4135 EMSG2(_("E197: Cannot set language to \"%s\""), name); 4136 else 4137 { 4138#ifdef HAVE_NL_MSG_CAT_CNTR 4139 /* Need to do this for GNU gettext, otherwise cached translations 4140 * will be used again. */ 4141 extern int _nl_msg_cat_cntr; 4142 4143 ++_nl_msg_cat_cntr; 4144#endif 4145 /* Reset $LC_ALL, otherwise it would overrule everything. */ 4146 vim_setenv((char_u *)"LC_ALL", (char_u *)""); 4147 4148 if (what != LC_TIME) 4149 { 4150 /* Tell gettext() what to translate to. It apparently doesn't 4151 * use the currently effective locale. Also do this when 4152 * FEAT_GETTEXT isn't defined, so that shell commands use this 4153 * value. */ 4154 if (what == LC_ALL) 4155 { 4156 vim_setenv((char_u *)"LANG", name); 4157# ifdef WIN32 4158 /* Apparently MS-Windows printf() may cause a crash when 4159 * we give it 8-bit text while it's expecting text in the 4160 * current locale. This call avoids that. */ 4161 setlocale(LC_CTYPE, "C"); 4162# endif 4163 } 4164 if (what != LC_CTYPE) 4165 { 4166 char_u *mname; 4167#ifdef WIN32 4168 mname = gettext_lang(name); 4169#else 4170 mname = name; 4171#endif 4172 vim_setenv((char_u *)"LC_MESSAGES", mname); 4173#ifdef FEAT_MULTI_LANG 4174 set_helplang_default(mname); 4175#endif 4176 } 4177 } 4178 4179# ifdef FEAT_EVAL 4180 /* Set v:lang, v:lc_time and v:ctype to the final result. */ 4181 set_lang_var(); 4182# endif 4183 } 4184 } 4185} 4186 4187# if defined(FEAT_CMDL_COMPL) || defined(PROTO) 4188/* 4189 * Function given to ExpandGeneric() to obtain the possible arguments of the 4190 * ":language" command. 4191 */ 4192 char_u * 4193get_lang_arg(xp, idx) 4194 expand_T *xp UNUSED; 4195 int idx; 4196{ 4197 if (idx == 0) 4198 return (char_u *)"messages"; 4199 if (idx == 1) 4200 return (char_u *)"ctype"; 4201 if (idx == 2) 4202 return (char_u *)"time"; 4203 return NULL; 4204} 4205# endif 4206 4207#endif 4208