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_cmds.c: some 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 21#ifdef FEAT_EX_EXTRA 22static int linelen __ARGS((int *has_tab)); 23#endif 24static void do_filter __ARGS((linenr_T line1, linenr_T line2, exarg_T *eap, char_u *cmd, int do_in, int do_out)); 25#ifdef FEAT_VIMINFO 26static char_u *viminfo_filename __ARGS((char_u *)); 27static void do_viminfo __ARGS((FILE *fp_in, FILE *fp_out, int flags)); 28static int viminfo_encoding __ARGS((vir_T *virp)); 29static int read_viminfo_up_to_marks __ARGS((vir_T *virp, int forceit, int writing)); 30#endif 31 32static int check_overwrite __ARGS((exarg_T *eap, buf_T *buf, char_u *fname, char_u *ffname, int other)); 33static int check_readonly __ARGS((int *forceit, buf_T *buf)); 34#ifdef FEAT_AUTOCMD 35static void delbuf_msg __ARGS((char_u *name)); 36#endif 37static int 38#ifdef __BORLANDC__ 39 _RTLENTRYF 40#endif 41 help_compare __ARGS((const void *s1, const void *s2)); 42 43/* 44 * ":ascii" and "ga". 45 */ 46 void 47do_ascii(eap) 48 exarg_T *eap UNUSED; 49{ 50 int c; 51 int cval; 52 char buf1[20]; 53 char buf2[20]; 54 char_u buf3[7]; 55#ifdef FEAT_MBYTE 56 int cc[MAX_MCO]; 57 int ci = 0; 58 int len; 59 60 if (enc_utf8) 61 c = utfc_ptr2char(ml_get_cursor(), cc); 62 else 63#endif 64 c = gchar_cursor(); 65 if (c == NUL) 66 { 67 MSG("NUL"); 68 return; 69 } 70 71#ifdef FEAT_MBYTE 72 IObuff[0] = NUL; 73 if (!has_mbyte || (enc_dbcs != 0 && c < 0x100) || c < 0x80) 74#endif 75 { 76 if (c == NL) /* NUL is stored as NL */ 77 c = NUL; 78 if (c == CAR && get_fileformat(curbuf) == EOL_MAC) 79 cval = NL; /* NL is stored as CR */ 80 else 81 cval = c; 82 if (vim_isprintc_strict(c) && (c < ' ' 83#ifndef EBCDIC 84 || c > '~' 85#endif 86 )) 87 { 88 transchar_nonprint(buf3, c); 89 vim_snprintf(buf1, sizeof(buf1), " <%s>", (char *)buf3); 90 } 91 else 92 buf1[0] = NUL; 93#ifndef EBCDIC 94 if (c >= 0x80) 95 vim_snprintf(buf2, sizeof(buf2), " <M-%s>", 96 (char *)transchar(c & 0x7f)); 97 else 98#endif 99 buf2[0] = NUL; 100 vim_snprintf((char *)IObuff, IOSIZE, 101 _("<%s>%s%s %d, Hex %02x, Octal %03o"), 102 transchar(c), buf1, buf2, cval, cval, cval); 103#ifdef FEAT_MBYTE 104 if (enc_utf8) 105 c = cc[ci++]; 106 else 107 c = 0; 108#endif 109 } 110 111#ifdef FEAT_MBYTE 112 /* Repeat for combining characters. */ 113 while (has_mbyte && (c >= 0x100 || (enc_utf8 && c >= 0x80))) 114 { 115 len = (int)STRLEN(IObuff); 116 /* This assumes every multi-byte char is printable... */ 117 if (len > 0) 118 IObuff[len++] = ' '; 119 IObuff[len++] = '<'; 120 if (enc_utf8 && utf_iscomposing(c) 121# ifdef USE_GUI 122 && !gui.in_use 123# endif 124 ) 125 IObuff[len++] = ' '; /* draw composing char on top of a space */ 126 len += (*mb_char2bytes)(c, IObuff + len); 127 vim_snprintf((char *)IObuff + len, IOSIZE - len, 128 c < 0x10000 ? _("> %d, Hex %04x, Octal %o") 129 : _("> %d, Hex %08x, Octal %o"), c, c, c); 130 if (ci == MAX_MCO) 131 break; 132 if (enc_utf8) 133 c = cc[ci++]; 134 else 135 c = 0; 136 } 137#endif 138 139 msg(IObuff); 140} 141 142#if defined(FEAT_EX_EXTRA) || defined(PROTO) 143/* 144 * ":left", ":center" and ":right": align text. 145 */ 146 void 147ex_align(eap) 148 exarg_T *eap; 149{ 150 pos_T save_curpos; 151 int len; 152 int indent = 0; 153 int new_indent; 154 int has_tab; 155 int width; 156 157#ifdef FEAT_RIGHTLEFT 158 if (curwin->w_p_rl) 159 { 160 /* switch left and right aligning */ 161 if (eap->cmdidx == CMD_right) 162 eap->cmdidx = CMD_left; 163 else if (eap->cmdidx == CMD_left) 164 eap->cmdidx = CMD_right; 165 } 166#endif 167 168 width = atoi((char *)eap->arg); 169 save_curpos = curwin->w_cursor; 170 if (eap->cmdidx == CMD_left) /* width is used for new indent */ 171 { 172 if (width >= 0) 173 indent = width; 174 } 175 else 176 { 177 /* 178 * if 'textwidth' set, use it 179 * else if 'wrapmargin' set, use it 180 * if invalid value, use 80 181 */ 182 if (width <= 0) 183 width = curbuf->b_p_tw; 184 if (width == 0 && curbuf->b_p_wm > 0) 185 width = W_WIDTH(curwin) - curbuf->b_p_wm; 186 if (width <= 0) 187 width = 80; 188 } 189 190 if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) 191 return; 192 193 for (curwin->w_cursor.lnum = eap->line1; 194 curwin->w_cursor.lnum <= eap->line2; ++curwin->w_cursor.lnum) 195 { 196 if (eap->cmdidx == CMD_left) /* left align */ 197 new_indent = indent; 198 else 199 { 200 has_tab = FALSE; /* avoid uninit warnings */ 201 len = linelen(eap->cmdidx == CMD_right ? &has_tab 202 : NULL) - get_indent(); 203 204 if (len <= 0) /* skip blank lines */ 205 continue; 206 207 if (eap->cmdidx == CMD_center) 208 new_indent = (width - len) / 2; 209 else 210 { 211 new_indent = width - len; /* right align */ 212 213 /* 214 * Make sure that embedded TABs don't make the text go too far 215 * to the right. 216 */ 217 if (has_tab) 218 while (new_indent > 0) 219 { 220 (void)set_indent(new_indent, 0); 221 if (linelen(NULL) <= width) 222 { 223 /* 224 * Now try to move the line as much as possible to 225 * the right. Stop when it moves too far. 226 */ 227 do 228 (void)set_indent(++new_indent, 0); 229 while (linelen(NULL) <= width); 230 --new_indent; 231 break; 232 } 233 --new_indent; 234 } 235 } 236 } 237 if (new_indent < 0) 238 new_indent = 0; 239 (void)set_indent(new_indent, 0); /* set indent */ 240 } 241 changed_lines(eap->line1, 0, eap->line2 + 1, 0L); 242 curwin->w_cursor = save_curpos; 243 beginline(BL_WHITE | BL_FIX); 244} 245 246/* 247 * Get the length of the current line, excluding trailing white space. 248 */ 249 static int 250linelen(has_tab) 251 int *has_tab; 252{ 253 char_u *line; 254 char_u *first; 255 char_u *last; 256 int save; 257 int len; 258 259 /* find the first non-blank character */ 260 line = ml_get_curline(); 261 first = skipwhite(line); 262 263 /* find the character after the last non-blank character */ 264 for (last = first + STRLEN(first); 265 last > first && vim_iswhite(last[-1]); --last) 266 ; 267 save = *last; 268 *last = NUL; 269 len = linetabsize(line); /* get line length */ 270 if (has_tab != NULL) /* check for embedded TAB */ 271 *has_tab = (vim_strrchr(first, TAB) != NULL); 272 *last = save; 273 274 return len; 275} 276 277/* Buffer for two lines used during sorting. They are allocated to 278 * contain the longest line being sorted. */ 279static char_u *sortbuf1; 280static char_u *sortbuf2; 281 282static int sort_ic; /* ignore case */ 283static int sort_nr; /* sort on number */ 284static int sort_rx; /* sort on regex instead of skipping it */ 285 286static int sort_abort; /* flag to indicate if sorting has been interrupted */ 287 288/* Struct to store info to be sorted. */ 289typedef struct 290{ 291 linenr_T lnum; /* line number */ 292 long start_col_nr; /* starting column number or number */ 293 long end_col_nr; /* ending column number */ 294} sorti_T; 295 296static int 297#ifdef __BORLANDC__ 298_RTLENTRYF 299#endif 300sort_compare __ARGS((const void *s1, const void *s2)); 301 302 static int 303#ifdef __BORLANDC__ 304_RTLENTRYF 305#endif 306sort_compare(s1, s2) 307 const void *s1; 308 const void *s2; 309{ 310 sorti_T l1 = *(sorti_T *)s1; 311 sorti_T l2 = *(sorti_T *)s2; 312 int result = 0; 313 314 /* If the user interrupts, there's no way to stop qsort() immediately, but 315 * if we return 0 every time, qsort will assume it's done sorting and 316 * exit. */ 317 if (sort_abort) 318 return 0; 319 fast_breakcheck(); 320 if (got_int) 321 sort_abort = TRUE; 322 323 /* When sorting numbers "start_col_nr" is the number, not the column 324 * number. */ 325 if (sort_nr) 326 result = l1.start_col_nr - l2.start_col_nr; 327 else 328 { 329 /* We need to copy one line into "sortbuf1", because there is no 330 * guarantee that the first pointer becomes invalid when obtaining the 331 * second one. */ 332 STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr, 333 l1.end_col_nr - l1.start_col_nr + 1); 334 sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0; 335 STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr, 336 l2.end_col_nr - l2.start_col_nr + 1); 337 sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0; 338 339 result = sort_ic ? STRICMP(sortbuf1, sortbuf2) 340 : STRCMP(sortbuf1, sortbuf2); 341 } 342 343 /* If two lines have the same value, preserve the original line order. */ 344 if (result == 0) 345 return (int)(l1.lnum - l2.lnum); 346 return result; 347} 348 349/* 350 * ":sort". 351 */ 352 void 353ex_sort(eap) 354 exarg_T *eap; 355{ 356 regmatch_T regmatch; 357 int len; 358 linenr_T lnum; 359 long maxlen = 0; 360 sorti_T *nrs; 361 size_t count = (size_t)(eap->line2 - eap->line1 + 1); 362 size_t i; 363 char_u *p; 364 char_u *s; 365 char_u *s2; 366 char_u c; /* temporary character storage */ 367 int unique = FALSE; 368 long deleted; 369 colnr_T start_col; 370 colnr_T end_col; 371 int sort_oct; /* sort on octal number */ 372 int sort_hex; /* sort on hex number */ 373 374 /* Sorting one line is really quick! */ 375 if (count <= 1) 376 return; 377 378 if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) 379 return; 380 sortbuf1 = NULL; 381 sortbuf2 = NULL; 382 regmatch.regprog = NULL; 383 nrs = (sorti_T *)lalloc((long_u)(count * sizeof(sorti_T)), TRUE); 384 if (nrs == NULL) 385 goto sortend; 386 387 sort_abort = sort_ic = sort_rx = sort_nr = sort_oct = sort_hex = 0; 388 389 for (p = eap->arg; *p != NUL; ++p) 390 { 391 if (vim_iswhite(*p)) 392 ; 393 else if (*p == 'i') 394 sort_ic = TRUE; 395 else if (*p == 'r') 396 sort_rx = TRUE; 397 else if (*p == 'n') 398 sort_nr = 2; 399 else if (*p == 'o') 400 sort_oct = 2; 401 else if (*p == 'x') 402 sort_hex = 2; 403 else if (*p == 'u') 404 unique = TRUE; 405 else if (*p == '"') /* comment start */ 406 break; 407 else if (check_nextcmd(p) != NULL) 408 { 409 eap->nextcmd = check_nextcmd(p); 410 break; 411 } 412 else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) 413 { 414 s = skip_regexp(p + 1, *p, TRUE, NULL); 415 if (*s != *p) 416 { 417 EMSG(_(e_invalpat)); 418 goto sortend; 419 } 420 *s = NUL; 421 /* Use last search pattern if sort pattern is empty. */ 422 if (s == p + 1 && last_search_pat() != NULL) 423 regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC); 424 else 425 regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC); 426 if (regmatch.regprog == NULL) 427 goto sortend; 428 p = s; /* continue after the regexp */ 429 regmatch.rm_ic = p_ic; 430 } 431 else 432 { 433 EMSG2(_(e_invarg2), p); 434 goto sortend; 435 } 436 } 437 438 /* Can only have one of 'n', 'o' and 'x'. */ 439 if (sort_nr + sort_oct + sort_hex > 2) 440 { 441 EMSG(_(e_invarg)); 442 goto sortend; 443 } 444 445 /* From here on "sort_nr" is used as a flag for any number sorting. */ 446 sort_nr += sort_oct + sort_hex; 447 448 /* 449 * Make an array with all line numbers. This avoids having to copy all 450 * the lines into allocated memory. 451 * When sorting on strings "start_col_nr" is the offset in the line, for 452 * numbers sorting it's the number to sort on. This means the pattern 453 * matching and number conversion only has to be done once per line. 454 * Also get the longest line length for allocating "sortbuf". 455 */ 456 for (lnum = eap->line1; lnum <= eap->line2; ++lnum) 457 { 458 s = ml_get(lnum); 459 len = (int)STRLEN(s); 460 if (maxlen < len) 461 maxlen = len; 462 463 start_col = 0; 464 end_col = len; 465 if (regmatch.regprog != NULL && vim_regexec(®match, s, 0)) 466 { 467 if (sort_rx) 468 { 469 start_col = (colnr_T)(regmatch.startp[0] - s); 470 end_col = (colnr_T)(regmatch.endp[0] - s); 471 } 472 else 473 start_col = (colnr_T)(regmatch.endp[0] - s); 474 } 475 else 476 if (regmatch.regprog != NULL) 477 end_col = 0; 478 479 if (sort_nr) 480 { 481 /* Make sure vim_str2nr doesn't read any digits past the end 482 * of the match, by temporarily terminating the string there */ 483 s2 = s + end_col; 484 c = *s2; 485 (*s2) = 0; 486 /* Sorting on number: Store the number itself. */ 487 p = s + start_col; 488 if (sort_hex) 489 s = skiptohex(p); 490 else 491 s = skiptodigit(p); 492 if (s > p && s[-1] == '-') 493 --s; /* include preceding negative sign */ 494 vim_str2nr(s, NULL, NULL, sort_oct, sort_hex, 495 &nrs[lnum - eap->line1].start_col_nr, NULL); 496 (*s2) = c; 497 } 498 else 499 { 500 /* Store the column to sort at. */ 501 nrs[lnum - eap->line1].start_col_nr = start_col; 502 nrs[lnum - eap->line1].end_col_nr = end_col; 503 } 504 505 nrs[lnum - eap->line1].lnum = lnum; 506 507 if (regmatch.regprog != NULL) 508 fast_breakcheck(); 509 if (got_int) 510 goto sortend; 511 } 512 513 /* Allocate a buffer that can hold the longest line. */ 514 sortbuf1 = alloc((unsigned)maxlen + 1); 515 if (sortbuf1 == NULL) 516 goto sortend; 517 sortbuf2 = alloc((unsigned)maxlen + 1); 518 if (sortbuf2 == NULL) 519 goto sortend; 520 521 /* Sort the array of line numbers. Note: can't be interrupted! */ 522 qsort((void *)nrs, count, sizeof(sorti_T), sort_compare); 523 524 if (sort_abort) 525 goto sortend; 526 527 /* Insert the lines in the sorted order below the last one. */ 528 lnum = eap->line2; 529 for (i = 0; i < count; ++i) 530 { 531 s = ml_get(nrs[eap->forceit ? count - i - 1 : i].lnum); 532 if (!unique || i == 0 533 || (sort_ic ? STRICMP(s, sortbuf1) : STRCMP(s, sortbuf1)) != 0) 534 { 535 if (ml_append(lnum++, s, (colnr_T)0, FALSE) == FAIL) 536 break; 537 if (unique) 538 STRCPY(sortbuf1, s); 539 } 540 fast_breakcheck(); 541 if (got_int) 542 goto sortend; 543 } 544 545 /* delete the original lines if appending worked */ 546 if (i == count) 547 for (i = 0; i < count; ++i) 548 ml_delete(eap->line1, FALSE); 549 else 550 count = 0; 551 552 /* Adjust marks for deleted (or added) lines and prepare for displaying. */ 553 deleted = (long)(count - (lnum - eap->line2)); 554 if (deleted > 0) 555 mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted); 556 else if (deleted < 0) 557 mark_adjust(eap->line2, MAXLNUM, -deleted, 0L); 558 changed_lines(eap->line1, 0, eap->line2 + 1, -deleted); 559 560 curwin->w_cursor.lnum = eap->line1; 561 beginline(BL_WHITE | BL_FIX); 562 563sortend: 564 vim_free(nrs); 565 vim_free(sortbuf1); 566 vim_free(sortbuf2); 567 vim_free(regmatch.regprog); 568 if (got_int) 569 EMSG(_(e_interr)); 570} 571 572/* 573 * ":retab". 574 */ 575 void 576ex_retab(eap) 577 exarg_T *eap; 578{ 579 linenr_T lnum; 580 int got_tab = FALSE; 581 long num_spaces = 0; 582 long num_tabs; 583 long len; 584 long col; 585 long vcol; 586 long start_col = 0; /* For start of white-space string */ 587 long start_vcol = 0; /* For start of white-space string */ 588 int temp; 589 long old_len; 590 char_u *ptr; 591 char_u *new_line = (char_u *)1; /* init to non-NULL */ 592 int did_undo; /* called u_save for current line */ 593 int new_ts; 594 int save_list; 595 linenr_T first_line = 0; /* first changed line */ 596 linenr_T last_line = 0; /* last changed line */ 597 598 save_list = curwin->w_p_list; 599 curwin->w_p_list = 0; /* don't want list mode here */ 600 601 new_ts = getdigits(&(eap->arg)); 602 if (new_ts < 0) 603 { 604 EMSG(_(e_positive)); 605 return; 606 } 607 if (new_ts == 0) 608 new_ts = curbuf->b_p_ts; 609 for (lnum = eap->line1; !got_int && lnum <= eap->line2; ++lnum) 610 { 611 ptr = ml_get(lnum); 612 col = 0; 613 vcol = 0; 614 did_undo = FALSE; 615 for (;;) 616 { 617 if (vim_iswhite(ptr[col])) 618 { 619 if (!got_tab && num_spaces == 0) 620 { 621 /* First consecutive white-space */ 622 start_vcol = vcol; 623 start_col = col; 624 } 625 if (ptr[col] == ' ') 626 num_spaces++; 627 else 628 got_tab = TRUE; 629 } 630 else 631 { 632 if (got_tab || (eap->forceit && num_spaces > 1)) 633 { 634 /* Retabulate this string of white-space */ 635 636 /* len is virtual length of white string */ 637 len = num_spaces = vcol - start_vcol; 638 num_tabs = 0; 639 if (!curbuf->b_p_et) 640 { 641 temp = new_ts - (start_vcol % new_ts); 642 if (num_spaces >= temp) 643 { 644 num_spaces -= temp; 645 num_tabs++; 646 } 647 num_tabs += num_spaces / new_ts; 648 num_spaces -= (num_spaces / new_ts) * new_ts; 649 } 650 if (curbuf->b_p_et || got_tab || 651 (num_spaces + num_tabs < len)) 652 { 653 if (did_undo == FALSE) 654 { 655 did_undo = TRUE; 656 if (u_save((linenr_T)(lnum - 1), 657 (linenr_T)(lnum + 1)) == FAIL) 658 { 659 new_line = NULL; /* flag out-of-memory */ 660 break; 661 } 662 } 663 664 /* len is actual number of white characters used */ 665 len = num_spaces + num_tabs; 666 old_len = (long)STRLEN(ptr); 667 new_line = lalloc(old_len - col + start_col + len + 1, 668 TRUE); 669 if (new_line == NULL) 670 break; 671 if (start_col > 0) 672 mch_memmove(new_line, ptr, (size_t)start_col); 673 mch_memmove(new_line + start_col + len, 674 ptr + col, (size_t)(old_len - col + 1)); 675 ptr = new_line + start_col; 676 for (col = 0; col < len; col++) 677 ptr[col] = (col < num_tabs) ? '\t' : ' '; 678 ml_replace(lnum, new_line, FALSE); 679 if (first_line == 0) 680 first_line = lnum; 681 last_line = lnum; 682 ptr = new_line; 683 col = start_col + len; 684 } 685 } 686 got_tab = FALSE; 687 num_spaces = 0; 688 } 689 if (ptr[col] == NUL) 690 break; 691 vcol += chartabsize(ptr + col, (colnr_T)vcol); 692#ifdef FEAT_MBYTE 693 if (has_mbyte) 694 col += (*mb_ptr2len)(ptr + col); 695 else 696#endif 697 ++col; 698 } 699 if (new_line == NULL) /* out of memory */ 700 break; 701 line_breakcheck(); 702 } 703 if (got_int) 704 EMSG(_(e_interr)); 705 706 if (curbuf->b_p_ts != new_ts) 707 redraw_curbuf_later(NOT_VALID); 708 if (first_line != 0) 709 changed_lines(first_line, 0, last_line + 1, 0L); 710 711 curwin->w_p_list = save_list; /* restore 'list' */ 712 713 curbuf->b_p_ts = new_ts; 714 coladvance(curwin->w_curswant); 715 716 u_clearline(); 717} 718#endif 719 720/* 721 * :move command - move lines line1-line2 to line dest 722 * 723 * return FAIL for failure, OK otherwise 724 */ 725 int 726do_move(line1, line2, dest) 727 linenr_T line1; 728 linenr_T line2; 729 linenr_T dest; 730{ 731 char_u *str; 732 linenr_T l; 733 linenr_T extra; /* Num lines added before line1 */ 734 linenr_T num_lines; /* Num lines moved */ 735 linenr_T last_line; /* Last line in file after adding new text */ 736 737 if (dest >= line1 && dest < line2) 738 { 739 EMSG(_("E134: Move lines into themselves")); 740 return FAIL; 741 } 742 743 num_lines = line2 - line1 + 1; 744 745 /* 746 * First we copy the old text to its new location -- webb 747 * Also copy the flag that ":global" command uses. 748 */ 749 if (u_save(dest, dest + 1) == FAIL) 750 return FAIL; 751 for (extra = 0, l = line1; l <= line2; l++) 752 { 753 str = vim_strsave(ml_get(l + extra)); 754 if (str != NULL) 755 { 756 ml_append(dest + l - line1, str, (colnr_T)0, FALSE); 757 vim_free(str); 758 if (dest < line1) 759 extra++; 760 } 761 } 762 763 /* 764 * Now we must be careful adjusting our marks so that we don't overlap our 765 * mark_adjust() calls. 766 * 767 * We adjust the marks within the old text so that they refer to the 768 * last lines of the file (temporarily), because we know no other marks 769 * will be set there since these line numbers did not exist until we added 770 * our new lines. 771 * 772 * Then we adjust the marks on lines between the old and new text positions 773 * (either forwards or backwards). 774 * 775 * And Finally we adjust the marks we put at the end of the file back to 776 * their final destination at the new text position -- webb 777 */ 778 last_line = curbuf->b_ml.ml_line_count; 779 mark_adjust(line1, line2, last_line - line2, 0L); 780 if (dest >= line2) 781 { 782 mark_adjust(line2 + 1, dest, -num_lines, 0L); 783 curbuf->b_op_start.lnum = dest - num_lines + 1; 784 curbuf->b_op_end.lnum = dest; 785 } 786 else 787 { 788 mark_adjust(dest + 1, line1 - 1, num_lines, 0L); 789 curbuf->b_op_start.lnum = dest + 1; 790 curbuf->b_op_end.lnum = dest + num_lines; 791 } 792 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 793 mark_adjust(last_line - num_lines + 1, last_line, 794 -(last_line - dest - extra), 0L); 795 796 /* 797 * Now we delete the original text -- webb 798 */ 799 if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL) 800 return FAIL; 801 802 for (l = line1; l <= line2; l++) 803 ml_delete(line1 + extra, TRUE); 804 805 if (!global_busy && num_lines > p_report) 806 { 807 if (num_lines == 1) 808 MSG(_("1 line moved")); 809 else 810 smsg((char_u *)_("%ld lines moved"), num_lines); 811 } 812 813 /* 814 * Leave the cursor on the last of the moved lines. 815 */ 816 if (dest >= line1) 817 curwin->w_cursor.lnum = dest; 818 else 819 curwin->w_cursor.lnum = dest + (line2 - line1) + 1; 820 821 if (line1 < dest) 822 changed_lines(line1, 0, dest + num_lines + 1, 0L); 823 else 824 changed_lines(dest + 1, 0, line1 + num_lines, 0L); 825 826 return OK; 827} 828 829/* 830 * ":copy" 831 */ 832 void 833ex_copy(line1, line2, n) 834 linenr_T line1; 835 linenr_T line2; 836 linenr_T n; 837{ 838 linenr_T count; 839 char_u *p; 840 841 count = line2 - line1 + 1; 842 curbuf->b_op_start.lnum = n + 1; 843 curbuf->b_op_end.lnum = n + count; 844 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 845 846 /* 847 * there are three situations: 848 * 1. destination is above line1 849 * 2. destination is between line1 and line2 850 * 3. destination is below line2 851 * 852 * n = destination (when starting) 853 * curwin->w_cursor.lnum = destination (while copying) 854 * line1 = start of source (while copying) 855 * line2 = end of source (while copying) 856 */ 857 if (u_save(n, n + 1) == FAIL) 858 return; 859 860 curwin->w_cursor.lnum = n; 861 while (line1 <= line2) 862 { 863 /* need to use vim_strsave() because the line will be unlocked within 864 * ml_append() */ 865 p = vim_strsave(ml_get(line1)); 866 if (p != NULL) 867 { 868 ml_append(curwin->w_cursor.lnum, p, (colnr_T)0, FALSE); 869 vim_free(p); 870 } 871 /* situation 2: skip already copied lines */ 872 if (line1 == n) 873 line1 = curwin->w_cursor.lnum; 874 ++line1; 875 if (curwin->w_cursor.lnum < line1) 876 ++line1; 877 if (curwin->w_cursor.lnum < line2) 878 ++line2; 879 ++curwin->w_cursor.lnum; 880 } 881 882 appended_lines_mark(n, count); 883 884 msgmore((long)count); 885} 886 887static char_u *prevcmd = NULL; /* the previous command */ 888 889#if defined(EXITFREE) || defined(PROTO) 890 void 891free_prev_shellcmd() 892{ 893 vim_free(prevcmd); 894} 895#endif 896 897/* 898 * Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd" 899 * Bangs in the argument are replaced with the previously entered command. 900 * Remember the argument. 901 * 902 * RISCOS: Bangs only replaced when followed by a space, since many 903 * pathnames contain one. 904 */ 905 void 906do_bang(addr_count, eap, forceit, do_in, do_out) 907 int addr_count; 908 exarg_T *eap; 909 int forceit; 910 int do_in, do_out; 911{ 912 char_u *arg = eap->arg; /* command */ 913 linenr_T line1 = eap->line1; /* start of range */ 914 linenr_T line2 = eap->line2; /* end of range */ 915 char_u *newcmd = NULL; /* the new command */ 916 int free_newcmd = FALSE; /* need to free() newcmd */ 917 int ins_prevcmd; 918 char_u *t; 919 char_u *p; 920 char_u *trailarg; 921 int len; 922 int scroll_save = msg_scroll; 923 924 /* 925 * Disallow shell commands for "rvim". 926 * Disallow shell commands from .exrc and .vimrc in current directory for 927 * security reasons. 928 */ 929 if (check_restricted() || check_secure()) 930 return; 931 932 if (addr_count == 0) /* :! */ 933 { 934 msg_scroll = FALSE; /* don't scroll here */ 935 autowrite_all(); 936 msg_scroll = scroll_save; 937 } 938 939 /* 940 * Try to find an embedded bang, like in :!<cmd> ! [args] 941 * (:!! is indicated by the 'forceit' variable) 942 */ 943 ins_prevcmd = forceit; 944 trailarg = arg; 945 do 946 { 947 len = (int)STRLEN(trailarg) + 1; 948 if (newcmd != NULL) 949 len += (int)STRLEN(newcmd); 950 if (ins_prevcmd) 951 { 952 if (prevcmd == NULL) 953 { 954 EMSG(_(e_noprev)); 955 vim_free(newcmd); 956 return; 957 } 958 len += (int)STRLEN(prevcmd); 959 } 960 if ((t = alloc((unsigned)len)) == NULL) 961 { 962 vim_free(newcmd); 963 return; 964 } 965 *t = NUL; 966 if (newcmd != NULL) 967 STRCAT(t, newcmd); 968 if (ins_prevcmd) 969 STRCAT(t, prevcmd); 970 p = t + STRLEN(t); 971 STRCAT(t, trailarg); 972 vim_free(newcmd); 973 newcmd = t; 974 975 /* 976 * Scan the rest of the argument for '!', which is replaced by the 977 * previous command. "\!" is replaced by "!" (this is vi compatible). 978 */ 979 trailarg = NULL; 980 while (*p) 981 { 982 if (*p == '!' 983#ifdef RISCOS 984 && (p[1] == ' ' || p[1] == NUL) 985#endif 986 ) 987 { 988 if (p > newcmd && p[-1] == '\\') 989 STRMOVE(p - 1, p); 990 else 991 { 992 trailarg = p; 993 *trailarg++ = NUL; 994 ins_prevcmd = TRUE; 995 break; 996 } 997 } 998 ++p; 999 } 1000 } while (trailarg != NULL); 1001 1002 vim_free(prevcmd); 1003 prevcmd = newcmd; 1004 1005 if (bangredo) /* put cmd in redo buffer for ! command */ 1006 { 1007 AppendToRedobuffLit(prevcmd, -1); 1008 AppendToRedobuff((char_u *)"\n"); 1009 bangredo = FALSE; 1010 } 1011 /* 1012 * Add quotes around the command, for shells that need them. 1013 */ 1014 if (*p_shq != NUL) 1015 { 1016 newcmd = alloc((unsigned)(STRLEN(prevcmd) + 2 * STRLEN(p_shq) + 1)); 1017 if (newcmd == NULL) 1018 return; 1019 STRCPY(newcmd, p_shq); 1020 STRCAT(newcmd, prevcmd); 1021 STRCAT(newcmd, p_shq); 1022 free_newcmd = TRUE; 1023 } 1024 if (addr_count == 0) /* :! */ 1025 { 1026 /* echo the command */ 1027 msg_start(); 1028 msg_putchar(':'); 1029 msg_putchar('!'); 1030 msg_outtrans(newcmd); 1031 msg_clr_eos(); 1032 windgoto(msg_row, msg_col); 1033 1034 do_shell(newcmd, 0); 1035 } 1036 else /* :range! */ 1037 { 1038 /* Careful: This may recursively call do_bang() again! (because of 1039 * autocommands) */ 1040 do_filter(line1, line2, eap, newcmd, do_in, do_out); 1041#ifdef FEAT_AUTOCMD 1042 apply_autocmds(EVENT_SHELLFILTERPOST, NULL, NULL, FALSE, curbuf); 1043#endif 1044 } 1045 if (free_newcmd) 1046 vim_free(newcmd); 1047} 1048 1049/* 1050 * do_filter: filter lines through a command given by the user 1051 * 1052 * We mostly use temp files and the call_shell() routine here. This would 1053 * normally be done using pipes on a UNIX machine, but this is more portable 1054 * to non-unix machines. The call_shell() routine needs to be able 1055 * to deal with redirection somehow, and should handle things like looking 1056 * at the PATH env. variable, and adding reasonable extensions to the 1057 * command name given by the user. All reasonable versions of call_shell() 1058 * do this. 1059 * Alternatively, if on Unix and redirecting input or output, but not both, 1060 * and the 'shelltemp' option isn't set, use pipes. 1061 * We use input redirection if do_in is TRUE. 1062 * We use output redirection if do_out is TRUE. 1063 */ 1064 static void 1065do_filter(line1, line2, eap, cmd, do_in, do_out) 1066 linenr_T line1, line2; 1067 exarg_T *eap; /* for forced 'ff' and 'fenc' */ 1068 char_u *cmd; 1069 int do_in, do_out; 1070{ 1071 char_u *itmp = NULL; 1072 char_u *otmp = NULL; 1073 linenr_T linecount; 1074 linenr_T read_linecount; 1075 pos_T cursor_save; 1076 char_u *cmd_buf; 1077#ifdef FEAT_AUTOCMD 1078 buf_T *old_curbuf = curbuf; 1079#endif 1080 int shell_flags = 0; 1081 1082 if (*cmd == NUL) /* no filter command */ 1083 return; 1084 1085#ifdef WIN3264 1086 /* 1087 * Check if external commands are allowed now. 1088 */ 1089 if (can_end_termcap_mode(TRUE) == FALSE) 1090 return; 1091#endif 1092 1093 cursor_save = curwin->w_cursor; 1094 linecount = line2 - line1 + 1; 1095 curwin->w_cursor.lnum = line1; 1096 curwin->w_cursor.col = 0; 1097 changed_line_abv_curs(); 1098 invalidate_botline(); 1099 1100 /* 1101 * When using temp files: 1102 * 1. * Form temp file names 1103 * 2. * Write the lines to a temp file 1104 * 3. Run the filter command on the temp file 1105 * 4. * Read the output of the command into the buffer 1106 * 5. * Delete the original lines to be filtered 1107 * 6. * Remove the temp files 1108 * 1109 * When writing the input with a pipe or when catching the output with a 1110 * pipe only need to do 3. 1111 */ 1112 1113 if (do_out) 1114 shell_flags |= SHELL_DOOUT; 1115 1116#if !defined(USE_SYSTEM) && defined(UNIX) 1117 if (!do_in && do_out && !p_stmp) 1118 { 1119 /* Use a pipe to fetch stdout of the command, do not use a temp file. */ 1120 shell_flags |= SHELL_READ; 1121 curwin->w_cursor.lnum = line2; 1122 } 1123 else if (do_in && !do_out && !p_stmp) 1124 { 1125 /* Use a pipe to write stdin of the command, do not use a temp file. */ 1126 shell_flags |= SHELL_WRITE; 1127 curbuf->b_op_start.lnum = line1; 1128 curbuf->b_op_end.lnum = line2; 1129 } 1130 else if (do_in && do_out && !p_stmp) 1131 { 1132 /* Use a pipe to write stdin and fetch stdout of the command, do not 1133 * use a temp file. */ 1134 shell_flags |= SHELL_READ|SHELL_WRITE; 1135 curbuf->b_op_start.lnum = line1; 1136 curbuf->b_op_end.lnum = line2; 1137 curwin->w_cursor.lnum = line2; 1138 } 1139 else 1140#endif 1141 if ((do_in && (itmp = vim_tempname('i')) == NULL) 1142 || (do_out && (otmp = vim_tempname('o')) == NULL)) 1143 { 1144 EMSG(_(e_notmp)); 1145 goto filterend; 1146 } 1147 1148/* 1149 * The writing and reading of temp files will not be shown. 1150 * Vi also doesn't do this and the messages are not very informative. 1151 */ 1152 ++no_wait_return; /* don't call wait_return() while busy */ 1153 if (itmp != NULL && buf_write(curbuf, itmp, NULL, line1, line2, eap, 1154 FALSE, FALSE, FALSE, TRUE) == FAIL) 1155 { 1156 msg_putchar('\n'); /* keep message from buf_write() */ 1157 --no_wait_return; 1158#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 1159 if (!aborting()) 1160#endif 1161 (void)EMSG2(_(e_notcreate), itmp); /* will call wait_return */ 1162 goto filterend; 1163 } 1164#ifdef FEAT_AUTOCMD 1165 if (curbuf != old_curbuf) 1166 goto filterend; 1167#endif 1168 1169 if (!do_out) 1170 msg_putchar('\n'); 1171 1172 /* Create the shell command in allocated memory. */ 1173 cmd_buf = make_filter_cmd(cmd, itmp, otmp); 1174 if (cmd_buf == NULL) 1175 goto filterend; 1176 1177 windgoto((int)Rows - 1, 0); 1178 cursor_on(); 1179 1180 /* 1181 * When not redirecting the output the command can write anything to the 1182 * screen. If 'shellredir' is equal to ">", screen may be messed up by 1183 * stderr output of external command. Clear the screen later. 1184 * If do_in is FALSE, this could be something like ":r !cat", which may 1185 * also mess up the screen, clear it later. 1186 */ 1187 if (!do_out || STRCMP(p_srr, ">") == 0 || !do_in) 1188 redraw_later_clear(); 1189 1190 if (do_out) 1191 { 1192 if (u_save((linenr_T)(line2), (linenr_T)(line2 + 1)) == FAIL) 1193 { 1194 vim_free(cmd_buf); 1195 goto error; 1196 } 1197 redraw_curbuf_later(VALID); 1198 } 1199 read_linecount = curbuf->b_ml.ml_line_count; 1200 1201 /* 1202 * When call_shell() fails wait_return() is called to give the user a 1203 * chance to read the error messages. Otherwise errors are ignored, so you 1204 * can see the error messages from the command that appear on stdout; use 1205 * 'u' to fix the text 1206 * Switch to cooked mode when not redirecting stdin, avoids that something 1207 * like ":r !cat" hangs. 1208 * Pass on the SHELL_DOOUT flag when the output is being redirected. 1209 */ 1210 if (call_shell(cmd_buf, SHELL_FILTER | SHELL_COOKED | shell_flags)) 1211 { 1212 redraw_later_clear(); 1213 wait_return(FALSE); 1214 } 1215 vim_free(cmd_buf); 1216 1217 did_check_timestamps = FALSE; 1218 need_check_timestamps = TRUE; 1219 1220 /* When interrupting the shell command, it may still have produced some 1221 * useful output. Reset got_int here, so that readfile() won't cancel 1222 * reading. */ 1223 ui_breakcheck(); 1224 got_int = FALSE; 1225 1226 if (do_out) 1227 { 1228 if (otmp != NULL) 1229 { 1230 if (readfile(otmp, NULL, line2, (linenr_T)0, (linenr_T)MAXLNUM, 1231 eap, READ_FILTER) == FAIL) 1232 { 1233#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 1234 if (!aborting()) 1235#endif 1236 { 1237 msg_putchar('\n'); 1238 EMSG2(_(e_notread), otmp); 1239 } 1240 goto error; 1241 } 1242#ifdef FEAT_AUTOCMD 1243 if (curbuf != old_curbuf) 1244 goto filterend; 1245#endif 1246 } 1247 1248 read_linecount = curbuf->b_ml.ml_line_count - read_linecount; 1249 1250 if (shell_flags & SHELL_READ) 1251 { 1252 curbuf->b_op_start.lnum = line2 + 1; 1253 curbuf->b_op_end.lnum = curwin->w_cursor.lnum; 1254 appended_lines_mark(line2, read_linecount); 1255 } 1256 1257 if (do_in) 1258 { 1259 if (cmdmod.keepmarks || vim_strchr(p_cpo, CPO_REMMARK) == NULL) 1260 { 1261 if (read_linecount >= linecount) 1262 /* move all marks from old lines to new lines */ 1263 mark_adjust(line1, line2, linecount, 0L); 1264 else 1265 { 1266 /* move marks from old lines to new lines, delete marks 1267 * that are in deleted lines */ 1268 mark_adjust(line1, line1 + read_linecount - 1, 1269 linecount, 0L); 1270 mark_adjust(line1 + read_linecount, line2, MAXLNUM, 0L); 1271 } 1272 } 1273 1274 /* 1275 * Put cursor on first filtered line for ":range!cmd". 1276 * Adjust '[ and '] (set by buf_write()). 1277 */ 1278 curwin->w_cursor.lnum = line1; 1279 del_lines(linecount, TRUE); 1280 curbuf->b_op_start.lnum -= linecount; /* adjust '[ */ 1281 curbuf->b_op_end.lnum -= linecount; /* adjust '] */ 1282 write_lnum_adjust(-linecount); /* adjust last line 1283 for next write */ 1284#ifdef FEAT_FOLDING 1285 foldUpdate(curwin, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum); 1286#endif 1287 } 1288 else 1289 { 1290 /* 1291 * Put cursor on last new line for ":r !cmd". 1292 */ 1293 linecount = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1; 1294 curwin->w_cursor.lnum = curbuf->b_op_end.lnum; 1295 } 1296 1297 beginline(BL_WHITE | BL_FIX); /* cursor on first non-blank */ 1298 --no_wait_return; 1299 1300 if (linecount > p_report) 1301 { 1302 if (do_in) 1303 { 1304 vim_snprintf((char *)msg_buf, sizeof(msg_buf), 1305 _("%ld lines filtered"), (long)linecount); 1306 if (msg(msg_buf) && !msg_scroll) 1307 /* save message to display it after redraw */ 1308 set_keep_msg(msg_buf, 0); 1309 } 1310 else 1311 msgmore((long)linecount); 1312 } 1313 } 1314 else 1315 { 1316error: 1317 /* put cursor back in same position for ":w !cmd" */ 1318 curwin->w_cursor = cursor_save; 1319 --no_wait_return; 1320 wait_return(FALSE); 1321 } 1322 1323filterend: 1324 1325#ifdef FEAT_AUTOCMD 1326 if (curbuf != old_curbuf) 1327 { 1328 --no_wait_return; 1329 EMSG(_("E135: *Filter* Autocommands must not change current buffer")); 1330 } 1331#endif 1332 if (itmp != NULL) 1333 mch_remove(itmp); 1334 if (otmp != NULL) 1335 mch_remove(otmp); 1336 vim_free(itmp); 1337 vim_free(otmp); 1338} 1339 1340/* 1341 * Call a shell to execute a command. 1342 * When "cmd" is NULL start an interactive shell. 1343 */ 1344 void 1345do_shell(cmd, flags) 1346 char_u *cmd; 1347 int flags; /* may be SHELL_DOOUT when output is redirected */ 1348{ 1349 buf_T *buf; 1350#ifndef FEAT_GUI_MSWIN 1351 int save_nwr; 1352#endif 1353#ifdef MSWIN 1354 int winstart = FALSE; 1355#endif 1356 1357 /* 1358 * Disallow shell commands for "rvim". 1359 * Disallow shell commands from .exrc and .vimrc in current directory for 1360 * security reasons. 1361 */ 1362 if (check_restricted() || check_secure()) 1363 { 1364 msg_end(); 1365 return; 1366 } 1367 1368#ifdef MSWIN 1369 /* 1370 * Check if external commands are allowed now. 1371 */ 1372 if (can_end_termcap_mode(TRUE) == FALSE) 1373 return; 1374 1375 /* 1376 * Check if ":!start" is used. 1377 */ 1378 if (cmd != NULL) 1379 winstart = (STRNICMP(cmd, "start ", 6) == 0); 1380#endif 1381 1382 /* 1383 * For autocommands we want to get the output on the current screen, to 1384 * avoid having to type return below. 1385 */ 1386 msg_putchar('\r'); /* put cursor at start of line */ 1387#ifdef FEAT_AUTOCMD 1388 if (!autocmd_busy) 1389#endif 1390 { 1391#ifdef MSWIN 1392 if (!winstart) 1393#endif 1394 stoptermcap(); 1395 } 1396#ifdef MSWIN 1397 if (!winstart) 1398#endif 1399 msg_putchar('\n'); /* may shift screen one line up */ 1400 1401 /* warning message before calling the shell */ 1402 if (p_warn 1403#ifdef FEAT_AUTOCMD 1404 && !autocmd_busy 1405#endif 1406 && msg_silent == 0) 1407 for (buf = firstbuf; buf; buf = buf->b_next) 1408 if (bufIsChanged(buf)) 1409 { 1410#ifdef FEAT_GUI_MSWIN 1411 if (!winstart) 1412 starttermcap(); /* don't want a message box here */ 1413#endif 1414 MSG_PUTS(_("[No write since last change]\n")); 1415#ifdef FEAT_GUI_MSWIN 1416 if (!winstart) 1417 stoptermcap(); 1418#endif 1419 break; 1420 } 1421 1422 /* This windgoto is required for when the '\n' resulted in a "delete line 1423 * 1" command to the terminal. */ 1424 if (!swapping_screen()) 1425 windgoto(msg_row, msg_col); 1426 cursor_on(); 1427 (void)call_shell(cmd, SHELL_COOKED | flags); 1428 did_check_timestamps = FALSE; 1429 need_check_timestamps = TRUE; 1430 1431 /* 1432 * put the message cursor at the end of the screen, avoids wait_return() 1433 * to overwrite the text that the external command showed 1434 */ 1435 if (!swapping_screen()) 1436 { 1437 msg_row = Rows - 1; 1438 msg_col = 0; 1439 } 1440 1441#ifdef FEAT_AUTOCMD 1442 if (autocmd_busy) 1443 { 1444 if (msg_silent == 0) 1445 redraw_later_clear(); 1446 } 1447 else 1448#endif 1449 { 1450 /* 1451 * For ":sh" there is no need to call wait_return(), just redraw. 1452 * Also for the Win32 GUI (the output is in a console window). 1453 * Otherwise there is probably text on the screen that the user wants 1454 * to read before redrawing, so call wait_return(). 1455 */ 1456#ifndef FEAT_GUI_MSWIN 1457 if (cmd == NULL 1458# ifdef WIN3264 1459 || (winstart && !need_wait_return) 1460# endif 1461 ) 1462 { 1463 if (msg_silent == 0) 1464 redraw_later_clear(); 1465 need_wait_return = FALSE; 1466 } 1467 else 1468 { 1469 /* 1470 * If we switch screens when starttermcap() is called, we really 1471 * want to wait for "hit return to continue". 1472 */ 1473 save_nwr = no_wait_return; 1474 if (swapping_screen()) 1475 no_wait_return = FALSE; 1476# ifdef AMIGA 1477 wait_return(term_console ? -1 : msg_silent == 0); /* see below */ 1478# else 1479 wait_return(msg_silent == 0); 1480# endif 1481 no_wait_return = save_nwr; 1482 } 1483#endif /* FEAT_GUI_W32 */ 1484 1485#ifdef MSWIN 1486 if (!winstart) /* if winstart==TRUE, never stopped termcap! */ 1487#endif 1488 starttermcap(); /* start termcap if not done by wait_return() */ 1489 1490 /* 1491 * In an Amiga window redrawing is caused by asking the window size. 1492 * If we got an interrupt this will not work. The chance that the 1493 * window size is wrong is very small, but we need to redraw the 1494 * screen. Don't do this if ':' hit in wait_return(). THIS IS UGLY 1495 * but it saves an extra redraw. 1496 */ 1497#ifdef AMIGA 1498 if (skip_redraw) /* ':' hit in wait_return() */ 1499 { 1500 if (msg_silent == 0) 1501 redraw_later_clear(); 1502 } 1503 else if (term_console) 1504 { 1505 OUT_STR(IF_EB("\033[0 q", ESC_STR "[0 q")); /* get window size */ 1506 if (got_int && msg_silent == 0) 1507 redraw_later_clear(); /* if got_int is TRUE, redraw needed */ 1508 else 1509 must_redraw = 0; /* no extra redraw needed */ 1510 } 1511#endif 1512 } 1513 1514 /* display any error messages now */ 1515 display_errors(); 1516 1517#ifdef FEAT_AUTOCMD 1518 apply_autocmds(EVENT_SHELLCMDPOST, NULL, NULL, FALSE, curbuf); 1519#endif 1520} 1521 1522/* 1523 * Create a shell command from a command string, input redirection file and 1524 * output redirection file. 1525 * Returns an allocated string with the shell command, or NULL for failure. 1526 */ 1527 char_u * 1528make_filter_cmd(cmd, itmp, otmp) 1529 char_u *cmd; /* command */ 1530 char_u *itmp; /* NULL or name of input file */ 1531 char_u *otmp; /* NULL or name of output file */ 1532{ 1533 char_u *buf; 1534 long_u len; 1535 1536 len = (long_u)STRLEN(cmd) + 3; /* "()" + NUL */ 1537 if (itmp != NULL) 1538 len += (long_u)STRLEN(itmp) + 9; /* " { < " + " } " */ 1539 if (otmp != NULL) 1540 len += (long_u)STRLEN(otmp) + (long_u)STRLEN(p_srr) + 2; /* " " */ 1541 buf = lalloc(len, TRUE); 1542 if (buf == NULL) 1543 return NULL; 1544 1545#if (defined(UNIX) && !defined(ARCHIE)) || defined(OS2) 1546 /* 1547 * Put braces around the command (for concatenated commands) when 1548 * redirecting input and/or output. 1549 */ 1550 if (itmp != NULL || otmp != NULL) 1551 vim_snprintf((char *)buf, len, "(%s)", (char *)cmd); 1552 else 1553 STRCPY(buf, cmd); 1554 if (itmp != NULL) 1555 { 1556 STRCAT(buf, " < "); 1557 STRCAT(buf, itmp); 1558 } 1559#else 1560 /* 1561 * for shells that don't understand braces around commands, at least allow 1562 * the use of commands in a pipe. 1563 */ 1564 STRCPY(buf, cmd); 1565 if (itmp != NULL) 1566 { 1567 char_u *p; 1568 1569 /* 1570 * If there is a pipe, we have to put the '<' in front of it. 1571 * Don't do this when 'shellquote' is not empty, otherwise the 1572 * redirection would be inside the quotes. 1573 */ 1574 if (*p_shq == NUL) 1575 { 1576 p = vim_strchr(buf, '|'); 1577 if (p != NULL) 1578 *p = NUL; 1579 } 1580# ifdef RISCOS 1581 STRCAT(buf, " { < "); /* Use RISC OS notation for input. */ 1582 STRCAT(buf, itmp); 1583 STRCAT(buf, " } "); 1584# else 1585 STRCAT(buf, " <"); /* " < " causes problems on Amiga */ 1586 STRCAT(buf, itmp); 1587# endif 1588 if (*p_shq == NUL) 1589 { 1590 p = vim_strchr(cmd, '|'); 1591 if (p != NULL) 1592 { 1593 STRCAT(buf, " "); /* insert a space before the '|' for DOS */ 1594 STRCAT(buf, p); 1595 } 1596 } 1597 } 1598#endif 1599 if (otmp != NULL) 1600 append_redir(buf, (int)len, p_srr, otmp); 1601 1602 return buf; 1603} 1604 1605/* 1606 * Append output redirection for file "fname" to the end of string buffer 1607 * "buf[buflen]" 1608 * Works with the 'shellredir' and 'shellpipe' options. 1609 * The caller should make sure that there is enough room: 1610 * STRLEN(opt) + STRLEN(fname) + 3 1611 */ 1612 void 1613append_redir(buf, buflen, opt, fname) 1614 char_u *buf; 1615 int buflen; 1616 char_u *opt; 1617 char_u *fname; 1618{ 1619 char_u *p; 1620 char_u *end; 1621 1622 end = buf + STRLEN(buf); 1623 /* find "%s", skipping "%%" */ 1624 for (p = opt; (p = vim_strchr(p, '%')) != NULL; ++p) 1625 if (p[1] == 's') 1626 break; 1627 if (p != NULL) 1628 { 1629 *end = ' '; /* not really needed? Not with sh, ksh or bash */ 1630 vim_snprintf((char *)end + 1, (size_t)(buflen - (end + 1 - buf)), 1631 (char *)opt, (char *)fname); 1632 } 1633 else 1634 vim_snprintf((char *)end, (size_t)(buflen - (end - buf)), 1635#ifdef FEAT_QUICKFIX 1636# ifndef RISCOS 1637 opt != p_sp ? " %s%s" : 1638# endif 1639 " %s %s", 1640#else 1641# ifndef RISCOS 1642 " %s%s", /* " > %s" causes problems on Amiga */ 1643# else 1644 " %s %s", /* But is needed for 'shellpipe' and RISC OS */ 1645# endif 1646#endif 1647 (char *)opt, (char *)fname); 1648} 1649 1650#ifdef FEAT_VIMINFO 1651 1652static int no_viminfo __ARGS((void)); 1653static int viminfo_errcnt; 1654 1655 static int 1656no_viminfo() 1657{ 1658 /* "vim -i NONE" does not read or write a viminfo file */ 1659 return (use_viminfo != NULL && STRCMP(use_viminfo, "NONE") == 0); 1660} 1661 1662/* 1663 * Report an error for reading a viminfo file. 1664 * Count the number of errors. When there are more than 10, return TRUE. 1665 */ 1666 int 1667viminfo_error(errnum, message, line) 1668 char *errnum; 1669 char *message; 1670 char_u *line; 1671{ 1672 vim_snprintf((char *)IObuff, IOSIZE, _("%sviminfo: %s in line: "), 1673 errnum, message); 1674 STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff) - 1); 1675 if (IObuff[STRLEN(IObuff) - 1] == '\n') 1676 IObuff[STRLEN(IObuff) - 1] = NUL; 1677 emsg(IObuff); 1678 if (++viminfo_errcnt >= 10) 1679 { 1680 EMSG(_("E136: viminfo: Too many errors, skipping rest of file")); 1681 return TRUE; 1682 } 1683 return FALSE; 1684} 1685 1686/* 1687 * read_viminfo() -- Read the viminfo file. Registers etc. which are already 1688 * set are not over-written unless "flags" includes VIF_FORCEIT. -- webb 1689 */ 1690 int 1691read_viminfo(file, flags) 1692 char_u *file; /* file name or NULL to use default name */ 1693 int flags; /* VIF_WANT_INFO et al. */ 1694{ 1695 FILE *fp; 1696 char_u *fname; 1697 1698 if (no_viminfo()) 1699 return FAIL; 1700 1701 fname = viminfo_filename(file); /* get file name in allocated buffer */ 1702 if (fname == NULL) 1703 return FAIL; 1704 fp = mch_fopen((char *)fname, READBIN); 1705 1706 if (p_verbose > 0) 1707 { 1708 verbose_enter(); 1709 smsg((char_u *)_("Reading viminfo file \"%s\"%s%s%s"), 1710 fname, 1711 (flags & VIF_WANT_INFO) ? _(" info") : "", 1712 (flags & VIF_WANT_MARKS) ? _(" marks") : "", 1713 (flags & VIF_GET_OLDFILES) ? _(" oldfiles") : "", 1714 fp == NULL ? _(" FAILED") : ""); 1715 verbose_leave(); 1716 } 1717 1718 vim_free(fname); 1719 if (fp == NULL) 1720 return FAIL; 1721 1722 viminfo_errcnt = 0; 1723 do_viminfo(fp, NULL, flags); 1724 1725 fclose(fp); 1726 return OK; 1727} 1728 1729/* 1730 * write_viminfo() -- Write the viminfo file. The old one is read in first so 1731 * that effectively a merge of current info and old info is done. This allows 1732 * multiple vims to run simultaneously, without losing any marks etc. If 1733 * forceit is TRUE, then the old file is not read in, and only internal info is 1734 * written to the file. -- webb 1735 */ 1736 void 1737write_viminfo(file, forceit) 1738 char_u *file; 1739 int forceit; 1740{ 1741 char_u *fname; 1742 FILE *fp_in = NULL; /* input viminfo file, if any */ 1743 FILE *fp_out = NULL; /* output viminfo file */ 1744 char_u *tempname = NULL; /* name of temp viminfo file */ 1745 struct stat st_new; /* mch_stat() of potential new file */ 1746 char_u *wp; 1747#if defined(UNIX) || defined(VMS) 1748 mode_t umask_save; 1749#endif 1750#ifdef UNIX 1751 int shortname = FALSE; /* use 8.3 file name */ 1752 struct stat st_old; /* mch_stat() of existing viminfo file */ 1753#endif 1754#ifdef WIN3264 1755 long perm = -1; 1756#endif 1757 1758 if (no_viminfo()) 1759 return; 1760 1761 fname = viminfo_filename(file); /* may set to default if NULL */ 1762 if (fname == NULL) 1763 return; 1764 1765 fp_in = mch_fopen((char *)fname, READBIN); 1766 if (fp_in == NULL) 1767 { 1768 /* if it does exist, but we can't read it, don't try writing */ 1769 if (mch_stat((char *)fname, &st_new) == 0) 1770 goto end; 1771#if defined(UNIX) || defined(VMS) 1772 /* 1773 * For Unix we create the .viminfo non-accessible for others, 1774 * because it may contain text from non-accessible documents. 1775 */ 1776 umask_save = umask(077); 1777#endif 1778 fp_out = mch_fopen((char *)fname, WRITEBIN); 1779#if defined(UNIX) || defined(VMS) 1780 (void)umask(umask_save); 1781#endif 1782 } 1783 else 1784 { 1785 /* 1786 * There is an existing viminfo file. Create a temporary file to 1787 * write the new viminfo into, in the same directory as the 1788 * existing viminfo file, which will be renamed later. 1789 */ 1790#ifdef UNIX 1791 /* 1792 * For Unix we check the owner of the file. It's not very nice to 1793 * overwrite a user's viminfo file after a "su root", with a 1794 * viminfo file that the user can't read. 1795 */ 1796 st_old.st_dev = (dev_t)0; 1797 st_old.st_ino = 0; 1798 st_old.st_mode = 0600; 1799 if (mch_stat((char *)fname, &st_old) == 0 1800 && getuid() != ROOT_UID 1801 && !(st_old.st_uid == getuid() 1802 ? (st_old.st_mode & 0200) 1803 : (st_old.st_gid == getgid() 1804 ? (st_old.st_mode & 0020) 1805 : (st_old.st_mode & 0002)))) 1806 { 1807 int tt = msg_didany; 1808 1809 /* avoid a wait_return for this message, it's annoying */ 1810 EMSG2(_("E137: Viminfo file is not writable: %s"), fname); 1811 msg_didany = tt; 1812 fclose(fp_in); 1813 goto end; 1814 } 1815#endif 1816#ifdef WIN3264 1817 /* Get the file attributes of the existing viminfo file. */ 1818 perm = mch_getperm(fname); 1819#endif 1820 1821 /* 1822 * Make tempname. 1823 * May try twice: Once normal and once with shortname set, just in 1824 * case somebody puts his viminfo file in an 8.3 filesystem. 1825 */ 1826 for (;;) 1827 { 1828 tempname = buf_modname( 1829#ifdef UNIX 1830 shortname, 1831#else 1832# ifdef SHORT_FNAME 1833 TRUE, 1834# else 1835# ifdef FEAT_GUI_W32 1836 gui_is_win32s(), 1837# else 1838 FALSE, 1839# endif 1840# endif 1841#endif 1842 fname, 1843#ifdef VMS 1844 (char_u *)"-tmp", 1845#else 1846# ifdef RISCOS 1847 (char_u *)"/tmp", 1848# else 1849 (char_u *)".tmp", 1850# endif 1851#endif 1852 FALSE); 1853 if (tempname == NULL) /* out of memory */ 1854 break; 1855 1856 /* 1857 * Check if tempfile already exists. Never overwrite an 1858 * existing file! 1859 */ 1860 if (mch_stat((char *)tempname, &st_new) == 0) 1861 { 1862#ifdef UNIX 1863 /* 1864 * Check if tempfile is same as original file. May happen 1865 * when modname() gave the same file back. E.g. silly 1866 * link, or file name-length reached. Try again with 1867 * shortname set. 1868 */ 1869 if (!shortname && st_new.st_dev == st_old.st_dev 1870 && st_new.st_ino == st_old.st_ino) 1871 { 1872 vim_free(tempname); 1873 tempname = NULL; 1874 shortname = TRUE; 1875 continue; 1876 } 1877#endif 1878 /* 1879 * Try another name. Change one character, just before 1880 * the extension. This should also work for an 8.3 1881 * file name, when after adding the extension it still is 1882 * the same file as the original. 1883 */ 1884 wp = tempname + STRLEN(tempname) - 5; 1885 if (wp < gettail(tempname)) /* empty file name? */ 1886 wp = gettail(tempname); 1887 for (*wp = 'z'; mch_stat((char *)tempname, &st_new) == 0; 1888 --*wp) 1889 { 1890 /* 1891 * They all exist? Must be something wrong! Don't 1892 * write the viminfo file then. 1893 */ 1894 if (*wp == 'a') 1895 { 1896 vim_free(tempname); 1897 tempname = NULL; 1898 break; 1899 } 1900 } 1901 } 1902 break; 1903 } 1904 1905 if (tempname != NULL) 1906 { 1907#ifdef VMS 1908 /* fdopen() fails for some reason */ 1909 umask_save = umask(077); 1910 fp_out = mch_fopen((char *)tempname, WRITEBIN); 1911 (void)umask(umask_save); 1912#else 1913 int fd; 1914 1915 /* Use mch_open() to be able to use O_NOFOLLOW and set file 1916 * protection: 1917 * Unix: same as original file, but strip s-bit. Reset umask to 1918 * avoid it getting in the way. 1919 * Others: r&w for user only. */ 1920# ifdef UNIX 1921 umask_save = umask(0); 1922 fd = mch_open((char *)tempname, 1923 O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 1924 (int)((st_old.st_mode & 0777) | 0600)); 1925 (void)umask(umask_save); 1926# else 1927 fd = mch_open((char *)tempname, 1928 O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600); 1929# endif 1930 if (fd < 0) 1931 fp_out = NULL; 1932 else 1933 fp_out = fdopen(fd, WRITEBIN); 1934#endif /* VMS */ 1935 1936 /* 1937 * If we can't create in the same directory, try creating a 1938 * "normal" temp file. 1939 */ 1940 if (fp_out == NULL) 1941 { 1942 vim_free(tempname); 1943 if ((tempname = vim_tempname('o')) != NULL) 1944 fp_out = mch_fopen((char *)tempname, WRITEBIN); 1945 } 1946 1947#if defined(UNIX) && defined(HAVE_FCHOWN) 1948 /* 1949 * Make sure the owner can read/write it. This only works for 1950 * root. 1951 */ 1952 if (fp_out != NULL) 1953 ignored = fchown(fileno(fp_out), st_old.st_uid, st_old.st_gid); 1954#endif 1955 } 1956 } 1957 1958 /* 1959 * Check if the new viminfo file can be written to. 1960 */ 1961 if (fp_out == NULL) 1962 { 1963 EMSG2(_("E138: Can't write viminfo file %s!"), 1964 (fp_in == NULL || tempname == NULL) ? fname : tempname); 1965 if (fp_in != NULL) 1966 fclose(fp_in); 1967 goto end; 1968 } 1969 1970 if (p_verbose > 0) 1971 { 1972 verbose_enter(); 1973 smsg((char_u *)_("Writing viminfo file \"%s\""), fname); 1974 verbose_leave(); 1975 } 1976 1977 viminfo_errcnt = 0; 1978 do_viminfo(fp_in, fp_out, forceit ? 0 : (VIF_WANT_INFO | VIF_WANT_MARKS)); 1979 1980 fclose(fp_out); /* errors are ignored !? */ 1981 if (fp_in != NULL) 1982 { 1983 fclose(fp_in); 1984 1985 /* 1986 * In case of an error keep the original viminfo file. 1987 * Otherwise rename the newly written file. 1988 */ 1989 if (viminfo_errcnt || vim_rename(tempname, fname) == -1) 1990 mch_remove(tempname); 1991 1992#ifdef WIN3264 1993 /* If the viminfo file was hidden then also hide the new file. */ 1994 if (perm > 0 && (perm & FILE_ATTRIBUTE_HIDDEN)) 1995 mch_hide(fname); 1996#endif 1997 } 1998 1999end: 2000 vim_free(fname); 2001 vim_free(tempname); 2002} 2003 2004/* 2005 * Get the viminfo file name to use. 2006 * If "file" is given and not empty, use it (has already been expanded by 2007 * cmdline functions). 2008 * Otherwise use "-i file_name", value from 'viminfo' or the default, and 2009 * expand environment variables. 2010 * Returns an allocated string. NULL when out of memory. 2011 */ 2012 static char_u * 2013viminfo_filename(file) 2014 char_u *file; 2015{ 2016 if (file == NULL || *file == NUL) 2017 { 2018 if (use_viminfo != NULL) 2019 file = use_viminfo; 2020 else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL) 2021 { 2022#ifdef VIMINFO_FILE2 2023 /* don't use $HOME when not defined (turned into "c:/"!). */ 2024# ifdef VMS 2025 if (mch_getenv((char_u *)"SYS$LOGIN") == NULL) 2026# else 2027 if (mch_getenv((char_u *)"HOME") == NULL) 2028# endif 2029 { 2030 /* don't use $VIM when not available. */ 2031 expand_env((char_u *)"$VIM", NameBuff, MAXPATHL); 2032 if (STRCMP("$VIM", NameBuff) != 0) /* $VIM was expanded */ 2033 file = (char_u *)VIMINFO_FILE2; 2034 else 2035 file = (char_u *)VIMINFO_FILE; 2036 } 2037 else 2038#endif 2039 file = (char_u *)VIMINFO_FILE; 2040 } 2041 expand_env(file, NameBuff, MAXPATHL); 2042 file = NameBuff; 2043 } 2044 return vim_strsave(file); 2045} 2046 2047/* 2048 * do_viminfo() -- Should only be called from read_viminfo() & write_viminfo(). 2049 */ 2050 static void 2051do_viminfo(fp_in, fp_out, flags) 2052 FILE *fp_in; 2053 FILE *fp_out; 2054 int flags; 2055{ 2056 int count = 0; 2057 int eof = FALSE; 2058 vir_T vir; 2059 2060 if ((vir.vir_line = alloc(LSIZE)) == NULL) 2061 return; 2062 vir.vir_fd = fp_in; 2063#ifdef FEAT_MBYTE 2064 vir.vir_conv.vc_type = CONV_NONE; 2065#endif 2066 2067 if (fp_in != NULL) 2068 { 2069 if (flags & VIF_WANT_INFO) 2070 eof = read_viminfo_up_to_marks(&vir, 2071 flags & VIF_FORCEIT, fp_out != NULL); 2072 else 2073 /* Skip info, find start of marks */ 2074 while (!(eof = viminfo_readline(&vir)) 2075 && vir.vir_line[0] != '>') 2076 ; 2077 } 2078 if (fp_out != NULL) 2079 { 2080 /* Write the info: */ 2081 fprintf(fp_out, _("# This viminfo file was generated by Vim %s.\n"), 2082 VIM_VERSION_MEDIUM); 2083 fputs(_("# You may edit it if you're careful!\n\n"), fp_out); 2084#ifdef FEAT_MBYTE 2085 fputs(_("# Value of 'encoding' when this file was written\n"), fp_out); 2086 fprintf(fp_out, "*encoding=%s\n\n", p_enc); 2087#endif 2088 write_viminfo_search_pattern(fp_out); 2089 write_viminfo_sub_string(fp_out); 2090#ifdef FEAT_CMDHIST 2091 write_viminfo_history(fp_out); 2092#endif 2093 write_viminfo_registers(fp_out); 2094#ifdef FEAT_EVAL 2095 write_viminfo_varlist(fp_out); 2096#endif 2097 write_viminfo_filemarks(fp_out); 2098 write_viminfo_bufferlist(fp_out); 2099 count = write_viminfo_marks(fp_out); 2100 } 2101 if (fp_in != NULL 2102 && (flags & (VIF_WANT_MARKS | VIF_GET_OLDFILES | VIF_FORCEIT))) 2103 copy_viminfo_marks(&vir, fp_out, count, eof, flags); 2104 2105 vim_free(vir.vir_line); 2106#ifdef FEAT_MBYTE 2107 if (vir.vir_conv.vc_type != CONV_NONE) 2108 convert_setup(&vir.vir_conv, NULL, NULL); 2109#endif 2110} 2111 2112/* 2113 * read_viminfo_up_to_marks() -- Only called from do_viminfo(). Reads in the 2114 * first part of the viminfo file which contains everything but the marks that 2115 * are local to a file. Returns TRUE when end-of-file is reached. -- webb 2116 */ 2117 static int 2118read_viminfo_up_to_marks(virp, forceit, writing) 2119 vir_T *virp; 2120 int forceit; 2121 int writing; 2122{ 2123 int eof; 2124 buf_T *buf; 2125 2126#ifdef FEAT_CMDHIST 2127 prepare_viminfo_history(forceit ? 9999 : 0); 2128#endif 2129 eof = viminfo_readline(virp); 2130 while (!eof && virp->vir_line[0] != '>') 2131 { 2132 switch (virp->vir_line[0]) 2133 { 2134 /* Characters reserved for future expansion, ignored now */ 2135 case '+': /* "+40 /path/dir file", for running vim without args */ 2136 case '|': /* to be defined */ 2137 case '^': /* to be defined */ 2138 case '<': /* long line - ignored */ 2139 /* A comment or empty line. */ 2140 case NUL: 2141 case '\r': 2142 case '\n': 2143 case '#': 2144 eof = viminfo_readline(virp); 2145 break; 2146 case '*': /* "*encoding=value" */ 2147 eof = viminfo_encoding(virp); 2148 break; 2149 case '!': /* global variable */ 2150#ifdef FEAT_EVAL 2151 eof = read_viminfo_varlist(virp, writing); 2152#else 2153 eof = viminfo_readline(virp); 2154#endif 2155 break; 2156 case '%': /* entry for buffer list */ 2157 eof = read_viminfo_bufferlist(virp, writing); 2158 break; 2159 case '"': 2160 eof = read_viminfo_register(virp, forceit); 2161 break; 2162 case '/': /* Search string */ 2163 case '&': /* Substitute search string */ 2164 case '~': /* Last search string, followed by '/' or '&' */ 2165 eof = read_viminfo_search_pattern(virp, forceit); 2166 break; 2167 case '$': 2168 eof = read_viminfo_sub_string(virp, forceit); 2169 break; 2170 case ':': 2171 case '?': 2172 case '=': 2173 case '@': 2174#ifdef FEAT_CMDHIST 2175 eof = read_viminfo_history(virp); 2176#else 2177 eof = viminfo_readline(virp); 2178#endif 2179 break; 2180 case '-': 2181 case '\'': 2182 eof = read_viminfo_filemark(virp, forceit); 2183 break; 2184 default: 2185 if (viminfo_error("E575: ", _("Illegal starting char"), 2186 virp->vir_line)) 2187 eof = TRUE; 2188 else 2189 eof = viminfo_readline(virp); 2190 break; 2191 } 2192 } 2193 2194#ifdef FEAT_CMDHIST 2195 /* Finish reading history items. */ 2196 finish_viminfo_history(); 2197#endif 2198 2199 /* Change file names to buffer numbers for fmarks. */ 2200 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 2201 fmarks_check_names(buf); 2202 2203 return eof; 2204} 2205 2206/* 2207 * Compare the 'encoding' value in the viminfo file with the current value of 2208 * 'encoding'. If different and the 'c' flag is in 'viminfo', setup for 2209 * conversion of text with iconv() in viminfo_readstring(). 2210 */ 2211 static int 2212viminfo_encoding(virp) 2213 vir_T *virp; 2214{ 2215#ifdef FEAT_MBYTE 2216 char_u *p; 2217 int i; 2218 2219 if (get_viminfo_parameter('c') != 0) 2220 { 2221 p = vim_strchr(virp->vir_line, '='); 2222 if (p != NULL) 2223 { 2224 /* remove trailing newline */ 2225 ++p; 2226 for (i = 0; vim_isprintc(p[i]); ++i) 2227 ; 2228 p[i] = NUL; 2229 2230 convert_setup(&virp->vir_conv, p, p_enc); 2231 } 2232 } 2233#endif 2234 return viminfo_readline(virp); 2235} 2236 2237/* 2238 * Read a line from the viminfo file. 2239 * Returns TRUE for end-of-file; 2240 */ 2241 int 2242viminfo_readline(virp) 2243 vir_T *virp; 2244{ 2245 return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd); 2246} 2247 2248/* 2249 * check string read from viminfo file 2250 * remove '\n' at the end of the line 2251 * - replace CTRL-V CTRL-V with CTRL-V 2252 * - replace CTRL-V 'n' with '\n' 2253 * 2254 * Check for a long line as written by viminfo_writestring(). 2255 * 2256 * Return the string in allocated memory (NULL when out of memory). 2257 */ 2258 char_u * 2259viminfo_readstring(virp, off, convert) 2260 vir_T *virp; 2261 int off; /* offset for virp->vir_line */ 2262 int convert UNUSED; /* convert the string */ 2263{ 2264 char_u *retval; 2265 char_u *s, *d; 2266 long len; 2267 2268 if (virp->vir_line[off] == Ctrl_V && vim_isdigit(virp->vir_line[off + 1])) 2269 { 2270 len = atol((char *)virp->vir_line + off + 1); 2271 retval = lalloc(len, TRUE); 2272 if (retval == NULL) 2273 { 2274 /* Line too long? File messed up? Skip next line. */ 2275 (void)vim_fgets(virp->vir_line, 10, virp->vir_fd); 2276 return NULL; 2277 } 2278 (void)vim_fgets(retval, (int)len, virp->vir_fd); 2279 s = retval + 1; /* Skip the leading '<' */ 2280 } 2281 else 2282 { 2283 retval = vim_strsave(virp->vir_line + off); 2284 if (retval == NULL) 2285 return NULL; 2286 s = retval; 2287 } 2288 2289 /* Change CTRL-V CTRL-V to CTRL-V and CTRL-V n to \n in-place. */ 2290 d = retval; 2291 while (*s != NUL && *s != '\n') 2292 { 2293 if (s[0] == Ctrl_V && s[1] != NUL) 2294 { 2295 if (s[1] == 'n') 2296 *d++ = '\n'; 2297 else 2298 *d++ = Ctrl_V; 2299 s += 2; 2300 } 2301 else 2302 *d++ = *s++; 2303 } 2304 *d = NUL; 2305 2306#ifdef FEAT_MBYTE 2307 if (convert && virp->vir_conv.vc_type != CONV_NONE && *retval != NUL) 2308 { 2309 d = string_convert(&virp->vir_conv, retval, NULL); 2310 if (d != NULL) 2311 { 2312 vim_free(retval); 2313 retval = d; 2314 } 2315 } 2316#endif 2317 2318 return retval; 2319} 2320 2321/* 2322 * write string to viminfo file 2323 * - replace CTRL-V with CTRL-V CTRL-V 2324 * - replace '\n' with CTRL-V 'n' 2325 * - add a '\n' at the end 2326 * 2327 * For a long line: 2328 * - write " CTRL-V <length> \n " in first line 2329 * - write " < <string> \n " in second line 2330 */ 2331 void 2332viminfo_writestring(fd, p) 2333 FILE *fd; 2334 char_u *p; 2335{ 2336 int c; 2337 char_u *s; 2338 int len = 0; 2339 2340 for (s = p; *s != NUL; ++s) 2341 { 2342 if (*s == Ctrl_V || *s == '\n') 2343 ++len; 2344 ++len; 2345 } 2346 2347 /* If the string will be too long, write its length and put it in the next 2348 * line. Take into account that some room is needed for what comes before 2349 * the string (e.g., variable name). Add something to the length for the 2350 * '<', NL and trailing NUL. */ 2351 if (len > LSIZE / 2) 2352 fprintf(fd, IF_EB("\026%d\n<", CTRL_V_STR "%d\n<"), len + 3); 2353 2354 while ((c = *p++) != NUL) 2355 { 2356 if (c == Ctrl_V || c == '\n') 2357 { 2358 putc(Ctrl_V, fd); 2359 if (c == '\n') 2360 c = 'n'; 2361 } 2362 putc(c, fd); 2363 } 2364 putc('\n', fd); 2365} 2366#endif /* FEAT_VIMINFO */ 2367 2368/* 2369 * Implementation of ":fixdel", also used by get_stty(). 2370 * <BS> resulting <Del> 2371 * ^? ^H 2372 * not ^? ^? 2373 */ 2374 void 2375do_fixdel(eap) 2376 exarg_T *eap UNUSED; 2377{ 2378 char_u *p; 2379 2380 p = find_termcode((char_u *)"kb"); 2381 add_termcode((char_u *)"kD", p != NULL 2382 && *p == DEL ? (char_u *)CTRL_H_STR : DEL_STR, FALSE); 2383} 2384 2385 void 2386print_line_no_prefix(lnum, use_number, list) 2387 linenr_T lnum; 2388 int use_number; 2389 int list; 2390{ 2391 char_u numbuf[30]; 2392 2393 if (curwin->w_p_nu || use_number) 2394 { 2395 vim_snprintf((char *)numbuf, sizeof(numbuf), 2396 "%*ld ", number_width(curwin), (long)lnum); 2397 msg_puts_attr(numbuf, hl_attr(HLF_N)); /* Highlight line nrs */ 2398 } 2399 msg_prt_line(ml_get(lnum), list); 2400} 2401 2402/* 2403 * Print a text line. Also in silent mode ("ex -s"). 2404 */ 2405 void 2406print_line(lnum, use_number, list) 2407 linenr_T lnum; 2408 int use_number; 2409 int list; 2410{ 2411 int save_silent = silent_mode; 2412 2413 msg_start(); 2414 silent_mode = FALSE; 2415 info_message = TRUE; /* use mch_msg(), not mch_errmsg() */ 2416 print_line_no_prefix(lnum, use_number, list); 2417 if (save_silent) 2418 { 2419 msg_putchar('\n'); 2420 cursor_on(); /* msg_start() switches it off */ 2421 out_flush(); 2422 silent_mode = save_silent; 2423 } 2424 info_message = FALSE; 2425} 2426 2427/* 2428 * ":file[!] [fname]". 2429 */ 2430 void 2431ex_file(eap) 2432 exarg_T *eap; 2433{ 2434 char_u *fname, *sfname, *xfname; 2435 buf_T *buf; 2436 2437 /* ":0file" removes the file name. Check for illegal uses ":3file", 2438 * "0file name", etc. */ 2439 if (eap->addr_count > 0 2440 && (*eap->arg != NUL 2441 || eap->line2 > 0 2442 || eap->addr_count > 1)) 2443 { 2444 EMSG(_(e_invarg)); 2445 return; 2446 } 2447 2448 if (*eap->arg != NUL || eap->addr_count == 1) 2449 { 2450#ifdef FEAT_AUTOCMD 2451 buf = curbuf; 2452 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf); 2453 /* buffer changed, don't change name now */ 2454 if (buf != curbuf) 2455 return; 2456# ifdef FEAT_EVAL 2457 if (aborting()) /* autocmds may abort script processing */ 2458 return; 2459# endif 2460#endif 2461 /* 2462 * The name of the current buffer will be changed. 2463 * A new (unlisted) buffer entry needs to be made to hold the old file 2464 * name, which will become the alternate file name. 2465 * But don't set the alternate file name if the buffer didn't have a 2466 * name. 2467 */ 2468 fname = curbuf->b_ffname; 2469 sfname = curbuf->b_sfname; 2470 xfname = curbuf->b_fname; 2471 curbuf->b_ffname = NULL; 2472 curbuf->b_sfname = NULL; 2473 if (setfname(curbuf, eap->arg, NULL, TRUE) == FAIL) 2474 { 2475 curbuf->b_ffname = fname; 2476 curbuf->b_sfname = sfname; 2477 return; 2478 } 2479 curbuf->b_flags |= BF_NOTEDITED; 2480 if (xfname != NULL && *xfname != NUL) 2481 { 2482 buf = buflist_new(fname, xfname, curwin->w_cursor.lnum, 0); 2483 if (buf != NULL && !cmdmod.keepalt) 2484 curwin->w_alt_fnum = buf->b_fnum; 2485 } 2486 vim_free(fname); 2487 vim_free(sfname); 2488#ifdef FEAT_AUTOCMD 2489 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf); 2490#endif 2491 /* Change directories when the 'acd' option is set. */ 2492 DO_AUTOCHDIR 2493 } 2494 /* print full file name if :cd used */ 2495 fileinfo(FALSE, FALSE, eap->forceit); 2496} 2497 2498/* 2499 * ":update". 2500 */ 2501 void 2502ex_update(eap) 2503 exarg_T *eap; 2504{ 2505 if (curbufIsChanged()) 2506 (void)do_write(eap); 2507} 2508 2509/* 2510 * ":write" and ":saveas". 2511 */ 2512 void 2513ex_write(eap) 2514 exarg_T *eap; 2515{ 2516 if (eap->usefilter) /* input lines to shell command */ 2517 do_bang(1, eap, FALSE, TRUE, FALSE); 2518 else 2519 (void)do_write(eap); 2520} 2521 2522/* 2523 * write current buffer to file 'eap->arg' 2524 * if 'eap->append' is TRUE, append to the file 2525 * 2526 * if *eap->arg == NUL write to current file 2527 * 2528 * return FAIL for failure, OK otherwise 2529 */ 2530 int 2531do_write(eap) 2532 exarg_T *eap; 2533{ 2534 int other; 2535 char_u *fname = NULL; /* init to shut up gcc */ 2536 char_u *ffname; 2537 int retval = FAIL; 2538 char_u *free_fname = NULL; 2539#ifdef FEAT_BROWSE 2540 char_u *browse_file = NULL; 2541#endif 2542 buf_T *alt_buf = NULL; 2543 2544 if (not_writing()) /* check 'write' option */ 2545 return FAIL; 2546 2547 ffname = eap->arg; 2548#ifdef FEAT_BROWSE 2549 if (cmdmod.browse) 2550 { 2551 browse_file = do_browse(BROWSE_SAVE, (char_u *)_("Save As"), ffname, 2552 NULL, NULL, NULL, curbuf); 2553 if (browse_file == NULL) 2554 goto theend; 2555 ffname = browse_file; 2556 } 2557#endif 2558 if (*ffname == NUL) 2559 { 2560 if (eap->cmdidx == CMD_saveas) 2561 { 2562 EMSG(_(e_argreq)); 2563 goto theend; 2564 } 2565 other = FALSE; 2566 } 2567 else 2568 { 2569 fname = ffname; 2570 free_fname = fix_fname(ffname); 2571 /* 2572 * When out-of-memory, keep unexpanded file name, because we MUST be 2573 * able to write the file in this situation. 2574 */ 2575 if (free_fname != NULL) 2576 ffname = free_fname; 2577 other = otherfile(ffname); 2578 } 2579 2580 /* 2581 * If we have a new file, put its name in the list of alternate file names. 2582 */ 2583 if (other) 2584 { 2585 if (vim_strchr(p_cpo, CPO_ALTWRITE) != NULL 2586 || eap->cmdidx == CMD_saveas) 2587 alt_buf = setaltfname(ffname, fname, (linenr_T)1); 2588 else 2589 alt_buf = buflist_findname(ffname); 2590 if (alt_buf != NULL && alt_buf->b_ml.ml_mfp != NULL) 2591 { 2592 /* Overwriting a file that is loaded in another buffer is not a 2593 * good idea. */ 2594 EMSG(_(e_bufloaded)); 2595 goto theend; 2596 } 2597 } 2598 2599 /* 2600 * Writing to the current file is not allowed in readonly mode 2601 * and a file name is required. 2602 * "nofile" and "nowrite" buffers cannot be written implicitly either. 2603 */ 2604 if (!other && ( 2605#ifdef FEAT_QUICKFIX 2606 bt_dontwrite_msg(curbuf) || 2607#endif 2608 check_fname() == FAIL || check_readonly(&eap->forceit, curbuf))) 2609 goto theend; 2610 2611 if (!other) 2612 { 2613 ffname = curbuf->b_ffname; 2614 fname = curbuf->b_fname; 2615 /* 2616 * Not writing the whole file is only allowed with '!'. 2617 */ 2618 if ( (eap->line1 != 1 2619 || eap->line2 != curbuf->b_ml.ml_line_count) 2620 && !eap->forceit 2621 && !eap->append 2622 && !p_wa) 2623 { 2624#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 2625 if (p_confirm || cmdmod.confirm) 2626 { 2627 if (vim_dialog_yesno(VIM_QUESTION, NULL, 2628 (char_u *)_("Write partial file?"), 2) != VIM_YES) 2629 goto theend; 2630 eap->forceit = TRUE; 2631 } 2632 else 2633#endif 2634 { 2635 EMSG(_("E140: Use ! to write partial buffer")); 2636 goto theend; 2637 } 2638 } 2639 } 2640 2641 if (check_overwrite(eap, curbuf, fname, ffname, other) == OK) 2642 { 2643 if (eap->cmdidx == CMD_saveas && alt_buf != NULL) 2644 { 2645#ifdef FEAT_AUTOCMD 2646 buf_T *was_curbuf = curbuf; 2647 2648 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf); 2649 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, alt_buf); 2650# ifdef FEAT_EVAL 2651 if (curbuf != was_curbuf || aborting()) 2652# else 2653 if (curbuf != was_curbuf) 2654# endif 2655 { 2656 /* buffer changed, don't change name now */ 2657 retval = FAIL; 2658 goto theend; 2659 } 2660#endif 2661 /* Exchange the file names for the current and the alternate 2662 * buffer. This makes it look like we are now editing the buffer 2663 * under the new name. Must be done before buf_write(), because 2664 * if there is no file name and 'cpo' contains 'F', it will set 2665 * the file name. */ 2666 fname = alt_buf->b_fname; 2667 alt_buf->b_fname = curbuf->b_fname; 2668 curbuf->b_fname = fname; 2669 fname = alt_buf->b_ffname; 2670 alt_buf->b_ffname = curbuf->b_ffname; 2671 curbuf->b_ffname = fname; 2672 fname = alt_buf->b_sfname; 2673 alt_buf->b_sfname = curbuf->b_sfname; 2674 curbuf->b_sfname = fname; 2675 buf_name_changed(curbuf); 2676#ifdef FEAT_AUTOCMD 2677 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf); 2678 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, alt_buf); 2679 if (!alt_buf->b_p_bl) 2680 { 2681 alt_buf->b_p_bl = TRUE; 2682 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, alt_buf); 2683 } 2684# ifdef FEAT_EVAL 2685 if (curbuf != was_curbuf || aborting()) 2686# else 2687 if (curbuf != was_curbuf) 2688# endif 2689 { 2690 /* buffer changed, don't write the file */ 2691 retval = FAIL; 2692 goto theend; 2693 } 2694 2695 /* If 'filetype' was empty try detecting it now. */ 2696 if (*curbuf->b_p_ft == NUL) 2697 { 2698 if (au_has_group((char_u *)"filetypedetect")) 2699 (void)do_doautocmd((char_u *)"filetypedetect BufRead", 2700 TRUE); 2701 do_modelines(0); 2702 } 2703#endif 2704 } 2705 2706 retval = buf_write(curbuf, ffname, fname, eap->line1, eap->line2, 2707 eap, eap->append, eap->forceit, TRUE, FALSE); 2708 2709 /* After ":saveas fname" reset 'readonly'. */ 2710 if (eap->cmdidx == CMD_saveas) 2711 { 2712 if (retval == OK) 2713 { 2714 curbuf->b_p_ro = FALSE; 2715#ifdef FEAT_WINDOWS 2716 redraw_tabline = TRUE; 2717#endif 2718 } 2719 /* Change directories when the 'acd' option is set. */ 2720 DO_AUTOCHDIR 2721 } 2722 } 2723 2724theend: 2725#ifdef FEAT_BROWSE 2726 vim_free(browse_file); 2727#endif 2728 vim_free(free_fname); 2729 return retval; 2730} 2731 2732/* 2733 * Check if it is allowed to overwrite a file. If b_flags has BF_NOTEDITED, 2734 * BF_NEW or BF_READERR, check for overwriting current file. 2735 * May set eap->forceit if a dialog says it's OK to overwrite. 2736 * Return OK if it's OK, FAIL if it is not. 2737 */ 2738 static int 2739check_overwrite(eap, buf, fname, ffname, other) 2740 exarg_T *eap; 2741 buf_T *buf; 2742 char_u *fname; /* file name to be used (can differ from 2743 buf->ffname) */ 2744 char_u *ffname; /* full path version of fname */ 2745 int other; /* writing under other name */ 2746{ 2747 /* 2748 * write to other file or b_flags set or not writing the whole file: 2749 * overwriting only allowed with '!' 2750 */ 2751 if ( (other 2752 || (buf->b_flags & BF_NOTEDITED) 2753 || ((buf->b_flags & BF_NEW) 2754 && vim_strchr(p_cpo, CPO_OVERNEW) == NULL) 2755 || (buf->b_flags & BF_READERR)) 2756 && !p_wa 2757#ifdef FEAT_QUICKFIX 2758 && !bt_nofile(buf) 2759#endif 2760 && vim_fexists(ffname)) 2761 { 2762 if (!eap->forceit && !eap->append) 2763 { 2764#ifdef UNIX 2765 /* with UNIX it is possible to open a directory */ 2766 if (mch_isdir(ffname)) 2767 { 2768 EMSG2(_(e_isadir2), ffname); 2769 return FAIL; 2770 } 2771#endif 2772#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 2773 if (p_confirm || cmdmod.confirm) 2774 { 2775 char_u buff[IOSIZE]; 2776 2777 dialog_msg(buff, _("Overwrite existing file \"%s\"?"), fname); 2778 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES) 2779 return FAIL; 2780 eap->forceit = TRUE; 2781 } 2782 else 2783#endif 2784 { 2785 EMSG(_(e_exists)); 2786 return FAIL; 2787 } 2788 } 2789 2790 /* For ":w! filename" check that no swap file exists for "filename". */ 2791 if (other && !emsg_silent) 2792 { 2793 char_u dir[MAXPATHL]; 2794 char_u *p; 2795 int r; 2796 char_u *swapname; 2797 2798 /* We only try the first entry in 'directory', without checking if 2799 * it's writable. If the "." directory is not writable the write 2800 * will probably fail anyway. 2801 * Use 'shortname' of the current buffer, since there is no buffer 2802 * for the written file. */ 2803 if (*p_dir == NUL) 2804 STRCPY(dir, "."); 2805 else 2806 { 2807 p = p_dir; 2808 copy_option_part(&p, dir, MAXPATHL, ","); 2809 } 2810 swapname = makeswapname(fname, ffname, curbuf, dir); 2811 r = vim_fexists(swapname); 2812 if (r && !eap->forceit) 2813 { 2814#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 2815 if (p_confirm || cmdmod.confirm) 2816 { 2817 char_u buff[IOSIZE]; 2818 2819 dialog_msg(buff, 2820 _("Swap file \"%s\" exists, overwrite anyway?"), 2821 swapname); 2822 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) 2823 != VIM_YES) 2824 { 2825 vim_free(swapname); 2826 return FAIL; 2827 } 2828 eap->forceit = TRUE; 2829 } 2830 else 2831#endif 2832 { 2833 EMSG2(_("E768: Swap file exists: %s (:silent! overrides)"), 2834 swapname); 2835 vim_free(swapname); 2836 return FAIL; 2837 } 2838 } 2839 vim_free(swapname); 2840 } 2841 } 2842 return OK; 2843} 2844 2845/* 2846 * Handle ":wnext", ":wNext" and ":wprevious" commands. 2847 */ 2848 void 2849ex_wnext(eap) 2850 exarg_T *eap; 2851{ 2852 int i; 2853 2854 if (eap->cmd[1] == 'n') 2855 i = curwin->w_arg_idx + (int)eap->line2; 2856 else 2857 i = curwin->w_arg_idx - (int)eap->line2; 2858 eap->line1 = 1; 2859 eap->line2 = curbuf->b_ml.ml_line_count; 2860 if (do_write(eap) != FAIL) 2861 do_argfile(eap, i); 2862} 2863 2864/* 2865 * ":wall", ":wqall" and ":xall": Write all changed files (and exit). 2866 */ 2867 void 2868do_wqall(eap) 2869 exarg_T *eap; 2870{ 2871 buf_T *buf; 2872 int error = 0; 2873 int save_forceit = eap->forceit; 2874 2875 if (eap->cmdidx == CMD_xall || eap->cmdidx == CMD_wqall) 2876 exiting = TRUE; 2877 2878 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 2879 { 2880 if (bufIsChanged(buf)) 2881 { 2882 /* 2883 * Check if there is a reason the buffer cannot be written: 2884 * 1. if the 'write' option is set 2885 * 2. if there is no file name (even after browsing) 2886 * 3. if the 'readonly' is set (even after a dialog) 2887 * 4. if overwriting is allowed (even after a dialog) 2888 */ 2889 if (not_writing()) 2890 { 2891 ++error; 2892 break; 2893 } 2894#ifdef FEAT_BROWSE 2895 /* ":browse wall": ask for file name if there isn't one */ 2896 if (buf->b_ffname == NULL && cmdmod.browse) 2897 browse_save_fname(buf); 2898#endif 2899 if (buf->b_ffname == NULL) 2900 { 2901 EMSGN(_("E141: No file name for buffer %ld"), (long)buf->b_fnum); 2902 ++error; 2903 } 2904 else if (check_readonly(&eap->forceit, buf) 2905 || check_overwrite(eap, buf, buf->b_fname, buf->b_ffname, 2906 FALSE) == FAIL) 2907 { 2908 ++error; 2909 } 2910 else 2911 { 2912 if (buf_write_all(buf, eap->forceit) == FAIL) 2913 ++error; 2914#ifdef FEAT_AUTOCMD 2915 /* an autocommand may have deleted the buffer */ 2916 if (!buf_valid(buf)) 2917 buf = firstbuf; 2918#endif 2919 } 2920 eap->forceit = save_forceit; /* check_overwrite() may set it */ 2921 } 2922 } 2923 if (exiting) 2924 { 2925 if (!error) 2926 getout(0); /* exit Vim */ 2927 not_exiting(); 2928 } 2929} 2930 2931/* 2932 * Check the 'write' option. 2933 * Return TRUE and give a message when it's not st. 2934 */ 2935 int 2936not_writing() 2937{ 2938 if (p_write) 2939 return FALSE; 2940 EMSG(_("E142: File not written: Writing is disabled by 'write' option")); 2941 return TRUE; 2942} 2943 2944/* 2945 * Check if a buffer is read-only (either 'readonly' option is set or file is 2946 * read-only). Ask for overruling in a dialog. Return TRUE and give an error 2947 * message when the buffer is readonly. 2948 */ 2949 static int 2950check_readonly(forceit, buf) 2951 int *forceit; 2952 buf_T *buf; 2953{ 2954 struct stat st; 2955 2956 /* Handle a file being readonly when the 'readonly' option is set or when 2957 * the file exists and permissions are read-only. 2958 * We will send 0777 to check_file_readonly(), as the "perm" variable is 2959 * important for device checks but not here. */ 2960 if (!*forceit && (buf->b_p_ro 2961 || (mch_stat((char *)buf->b_ffname, &st) >= 0 2962 && check_file_readonly(buf->b_ffname, 0777)))) 2963 { 2964#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 2965 if ((p_confirm || cmdmod.confirm) && buf->b_fname != NULL) 2966 { 2967 char_u buff[IOSIZE]; 2968 2969 if (buf->b_p_ro) 2970 dialog_msg(buff, _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"), 2971 buf->b_fname); 2972 else 2973 dialog_msg(buff, _("File permissions of \"%s\" are read-only.\nIt may still be possible to write it.\nDo you wish to try?"), 2974 buf->b_fname); 2975 2976 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) == VIM_YES) 2977 { 2978 /* Set forceit, to force the writing of a readonly file */ 2979 *forceit = TRUE; 2980 return FALSE; 2981 } 2982 else 2983 return TRUE; 2984 } 2985 else 2986#endif 2987 if (buf->b_p_ro) 2988 EMSG(_(e_readonly)); 2989 else 2990 EMSG2(_("E505: \"%s\" is read-only (add ! to override)"), 2991 buf->b_fname); 2992 return TRUE; 2993 } 2994 2995 return FALSE; 2996} 2997 2998/* 2999 * Try to abandon current file and edit a new or existing file. 3000 * 'fnum' is the number of the file, if zero use ffname/sfname. 3001 * 3002 * Return 1 for "normal" error, 2 for "not written" error, 0 for success 3003 * -1 for successfully opening another file. 3004 * 'lnum' is the line number for the cursor in the new file (if non-zero). 3005 */ 3006 int 3007getfile(fnum, ffname, sfname, setpm, lnum, forceit) 3008 int fnum; 3009 char_u *ffname; 3010 char_u *sfname; 3011 int setpm; 3012 linenr_T lnum; 3013 int forceit; 3014{ 3015 int other; 3016 int retval; 3017 char_u *free_me = NULL; 3018 3019 if (text_locked()) 3020 return 1; 3021#ifdef FEAT_AUTOCMD 3022 if (curbuf_locked()) 3023 return 1; 3024#endif 3025 3026 if (fnum == 0) 3027 { 3028 /* make ffname full path, set sfname */ 3029 fname_expand(curbuf, &ffname, &sfname); 3030 other = otherfile(ffname); 3031 free_me = ffname; /* has been allocated, free() later */ 3032 } 3033 else 3034 other = (fnum != curbuf->b_fnum); 3035 3036 if (other) 3037 ++no_wait_return; /* don't wait for autowrite message */ 3038 if (other && !forceit && curbuf->b_nwindows == 1 && !P_HID(curbuf) 3039 && curbufIsChanged() && autowrite(curbuf, forceit) == FAIL) 3040 { 3041#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 3042 if (p_confirm && p_write) 3043 dialog_changed(curbuf, FALSE); 3044 if (curbufIsChanged()) 3045#endif 3046 { 3047 if (other) 3048 --no_wait_return; 3049 EMSG(_(e_nowrtmsg)); 3050 retval = 2; /* file has been changed */ 3051 goto theend; 3052 } 3053 } 3054 if (other) 3055 --no_wait_return; 3056 if (setpm) 3057 setpcmark(); 3058 if (!other) 3059 { 3060 if (lnum != 0) 3061 curwin->w_cursor.lnum = lnum; 3062 check_cursor_lnum(); 3063 beginline(BL_SOL | BL_FIX); 3064 retval = 0; /* it's in the same file */ 3065 } 3066 else if (do_ecmd(fnum, ffname, sfname, NULL, lnum, 3067 (P_HID(curbuf) ? ECMD_HIDE : 0) + (forceit ? ECMD_FORCEIT : 0), 3068 curwin) == OK) 3069 retval = -1; /* opened another file */ 3070 else 3071 retval = 1; /* error encountered */ 3072 3073theend: 3074 vim_free(free_me); 3075 return retval; 3076} 3077 3078/* 3079 * start editing a new file 3080 * 3081 * fnum: file number; if zero use ffname/sfname 3082 * ffname: the file name 3083 * - full path if sfname used, 3084 * - any file name if sfname is NULL 3085 * - empty string to re-edit with the same file name (but may be 3086 * in a different directory) 3087 * - NULL to start an empty buffer 3088 * sfname: the short file name (or NULL) 3089 * eap: contains the command to be executed after loading the file and 3090 * forced 'ff' and 'fenc' 3091 * newlnum: if > 0: put cursor on this line number (if possible) 3092 * if ECMD_LASTL: use last position in loaded file 3093 * if ECMD_LAST: use last position in all files 3094 * if ECMD_ONE: use first line 3095 * flags: 3096 * ECMD_HIDE: if TRUE don't free the current buffer 3097 * ECMD_SET_HELP: set b_help flag of (new) buffer before opening file 3098 * ECMD_OLDBUF: use existing buffer if it exists 3099 * ECMD_FORCEIT: ! used for Ex command 3100 * ECMD_ADDBUF: don't edit, just add to buffer list 3101 * oldwin: Should be "curwin" when editing a new buffer in the current 3102 * window, NULL when splitting the window first. When not NULL info 3103 * of the previous buffer for "oldwin" is stored. 3104 * 3105 * return FAIL for failure, OK otherwise 3106 */ 3107 int 3108do_ecmd(fnum, ffname, sfname, eap, newlnum, flags, oldwin) 3109 int fnum; 3110 char_u *ffname; 3111 char_u *sfname; 3112 exarg_T *eap; /* can be NULL! */ 3113 linenr_T newlnum; 3114 int flags; 3115 win_T *oldwin; 3116{ 3117 int other_file; /* TRUE if editing another file */ 3118 int oldbuf; /* TRUE if using existing buffer */ 3119#ifdef FEAT_AUTOCMD 3120 int auto_buf = FALSE; /* TRUE if autocommands brought us 3121 into the buffer unexpectedly */ 3122 char_u *new_name = NULL; 3123 int did_set_swapcommand = FALSE; 3124#endif 3125 buf_T *buf; 3126#if defined(FEAT_AUTOCMD) || defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 3127 buf_T *old_curbuf = curbuf; 3128#endif 3129 char_u *free_fname = NULL; 3130#ifdef FEAT_BROWSE 3131 char_u *browse_file = NULL; 3132#endif 3133 int retval = FAIL; 3134 long n; 3135 linenr_T lnum; 3136 linenr_T topline = 0; 3137 int newcol = -1; 3138 int solcol = -1; 3139 pos_T *pos; 3140#ifdef FEAT_SUN_WORKSHOP 3141 char_u *cp; 3142#endif 3143 char_u *command = NULL; 3144#ifdef FEAT_SPELL 3145 int did_get_winopts = FALSE; 3146#endif 3147 int readfile_flags = 0; 3148 3149 if (eap != NULL) 3150 command = eap->do_ecmd_cmd; 3151 3152 if (fnum != 0) 3153 { 3154 if (fnum == curbuf->b_fnum) /* file is already being edited */ 3155 return OK; /* nothing to do */ 3156 other_file = TRUE; 3157 } 3158 else 3159 { 3160#ifdef FEAT_BROWSE 3161 if (cmdmod.browse) 3162 { 3163# ifdef FEAT_AUTOCMD 3164 if ( 3165# ifdef FEAT_GUI 3166 !gui.in_use && 3167# endif 3168 au_has_group((char_u *)"FileExplorer")) 3169 { 3170 /* No browsing supported but we do have the file explorer: 3171 * Edit the directory. */ 3172 if (ffname == NULL || !mch_isdir(ffname)) 3173 ffname = (char_u *)"."; 3174 } 3175 else 3176# endif 3177 { 3178 browse_file = do_browse(0, (char_u *)_("Edit File"), ffname, 3179 NULL, NULL, NULL, curbuf); 3180 if (browse_file == NULL) 3181 goto theend; 3182 ffname = browse_file; 3183 } 3184 } 3185#endif 3186 /* if no short name given, use ffname for short name */ 3187 if (sfname == NULL) 3188 sfname = ffname; 3189#ifdef USE_FNAME_CASE 3190# ifdef USE_LONG_FNAME 3191 if (USE_LONG_FNAME) 3192# endif 3193 if (sfname != NULL) 3194 fname_case(sfname, 0); /* set correct case for sfname */ 3195#endif 3196 3197#ifdef FEAT_LISTCMDS 3198 if ((flags & ECMD_ADDBUF) && (ffname == NULL || *ffname == NUL)) 3199 goto theend; 3200#endif 3201 3202 if (ffname == NULL) 3203 other_file = TRUE; 3204 /* there is no file name */ 3205 else if (*ffname == NUL && curbuf->b_ffname == NULL) 3206 other_file = FALSE; 3207 else 3208 { 3209 if (*ffname == NUL) /* re-edit with same file name */ 3210 { 3211 ffname = curbuf->b_ffname; 3212 sfname = curbuf->b_fname; 3213 } 3214 free_fname = fix_fname(ffname); /* may expand to full path name */ 3215 if (free_fname != NULL) 3216 ffname = free_fname; 3217 other_file = otherfile(ffname); 3218#ifdef FEAT_SUN_WORKSHOP 3219 if (usingSunWorkShop && p_acd 3220 && (cp = vim_strrchr(sfname, '/')) != NULL) 3221 sfname = ++cp; 3222#endif 3223 } 3224 } 3225 3226 /* 3227 * if the file was changed we may not be allowed to abandon it 3228 * - if we are going to re-edit the same file 3229 * - or if we are the only window on this file and if ECMD_HIDE is FALSE 3230 */ 3231 if ( ((!other_file && !(flags & ECMD_OLDBUF)) 3232 || (curbuf->b_nwindows == 1 3233 && !(flags & (ECMD_HIDE | ECMD_ADDBUF)))) 3234 && check_changed(curbuf, p_awa, !other_file, 3235 (flags & ECMD_FORCEIT), FALSE)) 3236 { 3237 if (fnum == 0 && other_file && ffname != NULL) 3238 (void)setaltfname(ffname, sfname, newlnum < 0 ? 0 : newlnum); 3239 goto theend; 3240 } 3241 3242#ifdef FEAT_VISUAL 3243 /* 3244 * End Visual mode before switching to another buffer, so the text can be 3245 * copied into the GUI selection buffer. 3246 */ 3247 reset_VIsual(); 3248#endif 3249 3250#ifdef FEAT_AUTOCMD 3251 if ((command != NULL || newlnum > (linenr_T)0) 3252 && *get_vim_var_str(VV_SWAPCOMMAND) == NUL) 3253 { 3254 int len; 3255 char_u *p; 3256 3257 /* Set v:swapcommand for the SwapExists autocommands. */ 3258 if (command != NULL) 3259 len = (int)STRLEN(command) + 3; 3260 else 3261 len = 30; 3262 p = alloc((unsigned)len); 3263 if (p != NULL) 3264 { 3265 if (command != NULL) 3266 vim_snprintf((char *)p, len, ":%s\r", command); 3267 else 3268 vim_snprintf((char *)p, len, "%ldG", (long)newlnum); 3269 set_vim_var_string(VV_SWAPCOMMAND, p, -1); 3270 did_set_swapcommand = TRUE; 3271 vim_free(p); 3272 } 3273 } 3274#endif 3275 3276 /* 3277 * If we are starting to edit another file, open a (new) buffer. 3278 * Otherwise we re-use the current buffer. 3279 */ 3280 if (other_file) 3281 { 3282#ifdef FEAT_LISTCMDS 3283 if (!(flags & ECMD_ADDBUF)) 3284#endif 3285 { 3286 if (!cmdmod.keepalt) 3287 curwin->w_alt_fnum = curbuf->b_fnum; 3288 if (oldwin != NULL) 3289 buflist_altfpos(oldwin); 3290 } 3291 3292 if (fnum) 3293 buf = buflist_findnr(fnum); 3294 else 3295 { 3296#ifdef FEAT_LISTCMDS 3297 if (flags & ECMD_ADDBUF) 3298 { 3299 linenr_T tlnum = 1L; 3300 3301 if (command != NULL) 3302 { 3303 tlnum = atol((char *)command); 3304 if (tlnum <= 0) 3305 tlnum = 1L; 3306 } 3307 (void)buflist_new(ffname, sfname, tlnum, BLN_LISTED); 3308 goto theend; 3309 } 3310#endif 3311 buf = buflist_new(ffname, sfname, 0L, 3312 BLN_CURBUF | ((flags & ECMD_SET_HELP) ? 0 : BLN_LISTED)); 3313 } 3314 if (buf == NULL) 3315 goto theend; 3316 if (buf->b_ml.ml_mfp == NULL) /* no memfile yet */ 3317 { 3318 oldbuf = FALSE; 3319 buf->b_nwindows = 0; 3320 } 3321 else /* existing memfile */ 3322 { 3323 oldbuf = TRUE; 3324 (void)buf_check_timestamp(buf, FALSE); 3325 /* Check if autocommands made buffer invalid or changed the current 3326 * buffer. */ 3327 if (!buf_valid(buf) 3328#ifdef FEAT_AUTOCMD 3329 || curbuf != old_curbuf 3330#endif 3331 ) 3332 goto theend; 3333#ifdef FEAT_EVAL 3334 if (aborting()) /* autocmds may abort script processing */ 3335 goto theend; 3336#endif 3337 } 3338 3339 /* May jump to last used line number for a loaded buffer or when asked 3340 * for explicitly */ 3341 if ((oldbuf && newlnum == ECMD_LASTL) || newlnum == ECMD_LAST) 3342 { 3343 pos = buflist_findfpos(buf); 3344 newlnum = pos->lnum; 3345 solcol = pos->col; 3346 } 3347 3348 /* 3349 * Make the (new) buffer the one used by the current window. 3350 * If the old buffer becomes unused, free it if ECMD_HIDE is FALSE. 3351 * If the current buffer was empty and has no file name, curbuf 3352 * is returned by buflist_new(). 3353 */ 3354 if (buf != curbuf) 3355 { 3356#ifdef FEAT_AUTOCMD 3357 /* 3358 * Be careful: The autocommands may delete any buffer and change 3359 * the current buffer. 3360 * - If the buffer we are going to edit is deleted, give up. 3361 * - If the current buffer is deleted, prefer to load the new 3362 * buffer when loading a buffer is required. This avoids 3363 * loading another buffer which then must be closed again. 3364 * - If we ended up in the new buffer already, need to skip a few 3365 * things, set auto_buf. 3366 */ 3367 if (buf->b_fname != NULL) 3368 new_name = vim_strsave(buf->b_fname); 3369 au_new_curbuf = buf; 3370 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf); 3371 if (!buf_valid(buf)) /* new buffer has been deleted */ 3372 { 3373 delbuf_msg(new_name); /* frees new_name */ 3374 goto theend; 3375 } 3376# ifdef FEAT_EVAL 3377 if (aborting()) /* autocmds may abort script processing */ 3378 { 3379 vim_free(new_name); 3380 goto theend; 3381 } 3382# endif 3383 if (buf == curbuf) /* already in new buffer */ 3384 auto_buf = TRUE; 3385 else 3386 { 3387 if (curbuf == old_curbuf) 3388#endif 3389 buf_copy_options(buf, BCO_ENTER); 3390 3391 /* close the link to the current buffer */ 3392 u_sync(FALSE); 3393 close_buffer(oldwin, curbuf, 3394 (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD); 3395 3396#ifdef FEAT_AUTOCMD 3397# ifdef FEAT_EVAL 3398 if (aborting()) /* autocmds may abort script processing */ 3399 { 3400 vim_free(new_name); 3401 goto theend; 3402 } 3403# endif 3404 /* Be careful again, like above. */ 3405 if (!buf_valid(buf)) /* new buffer has been deleted */ 3406 { 3407 delbuf_msg(new_name); /* frees new_name */ 3408 goto theend; 3409 } 3410 if (buf == curbuf) /* already in new buffer */ 3411 auto_buf = TRUE; 3412 else 3413#endif 3414 { 3415#ifdef FEAT_SYN_HL 3416 /* 3417 * <VN> We could instead free the synblock 3418 * and re-attach to buffer, perhaps. 3419 */ 3420 if (curwin->w_s == &(curwin->w_buffer->b_s)) 3421 curwin->w_s = &(buf->b_s); 3422#endif 3423 curwin->w_buffer = buf; 3424 curbuf = buf; 3425 ++curbuf->b_nwindows; 3426 /* set 'fileformat' */ 3427 if (*p_ffs && !oldbuf) 3428 set_fileformat(default_fileformat(), OPT_LOCAL); 3429 } 3430 3431 /* May get the window options from the last time this buffer 3432 * was in this window (or another window). If not used 3433 * before, reset the local window options to the global 3434 * values. Also restores old folding stuff. */ 3435 get_winopts(curbuf); 3436#ifdef FEAT_SPELL 3437 did_get_winopts = TRUE; 3438#endif 3439 3440#ifdef FEAT_AUTOCMD 3441 } 3442 vim_free(new_name); 3443 au_new_curbuf = NULL; 3444#endif 3445 } 3446 else 3447 ++curbuf->b_nwindows; 3448 3449 curwin->w_pcmark.lnum = 1; 3450 curwin->w_pcmark.col = 0; 3451 } 3452 else /* !other_file */ 3453 { 3454 if ( 3455#ifdef FEAT_LISTCMDS 3456 (flags & ECMD_ADDBUF) || 3457#endif 3458 check_fname() == FAIL) 3459 goto theend; 3460 oldbuf = (flags & ECMD_OLDBUF); 3461 } 3462 3463 if ((flags & ECMD_SET_HELP) || keep_help_flag) 3464 { 3465 char_u *p; 3466 3467 curbuf->b_help = TRUE; 3468#ifdef FEAT_QUICKFIX 3469 set_string_option_direct((char_u *)"buftype", -1, 3470 (char_u *)"help", OPT_FREE|OPT_LOCAL, 0); 3471#endif 3472 3473 /* 3474 * Always set these options after jumping to a help tag, because the 3475 * user may have an autocommand that gets in the way. 3476 * Accept all ASCII chars for keywords, except ' ', '*', '"', '|', and 3477 * latin1 word characters (for translated help files). 3478 * Only set it when needed, buf_init_chartab() is some work. 3479 */ 3480 p = 3481#ifdef EBCDIC 3482 (char_u *)"65-255,^*,^|,^\""; 3483#else 3484 (char_u *)"!-~,^*,^|,^\",192-255"; 3485#endif 3486 if (STRCMP(curbuf->b_p_isk, p) != 0) 3487 { 3488 set_string_option_direct((char_u *)"isk", -1, p, 3489 OPT_FREE|OPT_LOCAL, 0); 3490 check_buf_options(curbuf); 3491 (void)buf_init_chartab(curbuf, FALSE); 3492 } 3493 3494 curbuf->b_p_ts = 8; /* 'tabstop' is 8 */ 3495 curwin->w_p_list = FALSE; /* no list mode */ 3496 3497 curbuf->b_p_ma = FALSE; /* not modifiable */ 3498 curbuf->b_p_bin = FALSE; /* reset 'bin' before reading file */ 3499 curwin->w_p_nu = 0; /* no line numbers */ 3500 curwin->w_p_rnu = 0; /* no relative line numbers */ 3501#ifdef FEAT_SCROLLBIND 3502 curwin->w_p_scb = FALSE; /* no scroll binding */ 3503#endif 3504#ifdef FEAT_ARABIC 3505 curwin->w_p_arab = FALSE; /* no arabic mode */ 3506#endif 3507#ifdef FEAT_RIGHTLEFT 3508 curwin->w_p_rl = FALSE; /* help window is left-to-right */ 3509#endif 3510#ifdef FEAT_FOLDING 3511 curwin->w_p_fen = FALSE; /* No folding in the help window */ 3512#endif 3513#ifdef FEAT_DIFF 3514 curwin->w_p_diff = FALSE; /* No 'diff' */ 3515#endif 3516#ifdef FEAT_SPELL 3517 curwin->w_p_spell = FALSE; /* No spell checking */ 3518#endif 3519 3520#ifdef FEAT_AUTOCMD 3521 buf = curbuf; 3522#endif 3523 set_buflisted(FALSE); 3524 } 3525 else 3526 { 3527#ifdef FEAT_AUTOCMD 3528 buf = curbuf; 3529#endif 3530 /* Don't make a buffer listed if it's a help buffer. Useful when 3531 * using CTRL-O to go back to a help file. */ 3532 if (!curbuf->b_help) 3533 set_buflisted(TRUE); 3534 } 3535 3536#ifdef FEAT_AUTOCMD 3537 /* If autocommands change buffers under our fingers, forget about 3538 * editing the file. */ 3539 if (buf != curbuf) 3540 goto theend; 3541# ifdef FEAT_EVAL 3542 if (aborting()) /* autocmds may abort script processing */ 3543 goto theend; 3544# endif 3545 3546 /* Since we are starting to edit a file, consider the filetype to be 3547 * unset. Helps for when an autocommand changes files and expects syntax 3548 * highlighting to work in the other file. */ 3549 did_filetype = FALSE; 3550#endif 3551 3552/* 3553 * other_file oldbuf 3554 * FALSE FALSE re-edit same file, buffer is re-used 3555 * FALSE TRUE re-edit same file, nothing changes 3556 * TRUE FALSE start editing new file, new buffer 3557 * TRUE TRUE start editing in existing buffer (nothing to do) 3558 */ 3559 if (!other_file && !oldbuf) /* re-use the buffer */ 3560 { 3561 set_last_cursor(curwin); /* may set b_last_cursor */ 3562 if (newlnum == ECMD_LAST || newlnum == ECMD_LASTL) 3563 { 3564 newlnum = curwin->w_cursor.lnum; 3565 solcol = curwin->w_cursor.col; 3566 } 3567#ifdef FEAT_AUTOCMD 3568 buf = curbuf; 3569 if (buf->b_fname != NULL) 3570 new_name = vim_strsave(buf->b_fname); 3571 else 3572 new_name = NULL; 3573#endif 3574 if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) 3575 { 3576 /* Save all the text, so that the reload can be undone. 3577 * Sync first so that this is a separate undo-able action. */ 3578 u_sync(FALSE); 3579 if (u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE) 3580 == FAIL) 3581 goto theend; 3582 u_unchanged(curbuf); 3583 buf_freeall(curbuf, BFA_KEEP_UNDO); 3584 3585 /* tell readfile() not to clear or reload undo info */ 3586 readfile_flags = READ_KEEP_UNDO; 3587 } 3588 else 3589 buf_freeall(curbuf, 0); /* free all things for buffer */ 3590#ifdef FEAT_AUTOCMD 3591 /* If autocommands deleted the buffer we were going to re-edit, give 3592 * up and jump to the end. */ 3593 if (!buf_valid(buf)) 3594 { 3595 delbuf_msg(new_name); /* frees new_name */ 3596 goto theend; 3597 } 3598 vim_free(new_name); 3599 3600 /* If autocommands change buffers under our fingers, forget about 3601 * re-editing the file. Should do the buf_clear_file(), but perhaps 3602 * the autocommands changed the buffer... */ 3603 if (buf != curbuf) 3604 goto theend; 3605# ifdef FEAT_EVAL 3606 if (aborting()) /* autocmds may abort script processing */ 3607 goto theend; 3608# endif 3609#endif 3610 buf_clear_file(curbuf); 3611 curbuf->b_op_start.lnum = 0; /* clear '[ and '] marks */ 3612 curbuf->b_op_end.lnum = 0; 3613 } 3614 3615/* 3616 * If we get here we are sure to start editing 3617 */ 3618 /* don't redraw until the cursor is in the right line */ 3619 ++RedrawingDisabled; 3620 3621 /* Assume success now */ 3622 retval = OK; 3623 3624 /* 3625 * Reset cursor position, could be used by autocommands. 3626 */ 3627 check_cursor(); 3628 3629 /* 3630 * Check if we are editing the w_arg_idx file in the argument list. 3631 */ 3632 check_arg_idx(curwin); 3633 3634#ifdef FEAT_SYN_HL 3635 reset_synblock(curwin); /* remove any ownsyntax */ 3636#endif 3637 3638#ifdef FEAT_AUTOCMD 3639 if (!auto_buf) 3640#endif 3641 { 3642 /* 3643 * Set cursor and init window before reading the file and executing 3644 * autocommands. This allows for the autocommands to position the 3645 * cursor. 3646 */ 3647 curwin_init(); 3648 3649#ifdef FEAT_FOLDING 3650 /* It's possible that all lines in the buffer changed. Need to update 3651 * automatic folding for all windows where it's used. */ 3652# ifdef FEAT_WINDOWS 3653 { 3654 win_T *win; 3655 tabpage_T *tp; 3656 3657 FOR_ALL_TAB_WINDOWS(tp, win) 3658 if (win->w_buffer == curbuf) 3659 foldUpdateAll(win); 3660 } 3661# else 3662 foldUpdateAll(curwin); 3663# endif 3664#endif 3665 3666 /* Change directories when the 'acd' option is set. */ 3667 DO_AUTOCHDIR 3668 3669 /* 3670 * Careful: open_buffer() and apply_autocmds() may change the current 3671 * buffer and window. 3672 */ 3673 lnum = curwin->w_cursor.lnum; 3674 topline = curwin->w_topline; 3675 if (!oldbuf) /* need to read the file */ 3676 { 3677#if defined(HAS_SWAP_EXISTS_ACTION) 3678 swap_exists_action = SEA_DIALOG; 3679#endif 3680 curbuf->b_flags |= BF_CHECK_RO; /* set/reset 'ro' flag */ 3681 3682 /* 3683 * Open the buffer and read the file. 3684 */ 3685#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 3686 if (should_abort(open_buffer(FALSE, eap, readfile_flags))) 3687 retval = FAIL; 3688#else 3689 (void)open_buffer(FALSE, eap, readfile_flags); 3690#endif 3691 3692#if defined(HAS_SWAP_EXISTS_ACTION) 3693 if (swap_exists_action == SEA_QUIT) 3694 retval = FAIL; 3695 handle_swap_exists(old_curbuf); 3696#endif 3697 } 3698#ifdef FEAT_AUTOCMD 3699 else 3700 { 3701 /* Read the modelines, but only to set window-local options. Any 3702 * buffer-local options have already been set and may have been 3703 * changed by the user. */ 3704 do_modelines(OPT_WINONLY); 3705 3706 apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, 3707 &retval); 3708 apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf, 3709 &retval); 3710 } 3711 check_arg_idx(curwin); 3712#endif 3713 3714 /* 3715 * If autocommands change the cursor position or topline, we should 3716 * keep it. 3717 */ 3718 if (curwin->w_cursor.lnum != lnum) 3719 { 3720 newlnum = curwin->w_cursor.lnum; 3721 newcol = curwin->w_cursor.col; 3722 } 3723 if (curwin->w_topline == topline) 3724 topline = 0; 3725 3726 /* Even when cursor didn't move we need to recompute topline. */ 3727 changed_line_abv_curs(); 3728 3729#ifdef FEAT_TITLE 3730 maketitle(); 3731#endif 3732 } 3733 3734#ifdef FEAT_DIFF 3735 /* Tell the diff stuff that this buffer is new and/or needs updating. 3736 * Also needed when re-editing the same buffer, because unloading will 3737 * have removed it as a diff buffer. */ 3738 if (curwin->w_p_diff) 3739 { 3740 diff_buf_add(curbuf); 3741 diff_invalidate(curbuf); 3742 } 3743#endif 3744 3745#ifdef FEAT_SPELL 3746 /* If the window options were changed may need to set the spell language. 3747 * Can only do this after the buffer has been properly setup. */ 3748 if (did_get_winopts && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) 3749 (void)did_set_spelllang(curwin); 3750#endif 3751 3752 if (command == NULL) 3753 { 3754 if (newcol >= 0) /* position set by autocommands */ 3755 { 3756 curwin->w_cursor.lnum = newlnum; 3757 curwin->w_cursor.col = newcol; 3758 check_cursor(); 3759 } 3760 else if (newlnum > 0) /* line number from caller or old position */ 3761 { 3762 curwin->w_cursor.lnum = newlnum; 3763 check_cursor_lnum(); 3764 if (solcol >= 0 && !p_sol) 3765 { 3766 /* 'sol' is off: Use last known column. */ 3767 curwin->w_cursor.col = solcol; 3768 check_cursor_col(); 3769#ifdef FEAT_VIRTUALEDIT 3770 curwin->w_cursor.coladd = 0; 3771#endif 3772 curwin->w_set_curswant = TRUE; 3773 } 3774 else 3775 beginline(BL_SOL | BL_FIX); 3776 } 3777 else /* no line number, go to last line in Ex mode */ 3778 { 3779 if (exmode_active) 3780 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 3781 beginline(BL_WHITE | BL_FIX); 3782 } 3783 } 3784 3785#ifdef FEAT_WINDOWS 3786 /* Check if cursors in other windows on the same buffer are still valid */ 3787 check_lnums(FALSE); 3788#endif 3789 3790 /* 3791 * Did not read the file, need to show some info about the file. 3792 * Do this after setting the cursor. 3793 */ 3794 if (oldbuf 3795#ifdef FEAT_AUTOCMD 3796 && !auto_buf 3797#endif 3798 ) 3799 { 3800 int msg_scroll_save = msg_scroll; 3801 3802 /* Obey the 'O' flag in 'cpoptions': overwrite any previous file 3803 * message. */ 3804 if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) 3805 msg_scroll = FALSE; 3806 if (!msg_scroll) /* wait a bit when overwriting an error msg */ 3807 check_for_delay(FALSE); 3808 msg_start(); 3809 msg_scroll = msg_scroll_save; 3810 msg_scrolled_ign = TRUE; 3811 3812 fileinfo(FALSE, TRUE, FALSE); 3813 3814 msg_scrolled_ign = FALSE; 3815 } 3816 3817 if (command != NULL) 3818 do_cmdline(command, NULL, NULL, DOCMD_VERBOSE); 3819 3820#ifdef FEAT_KEYMAP 3821 if (curbuf->b_kmap_state & KEYMAP_INIT) 3822 (void)keymap_init(); 3823#endif 3824 3825 --RedrawingDisabled; 3826 if (!skip_redraw) 3827 { 3828 n = p_so; 3829 if (topline == 0 && command == NULL) 3830 p_so = 999; /* force cursor halfway the window */ 3831 update_topline(); 3832#ifdef FEAT_SCROLLBIND 3833 curwin->w_scbind_pos = curwin->w_topline; 3834#endif 3835 p_so = n; 3836 redraw_curbuf_later(NOT_VALID); /* redraw this buffer later */ 3837 } 3838 3839 if (p_im) 3840 need_start_insertmode = TRUE; 3841 3842 /* Change directories when the 'acd' option is set. */ 3843 DO_AUTOCHDIR 3844 3845#if defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG) 3846 if (curbuf->b_ffname != NULL) 3847 { 3848# ifdef FEAT_SUN_WORKSHOP 3849 if (gui.in_use && usingSunWorkShop) 3850 workshop_file_opened((char *)curbuf->b_ffname, curbuf->b_p_ro); 3851# endif 3852# ifdef FEAT_NETBEANS_INTG 3853 if ((flags & ECMD_SET_HELP) != ECMD_SET_HELP) 3854 netbeans_file_opened(curbuf); 3855# endif 3856 } 3857#endif 3858 3859theend: 3860#ifdef FEAT_AUTOCMD 3861 if (did_set_swapcommand) 3862 set_vim_var_string(VV_SWAPCOMMAND, NULL, -1); 3863#endif 3864#ifdef FEAT_BROWSE 3865 vim_free(browse_file); 3866#endif 3867 vim_free(free_fname); 3868 return retval; 3869} 3870 3871#ifdef FEAT_AUTOCMD 3872 static void 3873delbuf_msg(name) 3874 char_u *name; 3875{ 3876 EMSG2(_("E143: Autocommands unexpectedly deleted new buffer %s"), 3877 name == NULL ? (char_u *)"" : name); 3878 vim_free(name); 3879 au_new_curbuf = NULL; 3880} 3881#endif 3882 3883static int append_indent = 0; /* autoindent for first line */ 3884 3885/* 3886 * ":insert" and ":append", also used by ":change" 3887 */ 3888 void 3889ex_append(eap) 3890 exarg_T *eap; 3891{ 3892 char_u *theline; 3893 int did_undo = FALSE; 3894 linenr_T lnum = eap->line2; 3895 int indent = 0; 3896 char_u *p; 3897 int vcol; 3898 int empty = (curbuf->b_ml.ml_flags & ML_EMPTY); 3899 3900 /* the ! flag toggles autoindent */ 3901 if (eap->forceit) 3902 curbuf->b_p_ai = !curbuf->b_p_ai; 3903 3904 /* First autoindent comes from the line we start on */ 3905 if (eap->cmdidx != CMD_change && curbuf->b_p_ai && lnum > 0) 3906 append_indent = get_indent_lnum(lnum); 3907 3908 if (eap->cmdidx != CMD_append) 3909 --lnum; 3910 3911 /* when the buffer is empty append to line 0 and delete the dummy line */ 3912 if (empty && lnum == 1) 3913 lnum = 0; 3914 3915 State = INSERT; /* behave like in Insert mode */ 3916 if (curbuf->b_p_iminsert == B_IMODE_LMAP) 3917 State |= LANGMAP; 3918 3919 for (;;) 3920 { 3921 msg_scroll = TRUE; 3922 need_wait_return = FALSE; 3923 if (curbuf->b_p_ai) 3924 { 3925 if (append_indent >= 0) 3926 { 3927 indent = append_indent; 3928 append_indent = -1; 3929 } 3930 else if (lnum > 0) 3931 indent = get_indent_lnum(lnum); 3932 } 3933 ex_keep_indent = FALSE; 3934 if (eap->getline == NULL) 3935 { 3936 /* No getline() function, use the lines that follow. This ends 3937 * when there is no more. */ 3938 if (eap->nextcmd == NULL || *eap->nextcmd == NUL) 3939 break; 3940 p = vim_strchr(eap->nextcmd, NL); 3941 if (p == NULL) 3942 p = eap->nextcmd + STRLEN(eap->nextcmd); 3943 theline = vim_strnsave(eap->nextcmd, (int)(p - eap->nextcmd)); 3944 if (*p != NUL) 3945 ++p; 3946 eap->nextcmd = p; 3947 } 3948 else 3949 theline = eap->getline( 3950#ifdef FEAT_EVAL 3951 eap->cstack->cs_looplevel > 0 ? -1 : 3952#endif 3953 NUL, eap->cookie, indent); 3954 lines_left = Rows - 1; 3955 if (theline == NULL) 3956 break; 3957 3958 /* Using ^ CTRL-D in getexmodeline() makes us repeat the indent. */ 3959 if (ex_keep_indent) 3960 append_indent = indent; 3961 3962 /* Look for the "." after automatic indent. */ 3963 vcol = 0; 3964 for (p = theline; indent > vcol; ++p) 3965 { 3966 if (*p == ' ') 3967 ++vcol; 3968 else if (*p == TAB) 3969 vcol += 8 - vcol % 8; 3970 else 3971 break; 3972 } 3973 if ((p[0] == '.' && p[1] == NUL) 3974 || (!did_undo && u_save(lnum, lnum + 1 + (empty ? 1 : 0)) 3975 == FAIL)) 3976 { 3977 vim_free(theline); 3978 break; 3979 } 3980 3981 /* don't use autoindent if nothing was typed. */ 3982 if (p[0] == NUL) 3983 theline[0] = NUL; 3984 3985 did_undo = TRUE; 3986 ml_append(lnum, theline, (colnr_T)0, FALSE); 3987 appended_lines_mark(lnum, 1L); 3988 3989 vim_free(theline); 3990 ++lnum; 3991 3992 if (empty) 3993 { 3994 ml_delete(2L, FALSE); 3995 empty = FALSE; 3996 } 3997 } 3998 State = NORMAL; 3999 4000 if (eap->forceit) 4001 curbuf->b_p_ai = !curbuf->b_p_ai; 4002 4003 /* "start" is set to eap->line2+1 unless that position is invalid (when 4004 * eap->line2 pointed to the end of the buffer and nothing was appended) 4005 * "end" is set to lnum when something has been appended, otherwise 4006 * it is the same than "start" -- Acevedo */ 4007 curbuf->b_op_start.lnum = (eap->line2 < curbuf->b_ml.ml_line_count) ? 4008 eap->line2 + 1 : curbuf->b_ml.ml_line_count; 4009 if (eap->cmdidx != CMD_append) 4010 --curbuf->b_op_start.lnum; 4011 curbuf->b_op_end.lnum = (eap->line2 < lnum) 4012 ? lnum : curbuf->b_op_start.lnum; 4013 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 4014 curwin->w_cursor.lnum = lnum; 4015 check_cursor_lnum(); 4016 beginline(BL_SOL | BL_FIX); 4017 4018 need_wait_return = FALSE; /* don't use wait_return() now */ 4019 ex_no_reprint = TRUE; 4020} 4021 4022/* 4023 * ":change" 4024 */ 4025 void 4026ex_change(eap) 4027 exarg_T *eap; 4028{ 4029 linenr_T lnum; 4030 4031 if (eap->line2 >= eap->line1 4032 && u_save(eap->line1 - 1, eap->line2 + 1) == FAIL) 4033 return; 4034 4035 /* the ! flag toggles autoindent */ 4036 if (eap->forceit ? !curbuf->b_p_ai : curbuf->b_p_ai) 4037 append_indent = get_indent_lnum(eap->line1); 4038 4039 for (lnum = eap->line2; lnum >= eap->line1; --lnum) 4040 { 4041 if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */ 4042 break; 4043 ml_delete(eap->line1, FALSE); 4044 } 4045 4046 /* make sure the cursor is not beyond the end of the file now */ 4047 check_cursor_lnum(); 4048 deleted_lines_mark(eap->line1, (long)(eap->line2 - lnum)); 4049 4050 /* ":append" on the line above the deleted lines. */ 4051 eap->line2 = eap->line1; 4052 ex_append(eap); 4053} 4054 4055 void 4056ex_z(eap) 4057 exarg_T *eap; 4058{ 4059 char_u *x; 4060 int bigness; 4061 char_u *kind; 4062 int minus = 0; 4063 linenr_T start, end, curs, i; 4064 int j; 4065 linenr_T lnum = eap->line2; 4066 4067 /* Vi compatible: ":z!" uses display height, without a count uses 4068 * 'scroll' */ 4069 if (eap->forceit) 4070 bigness = curwin->w_height; 4071 else if (firstwin == lastwin) 4072 bigness = p_window_unix2003 ? p_window_unix2003 : curwin->w_p_scr * 2; 4073#ifdef FEAT_WINDOWS 4074 else 4075 bigness = curwin->w_height - 3; 4076#endif 4077 if (bigness < 1) 4078 bigness = 1; 4079 4080 x = eap->arg; 4081 kind = x; 4082 if (*kind == '-' || *kind == '+' || *kind == '=' 4083 || *kind == '^' || *kind == '.') 4084 ++x; 4085 while (*x == '-' || *x == '+') 4086 ++x; 4087 4088 if (*x != 0) 4089 { 4090 if (!VIM_ISDIGIT(*x)) 4091 { 4092 EMSG(_("E144: non-numeric argument to :z")); 4093 return; 4094 } 4095 else 4096 { 4097 bigness = atoi((char *)x); 4098 p_window = bigness; 4099 if (*kind == '=') 4100 bigness += 2; 4101 } 4102 } 4103 4104 /* the number of '-' and '+' multiplies the distance */ 4105 if (*kind == '-' || *kind == '+') 4106 for (x = kind + 1; *x == *kind; ++x) 4107 ; 4108 4109 switch (*kind) 4110 { 4111 case '-': 4112 start = lnum - bigness * (linenr_T)(x - kind); 4113 end = start + bigness; 4114 curs = end; 4115 break; 4116 4117 case '=': 4118 start = lnum - (bigness + 1) / 2 + 1; 4119 end = lnum + (bigness + 1) / 2 - 1; 4120 curs = lnum; 4121 minus = 1; 4122 break; 4123 4124 case '^': 4125 start = lnum - bigness * 2; 4126 end = lnum - bigness; 4127 curs = lnum - bigness; 4128 break; 4129 4130 case '.': 4131 start = lnum - (bigness + 1) / 2 + 1; 4132 end = lnum + (bigness + 1) / 2 - 1; 4133 curs = end; 4134 break; 4135 4136 default: /* '+' */ 4137 start = lnum; 4138 if (*kind == '+') 4139 start += bigness * (linenr_T)(x - kind - 1) + 1; 4140 else if (eap->addr_count == 0) 4141 ++start; 4142 end = start + bigness - 1; 4143 curs = end; 4144 break; 4145 } 4146 4147 if (start < 1) 4148 start = 1; 4149 4150 if (end > curbuf->b_ml.ml_line_count) 4151 end = curbuf->b_ml.ml_line_count; 4152 4153 if (curs > curbuf->b_ml.ml_line_count) 4154 curs = curbuf->b_ml.ml_line_count; 4155 4156 for (i = start; i <= end; i++) 4157 { 4158 if (minus && i == lnum) 4159 { 4160 msg_putchar('\n'); 4161 4162 for (j = 1; j < Columns; j++) 4163 msg_putchar('-'); 4164 } 4165 4166 print_line(i, eap->flags & EXFLAG_NR, eap->flags & EXFLAG_LIST); 4167 4168 if (minus && i == lnum) 4169 { 4170 msg_putchar('\n'); 4171 4172 for (j = 1; j < Columns; j++) 4173 msg_putchar('-'); 4174 } 4175 } 4176 4177 curwin->w_cursor.lnum = curs; 4178 ex_no_reprint = TRUE; 4179} 4180 4181/* 4182 * Check if the restricted flag is set. 4183 * If so, give an error message and return TRUE. 4184 * Otherwise, return FALSE. 4185 */ 4186 int 4187check_restricted() 4188{ 4189 if (restricted) 4190 { 4191 EMSG(_("E145: Shell commands not allowed in rvim")); 4192 return TRUE; 4193 } 4194 return FALSE; 4195} 4196 4197/* 4198 * Check if the secure flag is set (.exrc or .vimrc in current directory). 4199 * If so, give an error message and return TRUE. 4200 * Otherwise, return FALSE. 4201 */ 4202 int 4203check_secure() 4204{ 4205 if (secure) 4206 { 4207 secure = 2; 4208 EMSG(_(e_curdir)); 4209 return TRUE; 4210 } 4211#ifdef HAVE_SANDBOX 4212 /* 4213 * In the sandbox more things are not allowed, including the things 4214 * disallowed in secure mode. 4215 */ 4216 if (sandbox != 0) 4217 { 4218 EMSG(_(e_sandbox)); 4219 return TRUE; 4220 } 4221#endif 4222 return FALSE; 4223} 4224 4225static char_u *old_sub = NULL; /* previous substitute pattern */ 4226static int global_need_beginline; /* call beginline() after ":g" */ 4227 4228/* do_sub() 4229 * 4230 * Perform a substitution from line eap->line1 to line eap->line2 using the 4231 * command pointed to by eap->arg which should be of the form: 4232 * 4233 * /pattern/substitution/{flags} 4234 * 4235 * The usual escapes are supported as described in the regexp docs. 4236 */ 4237 void 4238do_sub(eap) 4239 exarg_T *eap; 4240{ 4241 linenr_T lnum; 4242 long i = 0; 4243 regmmatch_T regmatch; 4244 static int do_all = FALSE; /* do multiple substitutions per line */ 4245 static int do_ask = FALSE; /* ask for confirmation */ 4246 static int do_count = FALSE; /* count only */ 4247 static int do_error = TRUE; /* if false, ignore errors */ 4248 static int do_print = FALSE; /* print last line with subs. */ 4249 static int do_list = FALSE; /* list last line with subs. */ 4250 static int do_number = FALSE; /* list last line with line nr*/ 4251 static int do_ic = 0; /* ignore case flag */ 4252 char_u *pat = NULL, *sub = NULL; /* init for GCC */ 4253 int delimiter; 4254 int sublen; 4255 int got_quit = FALSE; 4256 int got_match = FALSE; 4257 int temp; 4258 int which_pat; 4259 char_u *cmd; 4260 int save_State; 4261 linenr_T first_line = 0; /* first changed line */ 4262 linenr_T last_line= 0; /* below last changed line AFTER the 4263 * change */ 4264 linenr_T old_line_count = curbuf->b_ml.ml_line_count; 4265 linenr_T line2; 4266 long nmatch; /* number of lines in match */ 4267 char_u *sub_firstline; /* allocated copy of first sub line */ 4268 int endcolumn = FALSE; /* cursor in last column when done */ 4269 pos_T old_cursor = curwin->w_cursor; 4270 int start_nsubs; 4271 4272 cmd = eap->arg; 4273 if (!global_busy) 4274 { 4275 sub_nsubs = 0; 4276 sub_nlines = 0; 4277 } 4278 start_nsubs = sub_nsubs; 4279 4280 if (eap->cmdidx == CMD_tilde) 4281 which_pat = RE_LAST; /* use last used regexp */ 4282 else 4283 which_pat = RE_SUBST; /* use last substitute regexp */ 4284 4285 /* new pattern and substitution */ 4286 if (eap->cmd[0] == 's' && *cmd != NUL && !vim_iswhite(*cmd) 4287 && vim_strchr((char_u *)"0123456789cegriIp|\"", *cmd) == NULL) 4288 { 4289 /* don't accept alphanumeric for separator */ 4290 if (isalpha(*cmd)) 4291 { 4292 EMSG(_("E146: Regular expressions can't be delimited by letters")); 4293 return; 4294 } 4295 /* 4296 * undocumented vi feature: 4297 * "\/sub/" and "\?sub?" use last used search pattern (almost like 4298 * //sub/r). "\&sub&" use last substitute pattern (like //sub/). 4299 */ 4300 if (*cmd == '\\') 4301 { 4302 ++cmd; 4303 if (vim_strchr((char_u *)"/?&", *cmd) == NULL) 4304 { 4305 EMSG(_(e_backslash)); 4306 return; 4307 } 4308 if (*cmd != '&') 4309 which_pat = RE_SEARCH; /* use last '/' pattern */ 4310 pat = (char_u *)""; /* empty search pattern */ 4311 delimiter = *cmd++; /* remember delimiter character */ 4312 } 4313 else /* find the end of the regexp */ 4314 { 4315#ifdef FEAT_FKMAP /* reverse the flow of the Farsi characters */ 4316 if (p_altkeymap && curwin->w_p_rl) 4317 lrF_sub(cmd); 4318#endif 4319 which_pat = RE_LAST; /* use last used regexp */ 4320 delimiter = *cmd++; /* remember delimiter character */ 4321 pat = cmd; /* remember start of search pat */ 4322 cmd = skip_regexp(cmd, delimiter, p_magic, &eap->arg); 4323 if (cmd[0] == delimiter) /* end delimiter found */ 4324 *cmd++ = NUL; /* replace it with a NUL */ 4325 } 4326 4327 /* 4328 * Small incompatibility: vi sees '\n' as end of the command, but in 4329 * Vim we want to use '\n' to find/substitute a NUL. 4330 */ 4331 sub = cmd; /* remember the start of the substitution */ 4332 4333 while (cmd[0]) 4334 { 4335 if (cmd[0] == delimiter) /* end delimiter found */ 4336 { 4337 *cmd++ = NUL; /* replace it with a NUL */ 4338 break; 4339 } 4340 if (cmd[0] == '\\' && cmd[1] != 0) /* skip escaped characters */ 4341 ++cmd; 4342 mb_ptr_adv(cmd); 4343 } 4344 4345 if (!eap->skip) 4346 { 4347 /* In POSIX vi ":s/pat/%/" uses the previous subst. string. */ 4348 if (STRCMP(sub, "%") == 0 4349 && vim_strchr(p_cpo, CPO_SUBPERCENT) != NULL) 4350 { 4351 if (old_sub == NULL) /* there is no previous command */ 4352 { 4353 EMSG(_(e_nopresub)); 4354 return; 4355 } 4356 sub = old_sub; 4357 } 4358 else 4359 { 4360 vim_free(old_sub); 4361 old_sub = vim_strsave(sub); 4362 } 4363 } 4364 } 4365 else if (!eap->skip) /* use previous pattern and substitution */ 4366 { 4367 if (old_sub == NULL) /* there is no previous command */ 4368 { 4369 EMSG(_(e_nopresub)); 4370 return; 4371 } 4372 pat = NULL; /* search_regcomp() will use previous pattern */ 4373 sub = old_sub; 4374 4375 /* Vi compatibility quirk: repeating with ":s" keeps the cursor in the 4376 * last column after using "$". */ 4377 endcolumn = (curwin->w_curswant == MAXCOL); 4378 } 4379 4380 /* 4381 * Find trailing options. When '&' is used, keep old options. 4382 */ 4383 if (*cmd == '&') 4384 ++cmd; 4385 else 4386 { 4387 if (!p_ed) 4388 { 4389 if (p_gd) /* default is global on */ 4390 do_all = TRUE; 4391 else 4392 do_all = FALSE; 4393 do_ask = FALSE; 4394 } 4395 do_error = TRUE; 4396 do_print = FALSE; 4397 do_count = FALSE; 4398 do_number = FALSE; 4399 do_ic = 0; 4400 } 4401 while (*cmd) 4402 { 4403 /* 4404 * Note that 'g' and 'c' are always inverted, also when p_ed is off. 4405 * 'r' is never inverted. 4406 */ 4407 if (*cmd == 'g') 4408 do_all = !do_all; 4409 else if (*cmd == 'c') 4410 do_ask = !do_ask; 4411 else if (*cmd == 'n') 4412 do_count = TRUE; 4413 else if (*cmd == 'e') 4414 do_error = !do_error; 4415 else if (*cmd == 'r') /* use last used regexp */ 4416 which_pat = RE_LAST; 4417 else if (*cmd == 'p') 4418 do_print = TRUE; 4419 else if (*cmd == '#') 4420 { 4421 do_print = TRUE; 4422 do_number = TRUE; 4423 } 4424 else if (*cmd == 'l') 4425 { 4426 do_print = TRUE; 4427 do_list = TRUE; 4428 } 4429 else if (*cmd == 'i') /* ignore case */ 4430 do_ic = 'i'; 4431 else if (*cmd == 'I') /* don't ignore case */ 4432 do_ic = 'I'; 4433 else 4434 break; 4435 ++cmd; 4436 } 4437 if (do_count) 4438 do_ask = FALSE; 4439 4440 /* 4441 * check for a trailing count 4442 */ 4443 cmd = skipwhite(cmd); 4444 if (VIM_ISDIGIT(*cmd)) 4445 { 4446 i = getdigits(&cmd); 4447 if (i <= 0 && !eap->skip && do_error) 4448 { 4449 EMSG(_(e_zerocount)); 4450 return; 4451 } 4452 eap->line1 = eap->line2; 4453 eap->line2 += i - 1; 4454 if (eap->line2 > curbuf->b_ml.ml_line_count) 4455 eap->line2 = curbuf->b_ml.ml_line_count; 4456 } 4457 4458 /* 4459 * check for trailing command or garbage 4460 */ 4461 cmd = skipwhite(cmd); 4462 if (*cmd && *cmd != '"') /* if not end-of-line or comment */ 4463 { 4464 eap->nextcmd = check_nextcmd(cmd); 4465 if (eap->nextcmd == NULL) 4466 { 4467 EMSG(_(e_trailing)); 4468 return; 4469 } 4470 } 4471 4472 if (eap->skip) /* not executing commands, only parsing */ 4473 return; 4474 4475 if (!do_count && !curbuf->b_p_ma) 4476 { 4477 /* Substitution is not allowed in non-'modifiable' buffer */ 4478 EMSG(_(e_modifiable)); 4479 return; 4480 } 4481 4482 if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, ®match) == FAIL) 4483 { 4484 if (do_error) 4485 EMSG(_(e_invcmd)); 4486 return; 4487 } 4488 4489 /* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */ 4490 if (do_ic == 'i') 4491 regmatch.rmm_ic = TRUE; 4492 else if (do_ic == 'I') 4493 regmatch.rmm_ic = FALSE; 4494 4495 sub_firstline = NULL; 4496 4497 /* 4498 * ~ in the substitute pattern is replaced with the old pattern. 4499 * We do it here once to avoid it to be replaced over and over again. 4500 * But don't do it when it starts with "\=", then it's an expression. 4501 */ 4502 if (!(sub[0] == '\\' && sub[1] == '=')) 4503 sub = regtilde(sub, p_magic); 4504 4505 /* 4506 * Check for a match on each line. 4507 */ 4508 line2 = eap->line2; 4509 for (lnum = eap->line1; lnum <= line2 && !(got_quit 4510#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD) 4511 || aborting() 4512#endif 4513 ); ++lnum) 4514 { 4515 nmatch = vim_regexec_multi(®match, curwin, curbuf, lnum, 4516 (colnr_T)0, NULL); 4517 if (nmatch) 4518 { 4519 colnr_T copycol; 4520 colnr_T matchcol; 4521 colnr_T prev_matchcol = MAXCOL; 4522 char_u *new_end, *new_start = NULL; 4523 unsigned new_start_len = 0; 4524 char_u *p1; 4525 int did_sub = FALSE; 4526 int lastone; 4527 int len, copy_len, needed_len; 4528 long nmatch_tl = 0; /* nr of lines matched below lnum */ 4529 int do_again; /* do it again after joining lines */ 4530 int skip_match = FALSE; 4531 linenr_T sub_firstlnum; /* nr of first sub line */ 4532 4533 /* 4534 * The new text is build up step by step, to avoid too much 4535 * copying. There are these pieces: 4536 * sub_firstline The old text, unmodified. 4537 * copycol Column in the old text where we started 4538 * looking for a match; from here old text still 4539 * needs to be copied to the new text. 4540 * matchcol Column number of the old text where to look 4541 * for the next match. It's just after the 4542 * previous match or one further. 4543 * prev_matchcol Column just after the previous match (if any). 4544 * Mostly equal to matchcol, except for the first 4545 * match and after skipping an empty match. 4546 * regmatch.*pos Where the pattern matched in the old text. 4547 * new_start The new text, all that has been produced so 4548 * far. 4549 * new_end The new text, where to append new text. 4550 * 4551 * lnum The line number where we found the start of 4552 * the match. Can be below the line we searched 4553 * when there is a \n before a \zs in the 4554 * pattern. 4555 * sub_firstlnum The line number in the buffer where to look 4556 * for a match. Can be different from "lnum" 4557 * when the pattern or substitute string contains 4558 * line breaks. 4559 * 4560 * Special situations: 4561 * - When the substitute string contains a line break, the part up 4562 * to the line break is inserted in the text, but the copy of 4563 * the original line is kept. "sub_firstlnum" is adjusted for 4564 * the inserted lines. 4565 * - When the matched pattern contains a line break, the old line 4566 * is taken from the line at the end of the pattern. The lines 4567 * in the match are deleted later, "sub_firstlnum" is adjusted 4568 * accordingly. 4569 * 4570 * The new text is built up in new_start[]. It has some extra 4571 * room to avoid using alloc()/free() too often. new_start_len is 4572 * the length of the allocated memory at new_start. 4573 * 4574 * Make a copy of the old line, so it won't be taken away when 4575 * updating the screen or handling a multi-line match. The "old_" 4576 * pointers point into this copy. 4577 */ 4578 sub_firstlnum = lnum; 4579 copycol = 0; 4580 matchcol = 0; 4581 4582 /* At first match, remember current cursor position. */ 4583 if (!got_match) 4584 { 4585 setpcmark(); 4586 got_match = TRUE; 4587 } 4588 4589 /* 4590 * Loop until nothing more to replace in this line. 4591 * 1. Handle match with empty string. 4592 * 2. If do_ask is set, ask for confirmation. 4593 * 3. substitute the string. 4594 * 4. if do_all is set, find next match 4595 * 5. break if there isn't another match in this line 4596 */ 4597 for (;;) 4598 { 4599 /* Advance "lnum" to the line where the match starts. The 4600 * match does not start in the first line when there is a line 4601 * break before \zs. */ 4602 if (regmatch.startpos[0].lnum > 0) 4603 { 4604 lnum += regmatch.startpos[0].lnum; 4605 sub_firstlnum += regmatch.startpos[0].lnum; 4606 nmatch -= regmatch.startpos[0].lnum; 4607 vim_free(sub_firstline); 4608 sub_firstline = NULL; 4609 } 4610 4611 if (sub_firstline == NULL) 4612 { 4613 sub_firstline = vim_strsave(ml_get(sub_firstlnum)); 4614 if (sub_firstline == NULL) 4615 { 4616 vim_free(new_start); 4617 goto outofmem; 4618 } 4619 } 4620 4621 /* Save the line number of the last change for the final 4622 * cursor position (just like Vi). */ 4623 curwin->w_cursor.lnum = lnum; 4624 do_again = FALSE; 4625 4626 /* 4627 * 1. Match empty string does not count, except for first 4628 * match. This reproduces the strange vi behaviour. 4629 * This also catches endless loops. 4630 */ 4631 if (matchcol == prev_matchcol 4632 && regmatch.endpos[0].lnum == 0 4633 && matchcol == regmatch.endpos[0].col) 4634 { 4635 if (sub_firstline[matchcol] == NUL) 4636 /* We already were at the end of the line. Don't look 4637 * for a match in this line again. */ 4638 skip_match = TRUE; 4639 else 4640 ++matchcol; /* search for a match at next column */ 4641 goto skip; 4642 } 4643 4644 /* Normally we continue searching for a match just after the 4645 * previous match. */ 4646 matchcol = regmatch.endpos[0].col; 4647 prev_matchcol = matchcol; 4648 4649 /* 4650 * 2. If do_count is set only increase the counter. 4651 * If do_ask is set, ask for confirmation. 4652 */ 4653 if (do_count) 4654 { 4655 /* For a multi-line match, put matchcol at the NUL at 4656 * the end of the line and set nmatch to one, so that 4657 * we continue looking for a match on the next line. 4658 * Avoids that ":s/\nB\@=//gc" get stuck. */ 4659 if (nmatch > 1) 4660 { 4661 matchcol = (colnr_T)STRLEN(sub_firstline); 4662 nmatch = 1; 4663 skip_match = TRUE; 4664 } 4665 sub_nsubs++; 4666 did_sub = TRUE; 4667 goto skip; 4668 } 4669 4670 if (do_ask) 4671 { 4672 int typed = 0; 4673 4674 /* change State to CONFIRM, so that the mouse works 4675 * properly */ 4676 save_State = State; 4677 State = CONFIRM; 4678#ifdef FEAT_MOUSE 4679 setmouse(); /* disable mouse in xterm */ 4680#endif 4681 curwin->w_cursor.col = regmatch.startpos[0].col; 4682 4683 /* When 'cpoptions' contains "u" don't sync undo when 4684 * asking for confirmation. */ 4685 if (vim_strchr(p_cpo, CPO_UNDO) != NULL) 4686 ++no_u_sync; 4687 4688 /* 4689 * Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed. 4690 */ 4691 while (do_ask) 4692 { 4693 if (exmode_active) 4694 { 4695 char_u *resp; 4696 colnr_T sc, ec; 4697 4698 print_line_no_prefix(lnum, FALSE, FALSE); 4699 4700 getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL); 4701 curwin->w_cursor.col = regmatch.endpos[0].col - 1; 4702 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec); 4703 msg_start(); 4704 for (i = 0; i < (long)sc; ++i) 4705 msg_putchar(' '); 4706 for ( ; i <= (long)ec; ++i) 4707 msg_putchar('^'); 4708 4709 resp = getexmodeline('?', NULL, 0); 4710 if (resp != NULL) 4711 { 4712 typed = *resp; 4713 vim_free(resp); 4714 } 4715 } 4716 else 4717 { 4718#ifdef FEAT_FOLDING 4719 int save_p_fen = curwin->w_p_fen; 4720 4721 curwin->w_p_fen = FALSE; 4722#endif 4723 /* Invert the matched string. 4724 * Remove the inversion afterwards. */ 4725 temp = RedrawingDisabled; 4726 RedrawingDisabled = 0; 4727 4728 search_match_lines = regmatch.endpos[0].lnum 4729 - regmatch.startpos[0].lnum; 4730 search_match_endcol = regmatch.endpos[0].col; 4731 highlight_match = TRUE; 4732 4733 update_topline(); 4734 validate_cursor(); 4735 update_screen(SOME_VALID); 4736 highlight_match = FALSE; 4737 redraw_later(SOME_VALID); 4738 4739#ifdef FEAT_FOLDING 4740 curwin->w_p_fen = save_p_fen; 4741#endif 4742 if (msg_row == Rows - 1) 4743 msg_didout = FALSE; /* avoid a scroll-up */ 4744 msg_starthere(); 4745 i = msg_scroll; 4746 msg_scroll = 0; /* truncate msg when 4747 needed */ 4748 msg_no_more = TRUE; 4749 /* write message same highlighting as for 4750 * wait_return */ 4751 smsg_attr(hl_attr(HLF_R), 4752 (char_u *)_("replace with %s (y/n/a/q/l/^E/^Y)?"), sub); 4753 msg_no_more = FALSE; 4754 msg_scroll = i; 4755 showruler(TRUE); 4756 windgoto(msg_row, msg_col); 4757 RedrawingDisabled = temp; 4758 4759#ifdef USE_ON_FLY_SCROLL 4760 dont_scroll = FALSE; /* allow scrolling here */ 4761#endif 4762 ++no_mapping; /* don't map this key */ 4763 ++allow_keys; /* allow special keys */ 4764 typed = plain_vgetc(); 4765 --allow_keys; 4766 --no_mapping; 4767 4768 /* clear the question */ 4769 msg_didout = FALSE; /* don't scroll up */ 4770 msg_col = 0; 4771 gotocmdline(TRUE); 4772 } 4773 4774 need_wait_return = FALSE; /* no hit-return prompt */ 4775 if (typed == 'q' || typed == ESC || typed == Ctrl_C 4776#ifdef UNIX 4777 || typed == intr_char 4778#endif 4779 ) 4780 { 4781 got_quit = TRUE; 4782 break; 4783 } 4784 if (typed == 'n') 4785 break; 4786 if (typed == 'y') 4787 break; 4788 if (typed == 'l') 4789 { 4790 /* last: replace and then stop */ 4791 do_all = FALSE; 4792 line2 = lnum; 4793 break; 4794 } 4795 if (typed == 'a') 4796 { 4797 do_ask = FALSE; 4798 break; 4799 } 4800#ifdef FEAT_INS_EXPAND 4801 if (typed == Ctrl_E) 4802 scrollup_clamp(); 4803 else if (typed == Ctrl_Y) 4804 scrolldown_clamp(); 4805#endif 4806 } 4807 State = save_State; 4808#ifdef FEAT_MOUSE 4809 setmouse(); 4810#endif 4811 if (vim_strchr(p_cpo, CPO_UNDO) != NULL) 4812 --no_u_sync; 4813 4814 if (typed == 'n') 4815 { 4816 /* For a multi-line match, put matchcol at the NUL at 4817 * the end of the line and set nmatch to one, so that 4818 * we continue looking for a match on the next line. 4819 * Avoids that ":%s/\nB\@=//gc" and ":%s/\n/,\r/gc" 4820 * get stuck when pressing 'n'. */ 4821 if (nmatch > 1) 4822 { 4823 matchcol = (colnr_T)STRLEN(sub_firstline); 4824 skip_match = TRUE; 4825 } 4826 goto skip; 4827 } 4828 if (got_quit) 4829 break; 4830 } 4831 4832 /* Move the cursor to the start of the match, so that we can 4833 * use "\=col("."). */ 4834 curwin->w_cursor.col = regmatch.startpos[0].col; 4835 4836 /* 4837 * 3. substitute the string. 4838 */ 4839 /* get length of substitution part */ 4840 sublen = vim_regsub_multi(®match, 4841 sub_firstlnum - regmatch.startpos[0].lnum, 4842 sub, sub_firstline, FALSE, p_magic, TRUE); 4843 4844 /* When the match included the "$" of the last line it may 4845 * go beyond the last line of the buffer. */ 4846 if (nmatch > curbuf->b_ml.ml_line_count - sub_firstlnum + 1) 4847 { 4848 nmatch = curbuf->b_ml.ml_line_count - sub_firstlnum + 1; 4849 skip_match = TRUE; 4850 } 4851 4852 /* Need room for: 4853 * - result so far in new_start (not for first sub in line) 4854 * - original text up to match 4855 * - length of substituted part 4856 * - original text after match 4857 */ 4858 if (nmatch == 1) 4859 p1 = sub_firstline; 4860 else 4861 { 4862 p1 = ml_get(sub_firstlnum + nmatch - 1); 4863 nmatch_tl += nmatch - 1; 4864 } 4865 copy_len = regmatch.startpos[0].col - copycol; 4866 needed_len = copy_len + ((unsigned)STRLEN(p1) 4867 - regmatch.endpos[0].col) + sublen + 1; 4868 if (new_start == NULL) 4869 { 4870 /* 4871 * Get some space for a temporary buffer to do the 4872 * substitution into (and some extra space to avoid 4873 * too many calls to alloc()/free()). 4874 */ 4875 new_start_len = needed_len + 50; 4876 if ((new_start = alloc_check(new_start_len)) == NULL) 4877 goto outofmem; 4878 *new_start = NUL; 4879 new_end = new_start; 4880 } 4881 else 4882 { 4883 /* 4884 * Check if the temporary buffer is long enough to do the 4885 * substitution into. If not, make it larger (with a bit 4886 * extra to avoid too many calls to alloc()/free()). 4887 */ 4888 len = (unsigned)STRLEN(new_start); 4889 needed_len += len; 4890 if (needed_len > (int)new_start_len) 4891 { 4892 new_start_len = needed_len + 50; 4893 if ((p1 = alloc_check(new_start_len)) == NULL) 4894 { 4895 vim_free(new_start); 4896 goto outofmem; 4897 } 4898 mch_memmove(p1, new_start, (size_t)(len + 1)); 4899 vim_free(new_start); 4900 new_start = p1; 4901 } 4902 new_end = new_start + len; 4903 } 4904 4905 /* 4906 * copy the text up to the part that matched 4907 */ 4908 mch_memmove(new_end, sub_firstline + copycol, (size_t)copy_len); 4909 new_end += copy_len; 4910 4911 (void)vim_regsub_multi(®match, 4912 sub_firstlnum - regmatch.startpos[0].lnum, 4913 sub, new_end, TRUE, p_magic, TRUE); 4914 sub_nsubs++; 4915 did_sub = TRUE; 4916 4917 /* Move the cursor to the start of the line, to avoid that it 4918 * is beyond the end of the line after the substitution. */ 4919 curwin->w_cursor.col = 0; 4920 4921 /* For a multi-line match, make a copy of the last matched 4922 * line and continue in that one. */ 4923 if (nmatch > 1) 4924 { 4925 sub_firstlnum += nmatch - 1; 4926 vim_free(sub_firstline); 4927 sub_firstline = vim_strsave(ml_get(sub_firstlnum)); 4928 /* When going beyond the last line, stop substituting. */ 4929 if (sub_firstlnum <= line2) 4930 do_again = TRUE; 4931 else 4932 do_all = FALSE; 4933 } 4934 4935 /* Remember next character to be copied. */ 4936 copycol = regmatch.endpos[0].col; 4937 4938 if (skip_match) 4939 { 4940 /* Already hit end of the buffer, sub_firstlnum is one 4941 * less than what it ought to be. */ 4942 vim_free(sub_firstline); 4943 sub_firstline = vim_strsave((char_u *)""); 4944 copycol = 0; 4945 } 4946 4947 /* 4948 * Now the trick is to replace CTRL-M chars with a real line 4949 * break. This would make it impossible to insert a CTRL-M in 4950 * the text. The line break can be avoided by preceding the 4951 * CTRL-M with a backslash. To be able to insert a backslash, 4952 * they must be doubled in the string and are halved here. 4953 * That is Vi compatible. 4954 */ 4955 for (p1 = new_end; *p1; ++p1) 4956 { 4957 if (p1[0] == '\\' && p1[1] != NUL) /* remove backslash */ 4958 STRMOVE(p1, p1 + 1); 4959 else if (*p1 == CAR) 4960 { 4961 if (u_inssub(lnum) == OK) /* prepare for undo */ 4962 { 4963 *p1 = NUL; /* truncate up to the CR */ 4964 ml_append(lnum - 1, new_start, 4965 (colnr_T)(p1 - new_start + 1), FALSE); 4966 mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L); 4967 if (do_ask) 4968 appended_lines(lnum - 1, 1L); 4969 else 4970 { 4971 if (first_line == 0) 4972 first_line = lnum; 4973 last_line = lnum + 1; 4974 } 4975 /* All line numbers increase. */ 4976 ++sub_firstlnum; 4977 ++lnum; 4978 ++line2; 4979 /* move the cursor to the new line, like Vi */ 4980 ++curwin->w_cursor.lnum; 4981 /* copy the rest */ 4982 STRMOVE(new_start, p1 + 1); 4983 p1 = new_start - 1; 4984 } 4985 } 4986#ifdef FEAT_MBYTE 4987 else if (has_mbyte) 4988 p1 += (*mb_ptr2len)(p1) - 1; 4989#endif 4990 } 4991 4992 /* 4993 * 4. If do_all is set, find next match. 4994 * Prevent endless loop with patterns that match empty 4995 * strings, e.g. :s/$/pat/g or :s/[a-z]* /(&)/g. 4996 * But ":s/\n/#/" is OK. 4997 */ 4998skip: 4999 /* We already know that we did the last subst when we are at 5000 * the end of the line, except that a pattern like 5001 * "bar\|\nfoo" may match at the NUL. "lnum" can be below 5002 * "line2" when there is a \zs in the pattern after a line 5003 * break. */ 5004 lastone = (skip_match 5005 || got_int 5006 || got_quit 5007 || lnum > line2 5008 || !(do_all || do_again) 5009 || (sub_firstline[matchcol] == NUL && nmatch <= 1 5010 && !re_multiline(regmatch.regprog))); 5011 nmatch = -1; 5012 5013 /* 5014 * Replace the line in the buffer when needed. This is 5015 * skipped when there are more matches. 5016 * The check for nmatch_tl is needed for when multi-line 5017 * matching must replace the lines before trying to do another 5018 * match, otherwise "\@<=" won't work. 5019 * When asking the user we like to show the already replaced 5020 * text, but don't do it when "\<@=" or "\<@!" is used, it 5021 * changes what matches. 5022 * When the match starts below where we start searching also 5023 * need to replace the line first (using \zs after \n). 5024 */ 5025 if (lastone 5026 || (do_ask && !re_lookbehind(regmatch.regprog)) 5027 || nmatch_tl > 0 5028 || (nmatch = vim_regexec_multi(®match, curwin, 5029 curbuf, sub_firstlnum, 5030 matchcol, NULL)) == 0 5031 || regmatch.startpos[0].lnum > 0) 5032 { 5033 if (new_start != NULL) 5034 { 5035 /* 5036 * Copy the rest of the line, that didn't match. 5037 * "matchcol" has to be adjusted, we use the end of 5038 * the line as reference, because the substitute may 5039 * have changed the number of characters. Same for 5040 * "prev_matchcol". 5041 */ 5042 STRCAT(new_start, sub_firstline + copycol); 5043 matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol; 5044 prev_matchcol = (colnr_T)STRLEN(sub_firstline) 5045 - prev_matchcol; 5046 5047 if (Unix2003_compat) 5048 beginline(BL_WHITE | BL_FIX); 5049 if (u_savesub(lnum) != OK) 5050 break; 5051 ml_replace(lnum, new_start, TRUE); 5052 5053 if (nmatch_tl > 0) 5054 { 5055 /* 5056 * Matched lines have now been substituted and are 5057 * useless, delete them. The part after the match 5058 * has been appended to new_start, we don't need 5059 * it in the buffer. 5060 */ 5061 ++lnum; 5062 if (u_savedel(lnum, nmatch_tl) != OK) 5063 break; 5064 for (i = 0; i < nmatch_tl; ++i) 5065 ml_delete(lnum, (int)FALSE); 5066 mark_adjust(lnum, lnum + nmatch_tl - 1, 5067 (long)MAXLNUM, -nmatch_tl); 5068 if (do_ask) 5069 deleted_lines(lnum, nmatch_tl); 5070 --lnum; 5071 line2 -= nmatch_tl; /* nr of lines decreases */ 5072 nmatch_tl = 0; 5073 } 5074 5075 /* When asking, undo is saved each time, must also set 5076 * changed flag each time. */ 5077 if (do_ask) 5078 changed_bytes(lnum, 0); 5079 else 5080 { 5081 if (first_line == 0) 5082 first_line = lnum; 5083 last_line = lnum + 1; 5084 } 5085 5086 sub_firstlnum = lnum; 5087 vim_free(sub_firstline); /* free the temp buffer */ 5088 sub_firstline = new_start; 5089 new_start = NULL; 5090 matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol; 5091 prev_matchcol = (colnr_T)STRLEN(sub_firstline) 5092 - prev_matchcol; 5093 copycol = 0; 5094 } 5095 if (nmatch == -1 && !lastone) 5096 nmatch = vim_regexec_multi(®match, curwin, curbuf, 5097 sub_firstlnum, matchcol, NULL); 5098 5099 /* 5100 * 5. break if there isn't another match in this line 5101 */ 5102 if (nmatch <= 0) 5103 { 5104 /* If the match found didn't start where we were 5105 * searching, do the next search in the line where we 5106 * found the match. */ 5107 if (nmatch == -1) 5108 lnum -= regmatch.startpos[0].lnum; 5109 break; 5110 } 5111 } 5112 5113 line_breakcheck(); 5114 } 5115 5116 if (did_sub) 5117 ++sub_nlines; 5118 vim_free(new_start); /* for when substitute was cancelled */ 5119 vim_free(sub_firstline); /* free the copy of the original line */ 5120 sub_firstline = NULL; 5121 } 5122 5123 line_breakcheck(); 5124 } 5125 5126 if (first_line != 0) 5127 { 5128 /* Need to subtract the number of added lines from "last_line" to get 5129 * the line number before the change (same as adding the number of 5130 * deleted lines). */ 5131 i = curbuf->b_ml.ml_line_count - old_line_count; 5132 changed_lines(first_line, 0, last_line - i, i); 5133 } 5134 5135outofmem: 5136 vim_free(sub_firstline); /* may have to free allocated copy of the line */ 5137 5138 /* ":s/pat//n" doesn't move the cursor */ 5139 if (do_count) 5140 curwin->w_cursor = old_cursor; 5141 5142 if (sub_nsubs > start_nsubs) 5143 { 5144 /* Set the '[ and '] marks. */ 5145 curbuf->b_op_start.lnum = eap->line1; 5146 curbuf->b_op_end.lnum = line2; 5147 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 5148 5149 if (!global_busy) 5150 { 5151 if (endcolumn) 5152 coladvance((colnr_T)MAXCOL); 5153 else 5154 beginline(BL_WHITE | BL_FIX); 5155 if (!do_sub_msg(do_count) && do_ask) 5156 MSG(""); 5157 } 5158 else 5159 global_need_beginline = TRUE; 5160 if (do_print) 5161 print_line(curwin->w_cursor.lnum, do_number, do_list); 5162 } 5163 else if (!global_busy) 5164 { 5165 if (got_int) /* interrupted */ 5166 EMSG(_(e_interr)); 5167 else if (got_match) /* did find something but nothing substituted */ 5168 MSG(""); 5169 else if (do_error) /* nothing found */ 5170 EMSG2(_(e_patnotf2), get_search_pat()); 5171 } 5172 5173 vim_free(regmatch.regprog); 5174} 5175 5176/* 5177 * Give message for number of substitutions. 5178 * Can also be used after a ":global" command. 5179 * Return TRUE if a message was given. 5180 */ 5181 int 5182do_sub_msg(count_only) 5183 int count_only; /* used 'n' flag for ":s" */ 5184{ 5185 /* 5186 * Only report substitutions when: 5187 * - more than 'report' substitutions 5188 * - command was typed by user, or number of changed lines > 'report' 5189 * - giving messages is not disabled by 'lazyredraw' 5190 */ 5191 if (((sub_nsubs > p_report && (KeyTyped || sub_nlines > 1 || p_report < 1)) 5192 || count_only) 5193 && messaging()) 5194 { 5195 if (got_int) 5196 STRCPY(msg_buf, _("(Interrupted) ")); 5197 else 5198 *msg_buf = NUL; 5199 if (sub_nsubs == 1) 5200 vim_snprintf_add((char *)msg_buf, sizeof(msg_buf), 5201 "%s", count_only ? _("1 match") : _("1 substitution")); 5202 else 5203 vim_snprintf_add((char *)msg_buf, sizeof(msg_buf), 5204 count_only ? _("%ld matches") : _("%ld substitutions"), 5205 sub_nsubs); 5206 if (sub_nlines == 1) 5207 vim_snprintf_add((char *)msg_buf, sizeof(msg_buf), 5208 "%s", _(" on 1 line")); 5209 else 5210 vim_snprintf_add((char *)msg_buf, sizeof(msg_buf), 5211 _(" on %ld lines"), (long)sub_nlines); 5212 if (msg(msg_buf)) 5213 /* save message to display it after redraw */ 5214 set_keep_msg(msg_buf, 0); 5215 return TRUE; 5216 } 5217 if (got_int) 5218 { 5219 EMSG(_(e_interr)); 5220 return TRUE; 5221 } 5222 return FALSE; 5223} 5224 5225/* 5226 * Execute a global command of the form: 5227 * 5228 * g/pattern/X : execute X on all lines where pattern matches 5229 * v/pattern/X : execute X on all lines where pattern does not match 5230 * 5231 * where 'X' is an EX command 5232 * 5233 * The command character (as well as the trailing slash) is optional, and 5234 * is assumed to be 'p' if missing. 5235 * 5236 * This is implemented in two passes: first we scan the file for the pattern and 5237 * set a mark for each line that (not) matches. secondly we execute the command 5238 * for each line that has a mark. This is required because after deleting 5239 * lines we do not know where to search for the next match. 5240 */ 5241 void 5242ex_global(eap) 5243 exarg_T *eap; 5244{ 5245 linenr_T lnum; /* line number according to old situation */ 5246 int ndone = 0; 5247 int type; /* first char of cmd: 'v' or 'g' */ 5248 char_u *cmd; /* command argument */ 5249 5250 char_u delim; /* delimiter, normally '/' */ 5251 char_u *pat; 5252 regmmatch_T regmatch; 5253 int match; 5254 int which_pat; 5255 5256 if (global_busy) 5257 { 5258 EMSG(_("E147: Cannot do :global recursive")); /* will increment global_busy */ 5259 return; 5260 } 5261 5262 if (eap->forceit) /* ":global!" is like ":vglobal" */ 5263 type = 'v'; 5264 else 5265 type = *eap->cmd; 5266 cmd = eap->arg; 5267 which_pat = RE_LAST; /* default: use last used regexp */ 5268 5269 /* 5270 * undocumented vi feature: 5271 * "\/" and "\?": use previous search pattern. 5272 * "\&": use previous substitute pattern. 5273 */ 5274 if (*cmd == '\\') 5275 { 5276 ++cmd; 5277 if (vim_strchr((char_u *)"/?&", *cmd) == NULL) 5278 { 5279 EMSG(_(e_backslash)); 5280 return; 5281 } 5282 if (*cmd == '&') 5283 which_pat = RE_SUBST; /* use previous substitute pattern */ 5284 else 5285 which_pat = RE_SEARCH; /* use previous search pattern */ 5286 ++cmd; 5287 pat = (char_u *)""; 5288 } 5289 else if (*cmd == NUL) 5290 { 5291 EMSG(_("E148: Regular expression missing from global")); 5292 return; 5293 } 5294 else 5295 { 5296 delim = *cmd; /* get the delimiter */ 5297 if (delim) 5298 ++cmd; /* skip delimiter if there is one */ 5299 pat = cmd; /* remember start of pattern */ 5300 cmd = skip_regexp(cmd, delim, p_magic, &eap->arg); 5301 if (cmd[0] == delim) /* end delimiter found */ 5302 *cmd++ = NUL; /* replace it with a NUL */ 5303 } 5304 5305#ifdef FEAT_FKMAP /* when in Farsi mode, reverse the character flow */ 5306 if (p_altkeymap && curwin->w_p_rl) 5307 lrFswap(pat,0); 5308#endif 5309 5310 if (search_regcomp(pat, RE_BOTH, which_pat, SEARCH_HIS, ®match) == FAIL) 5311 { 5312 EMSG(_(e_invcmd)); 5313 return; 5314 } 5315 5316 /* 5317 * pass 1: set marks for each (not) matching line 5318 */ 5319 for (lnum = eap->line1; lnum <= eap->line2 && !got_int; ++lnum) 5320 { 5321 /* a match on this line? */ 5322 match = vim_regexec_multi(®match, curwin, curbuf, lnum, 5323 (colnr_T)0, NULL); 5324 if ((type == 'g' && match) || (type == 'v' && !match)) 5325 { 5326 ml_setmarked(lnum); 5327 ndone++; 5328 } 5329 line_breakcheck(); 5330 } 5331 5332 /* 5333 * pass 2: execute the command for each line that has been marked 5334 */ 5335 if (got_int) 5336 MSG(_(e_interr)); 5337 else if (ndone == 0) 5338 { 5339 if (type == 'v') 5340 smsg((char_u *)_("Pattern found in every line: %s"), pat); 5341 else 5342 smsg((char_u *)_(e_patnotf2), pat); 5343 } 5344 else 5345 { 5346 global_last_cmd = 1; 5347 global_exe(cmd); 5348 } 5349 5350 ml_clearmarked(); /* clear rest of the marks */ 5351 vim_free(regmatch.regprog); 5352} 5353 5354/* 5355 * Execute "cmd" on lines marked with ml_setmarked(). 5356 */ 5357 void 5358global_exe(cmd) 5359 char_u *cmd; 5360{ 5361 linenr_T old_lcount; /* b_ml.ml_line_count before the command */ 5362 linenr_T lnum; /* line number according to old situation */ 5363 5364 /* 5365 * Set current position only once for a global command. 5366 * If global_busy is set, setpcmark() will not do anything. 5367 * If there is an error, global_busy will be incremented. 5368 */ 5369 setpcmark(); 5370 5371 /* When the command writes a message, don't overwrite the command. */ 5372 msg_didout = TRUE; 5373 5374 sub_nsubs = 0; 5375 sub_nlines = 0; 5376 global_need_beginline = FALSE; 5377 global_busy = 1; 5378 old_lcount = curbuf->b_ml.ml_line_count; 5379 while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1) 5380 { 5381 curwin->w_cursor.lnum = lnum; 5382 curwin->w_cursor.col = 0; 5383 if (*cmd == NUL || *cmd == '\n') 5384 do_cmdline((char_u *)"p", NULL, NULL, DOCMD_NOWAIT); 5385 else 5386 do_cmdline(cmd, NULL, NULL, DOCMD_NOWAIT); 5387 ui_breakcheck(); 5388 } 5389 5390 global_busy = 0; 5391 if (global_need_beginline) 5392 beginline(BL_WHITE | BL_FIX); 5393 else 5394 check_cursor(); /* cursor may be beyond the end of the line */ 5395 5396 /* the cursor may not have moved in the text but a change in a previous 5397 * line may move it on the screen */ 5398 changed_line_abv_curs(); 5399 5400 /* If it looks like no message was written, allow overwriting the 5401 * command with the report for number of changes. */ 5402 if (msg_col == 0 && msg_scrolled == 0) 5403 msg_didout = FALSE; 5404 5405 /* If substitutes done, report number of substitutes, otherwise report 5406 * number of extra or deleted lines. */ 5407 if (!do_sub_msg(FALSE)) 5408 msgmore(curbuf->b_ml.ml_line_count - old_lcount); 5409} 5410 5411#ifdef FEAT_VIMINFO 5412 int 5413read_viminfo_sub_string(virp, force) 5414 vir_T *virp; 5415 int force; 5416{ 5417 if (old_sub != NULL && force) 5418 vim_free(old_sub); 5419 if (force || old_sub == NULL) 5420 old_sub = viminfo_readstring(virp, 1, TRUE); 5421 return viminfo_readline(virp); 5422} 5423 5424 void 5425write_viminfo_sub_string(fp) 5426 FILE *fp; 5427{ 5428 if (get_viminfo_parameter('/') != 0 && old_sub != NULL) 5429 { 5430 fputs(_("\n# Last Substitute String:\n$"), fp); 5431 viminfo_writestring(fp, old_sub); 5432 } 5433} 5434#endif /* FEAT_VIMINFO */ 5435 5436#if defined(EXITFREE) || defined(PROTO) 5437 void 5438free_old_sub() 5439{ 5440 vim_free(old_sub); 5441} 5442#endif 5443 5444#if (defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)) || defined(PROTO) 5445/* 5446 * Set up for a tagpreview. 5447 * Return TRUE when it was created. 5448 */ 5449 int 5450prepare_tagpreview(undo_sync) 5451 int undo_sync; /* sync undo when leaving the window */ 5452{ 5453 win_T *wp; 5454 5455# ifdef FEAT_GUI 5456 need_mouse_correct = TRUE; 5457# endif 5458 5459 /* 5460 * If there is already a preview window open, use that one. 5461 */ 5462 if (!curwin->w_p_pvw) 5463 { 5464 for (wp = firstwin; wp != NULL; wp = wp->w_next) 5465 if (wp->w_p_pvw) 5466 break; 5467 if (wp != NULL) 5468 win_enter(wp, undo_sync); 5469 else 5470 { 5471 /* 5472 * There is no preview window open yet. Create one. 5473 */ 5474 if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0) 5475 == FAIL) 5476 return FALSE; 5477 curwin->w_p_pvw = TRUE; 5478 curwin->w_p_wfh = TRUE; 5479# ifdef FEAT_SCROLLBIND 5480 curwin->w_p_scb = FALSE; /* don't take over 'scrollbind' */ 5481# endif 5482# ifdef FEAT_DIFF 5483 curwin->w_p_diff = FALSE; /* no 'diff' */ 5484# endif 5485# ifdef FEAT_FOLDING 5486 curwin->w_p_fdc = 0; /* no 'foldcolumn' */ 5487# endif 5488 return TRUE; 5489 } 5490 } 5491 return FALSE; 5492} 5493 5494#endif 5495 5496 5497/* 5498 * ":help": open a read-only window on a help file 5499 */ 5500 void 5501ex_help(eap) 5502 exarg_T *eap; 5503{ 5504 char_u *arg; 5505 char_u *tag; 5506 FILE *helpfd; /* file descriptor of help file */ 5507 int n; 5508 int i; 5509#ifdef FEAT_WINDOWS 5510 win_T *wp; 5511#endif 5512 int num_matches; 5513 char_u **matches; 5514 char_u *p; 5515 int empty_fnum = 0; 5516 int alt_fnum = 0; 5517 buf_T *buf; 5518#ifdef FEAT_MULTI_LANG 5519 int len; 5520 char_u *lang; 5521#endif 5522 5523 if (eap != NULL) 5524 { 5525 /* 5526 * A ":help" command ends at the first LF, or at a '|' that is 5527 * followed by some text. Set nextcmd to the following command. 5528 */ 5529 for (arg = eap->arg; *arg; ++arg) 5530 { 5531 if (*arg == '\n' || *arg == '\r' 5532 || (*arg == '|' && arg[1] != NUL && arg[1] != '|')) 5533 { 5534 *arg++ = NUL; 5535 eap->nextcmd = arg; 5536 break; 5537 } 5538 } 5539 arg = eap->arg; 5540 5541 if (eap->forceit && *arg == NUL) 5542 { 5543 EMSG(_("E478: Don't panic!")); 5544 return; 5545 } 5546 5547 if (eap->skip) /* not executing commands */ 5548 return; 5549 } 5550 else 5551 arg = (char_u *)""; 5552 5553 /* remove trailing blanks */ 5554 p = arg + STRLEN(arg) - 1; 5555 while (p > arg && vim_iswhite(*p) && p[-1] != '\\') 5556 *p-- = NUL; 5557 5558#ifdef FEAT_MULTI_LANG 5559 /* Check for a specified language */ 5560 lang = check_help_lang(arg); 5561#endif 5562 5563 /* When no argument given go to the index. */ 5564 if (*arg == NUL) 5565 arg = (char_u *)"help.txt"; 5566 5567 /* 5568 * Check if there is a match for the argument. 5569 */ 5570 n = find_help_tags(arg, &num_matches, &matches, 5571 eap != NULL && eap->forceit); 5572 5573 i = 0; 5574#ifdef FEAT_MULTI_LANG 5575 if (n != FAIL && lang != NULL) 5576 /* Find first item with the requested language. */ 5577 for (i = 0; i < num_matches; ++i) 5578 { 5579 len = (int)STRLEN(matches[i]); 5580 if (len > 3 && matches[i][len - 3] == '@' 5581 && STRICMP(matches[i] + len - 2, lang) == 0) 5582 break; 5583 } 5584#endif 5585 if (i >= num_matches || n == FAIL) 5586 { 5587#ifdef FEAT_MULTI_LANG 5588 if (lang != NULL) 5589 EMSG3(_("E661: Sorry, no '%s' help for %s"), lang, arg); 5590 else 5591#endif 5592 EMSG2(_("E149: Sorry, no help for %s"), arg); 5593 if (n != FAIL) 5594 FreeWild(num_matches, matches); 5595 return; 5596 } 5597 5598 /* The first match (in the requested language) is the best match. */ 5599 tag = vim_strsave(matches[i]); 5600 FreeWild(num_matches, matches); 5601 5602#ifdef FEAT_GUI 5603 need_mouse_correct = TRUE; 5604#endif 5605 5606 /* 5607 * Re-use an existing help window or open a new one. 5608 * Always open a new one for ":tab help". 5609 */ 5610 if (!curwin->w_buffer->b_help 5611#ifdef FEAT_WINDOWS 5612 || cmdmod.tab != 0 5613#endif 5614 ) 5615 { 5616#ifdef FEAT_WINDOWS 5617 if (cmdmod.tab != 0) 5618 wp = NULL; 5619 else 5620 for (wp = firstwin; wp != NULL; wp = wp->w_next) 5621 if (wp->w_buffer != NULL && wp->w_buffer->b_help) 5622 break; 5623 if (wp != NULL && wp->w_buffer->b_nwindows > 0) 5624 win_enter(wp, TRUE); 5625 else 5626#endif 5627 { 5628 /* 5629 * There is no help window yet. 5630 * Try to open the file specified by the "helpfile" option. 5631 */ 5632 if ((helpfd = mch_fopen((char *)p_hf, READBIN)) == NULL) 5633 { 5634 smsg((char_u *)_("Sorry, help file \"%s\" not found"), p_hf); 5635 goto erret; 5636 } 5637 fclose(helpfd); 5638 5639#ifdef FEAT_WINDOWS 5640 /* Split off help window; put it at far top if no position 5641 * specified, the current window is vertically split and 5642 * narrow. */ 5643 n = WSP_HELP; 5644# ifdef FEAT_VERTSPLIT 5645 if (cmdmod.split == 0 && curwin->w_width != Columns 5646 && curwin->w_width < 80) 5647 n |= WSP_TOP; 5648# endif 5649 if (win_split(0, n) == FAIL) 5650 goto erret; 5651#else 5652 /* use current window */ 5653 if (!can_abandon(curbuf, FALSE)) 5654 goto erret; 5655#endif 5656 5657#ifdef FEAT_WINDOWS 5658 if (curwin->w_height < p_hh) 5659 win_setheight((int)p_hh); 5660#endif 5661 5662 /* 5663 * Open help file (do_ecmd() will set b_help flag, readfile() will 5664 * set b_p_ro flag). 5665 * Set the alternate file to the previously edited file. 5666 */ 5667 alt_fnum = curbuf->b_fnum; 5668 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_LASTL, 5669 ECMD_HIDE + ECMD_SET_HELP, 5670#ifdef FEAT_WINDOWS 5671 NULL /* buffer is still open, don't store info */ 5672#else 5673 curwin 5674#endif 5675 ); 5676 if (!cmdmod.keepalt) 5677 curwin->w_alt_fnum = alt_fnum; 5678 empty_fnum = curbuf->b_fnum; 5679 } 5680 } 5681 5682 if (!p_im) 5683 restart_edit = 0; /* don't want insert mode in help file */ 5684 5685 if (tag != NULL) 5686 do_tag(tag, DT_HELP, 1, FALSE, TRUE); 5687 5688 /* Delete the empty buffer if we're not using it. Careful: autocommands 5689 * may have jumped to another window, check that the buffer is not in a 5690 * window. */ 5691 if (empty_fnum != 0 && curbuf->b_fnum != empty_fnum) 5692 { 5693 buf = buflist_findnr(empty_fnum); 5694 if (buf != NULL && buf->b_nwindows == 0) 5695 wipe_buffer(buf, TRUE); 5696 } 5697 5698 /* keep the previous alternate file */ 5699 if (alt_fnum != 0 && curwin->w_alt_fnum == empty_fnum && !cmdmod.keepalt) 5700 curwin->w_alt_fnum = alt_fnum; 5701 5702erret: 5703 vim_free(tag); 5704} 5705 5706 5707#if defined(FEAT_MULTI_LANG) || defined(PROTO) 5708/* 5709 * In an argument search for a language specifiers in the form "@xx". 5710 * Changes the "@" to NUL if found, and returns a pointer to "xx". 5711 * Returns NULL if not found. 5712 */ 5713 char_u * 5714check_help_lang(arg) 5715 char_u *arg; 5716{ 5717 int len = (int)STRLEN(arg); 5718 5719 if (len >= 3 && arg[len - 3] == '@' && ASCII_ISALPHA(arg[len - 2]) 5720 && ASCII_ISALPHA(arg[len - 1])) 5721 { 5722 arg[len - 3] = NUL; /* remove the '@' */ 5723 return arg + len - 2; 5724 } 5725 return NULL; 5726} 5727#endif 5728 5729/* 5730 * Return a heuristic indicating how well the given string matches. The 5731 * smaller the number, the better the match. This is the order of priorities, 5732 * from best match to worst match: 5733 * - Match with least alpha-numeric characters is better. 5734 * - Match with least total characters is better. 5735 * - Match towards the start is better. 5736 * - Match starting with "+" is worse (feature instead of command) 5737 * Assumption is made that the matched_string passed has already been found to 5738 * match some string for which help is requested. webb. 5739 */ 5740 int 5741help_heuristic(matched_string, offset, wrong_case) 5742 char_u *matched_string; 5743 int offset; /* offset for match */ 5744 int wrong_case; /* no matching case */ 5745{ 5746 int num_letters; 5747 char_u *p; 5748 5749 num_letters = 0; 5750 for (p = matched_string; *p; p++) 5751 if (ASCII_ISALNUM(*p)) 5752 num_letters++; 5753 5754 /* 5755 * Multiply the number of letters by 100 to give it a much bigger 5756 * weighting than the number of characters. 5757 * If there only is a match while ignoring case, add 5000. 5758 * If the match starts in the middle of a word, add 10000 to put it 5759 * somewhere in the last half. 5760 * If the match is more than 2 chars from the start, multiply by 200 to 5761 * put it after matches at the start. 5762 */ 5763 if (ASCII_ISALNUM(matched_string[offset]) && offset > 0 5764 && ASCII_ISALNUM(matched_string[offset - 1])) 5765 offset += 10000; 5766 else if (offset > 2) 5767 offset *= 200; 5768 if (wrong_case) 5769 offset += 5000; 5770 /* Features are less interesting than the subjects themselves, but "+" 5771 * alone is not a feature. */ 5772 if (matched_string[0] == '+' && matched_string[1] != NUL) 5773 offset += 100; 5774 return (int)(100 * num_letters + STRLEN(matched_string) + offset); 5775} 5776 5777/* 5778 * Compare functions for qsort() below, that checks the help heuristics number 5779 * that has been put after the tagname by find_tags(). 5780 */ 5781 static int 5782#ifdef __BORLANDC__ 5783_RTLENTRYF 5784#endif 5785help_compare(s1, s2) 5786 const void *s1; 5787 const void *s2; 5788{ 5789 char *p1; 5790 char *p2; 5791 5792 p1 = *(char **)s1 + strlen(*(char **)s1) + 1; 5793 p2 = *(char **)s2 + strlen(*(char **)s2) + 1; 5794 return strcmp(p1, p2); 5795} 5796 5797/* 5798 * Find all help tags matching "arg", sort them and return in matches[], with 5799 * the number of matches in num_matches. 5800 * The matches will be sorted with a "best" match algorithm. 5801 * When "keep_lang" is TRUE try keeping the language of the current buffer. 5802 */ 5803 int 5804find_help_tags(arg, num_matches, matches, keep_lang) 5805 char_u *arg; 5806 int *num_matches; 5807 char_u ***matches; 5808 int keep_lang; 5809{ 5810 char_u *s, *d; 5811 int i; 5812 static char *(mtable[]) = {"*", "g*", "[*", "]*", ":*", 5813 "/*", "/\\*", "\"*", "**", 5814 "/\\(\\)", 5815 "?", ":?", "?<CR>", "g?", "g?g?", "g??", "z?", 5816 "/\\?", "/\\z(\\)", "\\=", ":s\\=", 5817 "[count]", "[quotex]", "[range]", 5818 "[pattern]", "\\|", "\\%$"}; 5819 static char *(rtable[]) = {"star", "gstar", "[star", "]star", ":star", 5820 "/star", "/\\\\star", "quotestar", "starstar", 5821 "/\\\\(\\\\)", 5822 "?", ":?", "?<CR>", "g?", "g?g?", "g??", "z?", 5823 "/\\\\?", "/\\\\z(\\\\)", "\\\\=", ":s\\\\=", 5824 "\\[count]", "\\[quotex]", "\\[range]", 5825 "\\[pattern]", "\\\\bar", "/\\\\%\\$"}; 5826 int flags; 5827 5828 d = IObuff; /* assume IObuff is long enough! */ 5829 5830 /* 5831 * Recognize a few exceptions to the rule. Some strings that contain '*' 5832 * with "star". Otherwise '*' is recognized as a wildcard. 5833 */ 5834 for (i = (int)(sizeof(mtable) / sizeof(char *)); --i >= 0; ) 5835 if (STRCMP(arg, mtable[i]) == 0) 5836 { 5837 STRCPY(d, rtable[i]); 5838 break; 5839 } 5840 5841 if (i < 0) /* no match in table */ 5842 { 5843 /* Replace "\S" with "/\\S", etc. Otherwise every tag is matched. 5844 * Also replace "\%^" and "\%(", they match every tag too. 5845 * Also "\zs", "\z1", etc. 5846 * Also "\@<", "\@=", "\@<=", etc. 5847 * And also "\_$" and "\_^". */ 5848 if (arg[0] == '\\' 5849 && ((arg[1] != NUL && arg[2] == NUL) 5850 || (vim_strchr((char_u *)"%_z@", arg[1]) != NULL 5851 && arg[2] != NUL))) 5852 { 5853 STRCPY(d, "/\\\\"); 5854 STRCPY(d + 3, arg + 1); 5855 /* Check for "/\\_$", should be "/\\_\$" */ 5856 if (d[3] == '_' && d[4] == '$') 5857 STRCPY(d + 4, "\\$"); 5858 } 5859 else 5860 { 5861 /* replace "[:...:]" with "\[:...:]"; "[+...]" with "\[++...]" */ 5862 if (arg[0] == '[' && (arg[1] == ':' 5863 || (arg[1] == '+' && arg[2] == '+'))) 5864 *d++ = '\\'; 5865 5866 for (s = arg; *s; ++s) 5867 { 5868 /* 5869 * Replace "|" with "bar" and '"' with "quote" to match the name of 5870 * the tags for these commands. 5871 * Replace "*" with ".*" and "?" with "." to match command line 5872 * completion. 5873 * Insert a backslash before '~', '$' and '.' to avoid their 5874 * special meaning. 5875 */ 5876 if (d - IObuff > IOSIZE - 10) /* getting too long!? */ 5877 break; 5878 switch (*s) 5879 { 5880 case '|': STRCPY(d, "bar"); 5881 d += 3; 5882 continue; 5883 case '"': STRCPY(d, "quote"); 5884 d += 5; 5885 continue; 5886 case '*': *d++ = '.'; 5887 break; 5888 case '?': *d++ = '.'; 5889 continue; 5890 case '$': 5891 case '.': 5892 case '~': *d++ = '\\'; 5893 break; 5894 } 5895 5896 /* 5897 * Replace "^x" by "CTRL-X". Don't do this for "^_" to make 5898 * ":help i_^_CTRL-D" work. 5899 * Insert '-' before and after "CTRL-X" when applicable. 5900 */ 5901 if (*s < ' ' || (*s == '^' && s[1] && (ASCII_ISALPHA(s[1]) 5902 || vim_strchr((char_u *)"?@[\\]^", s[1]) != NULL))) 5903 { 5904 if (d > IObuff && d[-1] != '_') 5905 *d++ = '_'; /* prepend a '_' */ 5906 STRCPY(d, "CTRL-"); 5907 d += 5; 5908 if (*s < ' ') 5909 { 5910#ifdef EBCDIC 5911 *d++ = CtrlChar(*s); 5912#else 5913 *d++ = *s + '@'; 5914#endif 5915 if (d[-1] == '\\') 5916 *d++ = '\\'; /* double a backslash */ 5917 } 5918 else 5919 *d++ = *++s; 5920 if (s[1] != NUL && s[1] != '_') 5921 *d++ = '_'; /* append a '_' */ 5922 continue; 5923 } 5924 else if (*s == '^') /* "^" or "CTRL-^" or "^_" */ 5925 *d++ = '\\'; 5926 5927 /* 5928 * Insert a backslash before a backslash after a slash, for search 5929 * pattern tags: "/\|" --> "/\\|". 5930 */ 5931 else if (s[0] == '\\' && s[1] != '\\' 5932 && *arg == '/' && s == arg + 1) 5933 *d++ = '\\'; 5934 5935 /* "CTRL-\_" -> "CTRL-\\_" to avoid the special meaning of "\_" in 5936 * "CTRL-\_CTRL-N" */ 5937 if (STRNICMP(s, "CTRL-\\_", 7) == 0) 5938 { 5939 STRCPY(d, "CTRL-\\\\"); 5940 d += 7; 5941 s += 6; 5942 } 5943 5944 *d++ = *s; 5945 5946 /* 5947 * If tag starts with ', toss everything after a second '. Fixes 5948 * CTRL-] on 'option'. (would include the trailing '.'). 5949 */ 5950 if (*s == '\'' && s > arg && *arg == '\'') 5951 break; 5952 } 5953 *d = NUL; 5954 } 5955 } 5956 5957 *matches = (char_u **)""; 5958 *num_matches = 0; 5959 flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE; 5960 if (keep_lang) 5961 flags |= TAG_KEEP_LANG; 5962 if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL, NULL) == OK 5963 && *num_matches > 0) 5964 { 5965 /* Sort the matches found on the heuristic number that is after the 5966 * tag name. */ 5967 qsort((void *)*matches, (size_t)*num_matches, 5968 sizeof(char_u *), help_compare); 5969 /* Delete more than TAG_MANY to reduce the size of the listing. */ 5970 while (*num_matches > TAG_MANY) 5971 vim_free((*matches)[--*num_matches]); 5972 } 5973 return OK; 5974} 5975 5976/* 5977 * After reading a help file: May cleanup a help buffer when syntax 5978 * highlighting is not used. 5979 */ 5980 void 5981fix_help_buffer() 5982{ 5983 linenr_T lnum; 5984 char_u *line; 5985 int in_example = FALSE; 5986 int len; 5987 char_u *p; 5988 char_u *rt; 5989 int mustfree; 5990 5991 /* set filetype to "help". */ 5992 set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL); 5993 5994#ifdef FEAT_SYN_HL 5995 if (!syntax_present(curwin)) 5996#endif 5997 { 5998 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) 5999 { 6000 line = ml_get_buf(curbuf, lnum, FALSE); 6001 len = (int)STRLEN(line); 6002 if (in_example && len > 0 && !vim_iswhite(line[0])) 6003 { 6004 /* End of example: non-white or '<' in first column. */ 6005 if (line[0] == '<') 6006 { 6007 /* blank-out a '<' in the first column */ 6008 line = ml_get_buf(curbuf, lnum, TRUE); 6009 line[0] = ' '; 6010 } 6011 in_example = FALSE; 6012 } 6013 if (!in_example && len > 0) 6014 { 6015 if (line[len - 1] == '>' && (len == 1 || line[len - 2] == ' ')) 6016 { 6017 /* blank-out a '>' in the last column (start of example) */ 6018 line = ml_get_buf(curbuf, lnum, TRUE); 6019 line[len - 1] = ' '; 6020 in_example = TRUE; 6021 } 6022 else if (line[len - 1] == '~') 6023 { 6024 /* blank-out a '~' at the end of line (header marker) */ 6025 line = ml_get_buf(curbuf, lnum, TRUE); 6026 line[len - 1] = ' '; 6027 } 6028 } 6029 } 6030 } 6031 6032 /* 6033 * In the "help.txt" file, add the locally added help files. 6034 * This uses the very first line in the help file. 6035 */ 6036 if (fnamecmp(gettail(curbuf->b_fname), "help.txt") == 0) 6037 { 6038 for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; ++lnum) 6039 { 6040 line = ml_get_buf(curbuf, lnum, FALSE); 6041 if (strstr((char *)line, "*local-additions*") != NULL) 6042 { 6043 /* Go through all directories in 'runtimepath', skipping 6044 * $VIMRUNTIME. */ 6045 p = p_rtp; 6046 while (*p != NUL) 6047 { 6048 copy_option_part(&p, NameBuff, MAXPATHL, ","); 6049 mustfree = FALSE; 6050 rt = vim_getenv((char_u *)"VIMRUNTIME", &mustfree); 6051 if (fullpathcmp(rt, NameBuff, FALSE) != FPC_SAME) 6052 { 6053 int fcount; 6054 char_u **fnames; 6055 FILE *fd; 6056 char_u *s; 6057 int fi; 6058#ifdef FEAT_MBYTE 6059 vimconv_T vc; 6060 char_u *cp; 6061#endif 6062 6063 /* Find all "doc/ *.txt" files in this directory. */ 6064 add_pathsep(NameBuff); 6065 STRCAT(NameBuff, "doc/*.txt"); 6066 if (gen_expand_wildcards(1, &NameBuff, &fcount, 6067 &fnames, EW_FILE|EW_SILENT) == OK 6068 && fcount > 0) 6069 { 6070 for (fi = 0; fi < fcount; ++fi) 6071 { 6072 fd = mch_fopen((char *)fnames[fi], "r"); 6073 if (fd != NULL) 6074 { 6075 vim_fgets(IObuff, IOSIZE, fd); 6076 if (IObuff[0] == '*' 6077 && (s = vim_strchr(IObuff + 1, '*')) 6078 != NULL) 6079 { 6080#ifdef FEAT_MBYTE 6081 int this_utf = MAYBE; 6082#endif 6083 /* Change tag definition to a 6084 * reference and remove <CR>/<NL>. */ 6085 IObuff[0] = '|'; 6086 *s = '|'; 6087 while (*s != NUL) 6088 { 6089 if (*s == '\r' || *s == '\n') 6090 *s = NUL; 6091#ifdef FEAT_MBYTE 6092 /* The text is utf-8 when a byte 6093 * above 127 is found and no 6094 * illegal byte sequence is found. 6095 */ 6096 if (*s >= 0x80 && this_utf != FALSE) 6097 { 6098 int l; 6099 6100 this_utf = TRUE; 6101 l = utf_ptr2len(s); 6102 if (l == 1) 6103 this_utf = FALSE; 6104 s += l - 1; 6105 } 6106#endif 6107 ++s; 6108 } 6109#ifdef FEAT_MBYTE 6110 /* The help file is latin1 or utf-8; 6111 * conversion to the current 6112 * 'encoding' may be required. */ 6113 vc.vc_type = CONV_NONE; 6114 convert_setup(&vc, (char_u *)( 6115 this_utf == TRUE ? "utf-8" 6116 : "latin1"), p_enc); 6117 if (vc.vc_type == CONV_NONE) 6118 /* No conversion needed. */ 6119 cp = IObuff; 6120 else 6121 { 6122 /* Do the conversion. If it fails 6123 * use the unconverted text. */ 6124 cp = string_convert(&vc, IObuff, 6125 NULL); 6126 if (cp == NULL) 6127 cp = IObuff; 6128 } 6129 convert_setup(&vc, NULL, NULL); 6130 6131 ml_append(lnum, cp, (colnr_T)0, FALSE); 6132 if (cp != IObuff) 6133 vim_free(cp); 6134#else 6135 ml_append(lnum, IObuff, (colnr_T)0, 6136 FALSE); 6137#endif 6138 ++lnum; 6139 } 6140 fclose(fd); 6141 } 6142 } 6143 FreeWild(fcount, fnames); 6144 } 6145 } 6146 if (mustfree) 6147 vim_free(rt); 6148 } 6149 break; 6150 } 6151 } 6152 } 6153} 6154 6155/* 6156 * ":exusage" 6157 */ 6158 void 6159ex_exusage(eap) 6160 exarg_T *eap UNUSED; 6161{ 6162 do_cmdline_cmd((char_u *)"help ex-cmd-index"); 6163} 6164 6165/* 6166 * ":viusage" 6167 */ 6168 void 6169ex_viusage(eap) 6170 exarg_T *eap UNUSED; 6171{ 6172 do_cmdline_cmd((char_u *)"help normal-index"); 6173} 6174 6175#if defined(FEAT_EX_EXTRA) || defined(PROTO) 6176static void helptags_one __ARGS((char_u *dir, char_u *ext, char_u *lang, int add_help_tags)); 6177 6178/* 6179 * ":helptags" 6180 */ 6181 void 6182ex_helptags(eap) 6183 exarg_T *eap; 6184{ 6185 garray_T ga; 6186 int i, j; 6187 int len; 6188#ifdef FEAT_MULTI_LANG 6189 char_u lang[2]; 6190#endif 6191 expand_T xpc; 6192 char_u *dirname; 6193 char_u ext[5]; 6194 char_u fname[8]; 6195 int filecount; 6196 char_u **files; 6197 int add_help_tags = FALSE; 6198 6199 /* Check for ":helptags ++t {dir}". */ 6200 if (STRNCMP(eap->arg, "++t", 3) == 0 && vim_iswhite(eap->arg[3])) 6201 { 6202 add_help_tags = TRUE; 6203 eap->arg = skipwhite(eap->arg + 3); 6204 } 6205 6206 ExpandInit(&xpc); 6207 xpc.xp_context = EXPAND_DIRECTORIES; 6208 dirname = ExpandOne(&xpc, eap->arg, NULL, 6209 WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); 6210 if (dirname == NULL || !mch_isdir(dirname)) 6211 { 6212 EMSG2(_("E150: Not a directory: %s"), eap->arg); 6213 return; 6214 } 6215 6216#ifdef FEAT_MULTI_LANG 6217 /* Get a list of all files in the directory. */ 6218 STRCPY(NameBuff, dirname); 6219 add_pathsep(NameBuff); 6220 STRCAT(NameBuff, "*"); 6221 if (gen_expand_wildcards(1, &NameBuff, &filecount, &files, 6222 EW_FILE|EW_SILENT) == FAIL 6223 || filecount == 0) 6224 { 6225 EMSG2("E151: No match: %s", NameBuff); 6226 vim_free(dirname); 6227 return; 6228 } 6229 6230 /* Go over all files in the directory to find out what languages are 6231 * present. */ 6232 ga_init2(&ga, 1, 10); 6233 for (i = 0; i < filecount; ++i) 6234 { 6235 len = (int)STRLEN(files[i]); 6236 if (len > 4) 6237 { 6238 if (STRICMP(files[i] + len - 4, ".txt") == 0) 6239 { 6240 /* ".txt" -> language "en" */ 6241 lang[0] = 'e'; 6242 lang[1] = 'n'; 6243 } 6244 else if (files[i][len - 4] == '.' 6245 && ASCII_ISALPHA(files[i][len - 3]) 6246 && ASCII_ISALPHA(files[i][len - 2]) 6247 && TOLOWER_ASC(files[i][len - 1]) == 'x') 6248 { 6249 /* ".abx" -> language "ab" */ 6250 lang[0] = TOLOWER_ASC(files[i][len - 3]); 6251 lang[1] = TOLOWER_ASC(files[i][len - 2]); 6252 } 6253 else 6254 continue; 6255 6256 /* Did we find this language already? */ 6257 for (j = 0; j < ga.ga_len; j += 2) 6258 if (STRNCMP(lang, ((char_u *)ga.ga_data) + j, 2) == 0) 6259 break; 6260 if (j == ga.ga_len) 6261 { 6262 /* New language, add it. */ 6263 if (ga_grow(&ga, 2) == FAIL) 6264 break; 6265 ((char_u *)ga.ga_data)[ga.ga_len++] = lang[0]; 6266 ((char_u *)ga.ga_data)[ga.ga_len++] = lang[1]; 6267 } 6268 } 6269 } 6270 6271 /* 6272 * Loop over the found languages to generate a tags file for each one. 6273 */ 6274 for (j = 0; j < ga.ga_len; j += 2) 6275 { 6276 STRCPY(fname, "tags-xx"); 6277 fname[5] = ((char_u *)ga.ga_data)[j]; 6278 fname[6] = ((char_u *)ga.ga_data)[j + 1]; 6279 if (fname[5] == 'e' && fname[6] == 'n') 6280 { 6281 /* English is an exception: use ".txt" and "tags". */ 6282 fname[4] = NUL; 6283 STRCPY(ext, ".txt"); 6284 } 6285 else 6286 { 6287 /* Language "ab" uses ".abx" and "tags-ab". */ 6288 STRCPY(ext, ".xxx"); 6289 ext[1] = fname[5]; 6290 ext[2] = fname[6]; 6291 } 6292 helptags_one(dirname, ext, fname, add_help_tags); 6293 } 6294 6295 ga_clear(&ga); 6296 FreeWild(filecount, files); 6297 6298#else 6299 /* No language support, just use "*.txt" and "tags". */ 6300 helptags_one(dirname, (char_u *)".txt", (char_u *)"tags", add_help_tags); 6301#endif 6302 vim_free(dirname); 6303} 6304 6305 static void 6306helptags_one(dir, ext, tagfname, add_help_tags) 6307 char_u *dir; /* doc directory */ 6308 char_u *ext; /* suffix, ".txt", ".itx", ".frx", etc. */ 6309 char_u *tagfname; /* "tags" for English, "tags-fr" for French. */ 6310 int add_help_tags; /* add "help-tags" tag */ 6311{ 6312 FILE *fd_tags; 6313 FILE *fd; 6314 garray_T ga; 6315 int filecount; 6316 char_u **files; 6317 char_u *p1, *p2; 6318 int fi; 6319 char_u *s; 6320 int i; 6321 char_u *fname; 6322# ifdef FEAT_MBYTE 6323 int utf8 = MAYBE; 6324 int this_utf8; 6325 int firstline; 6326 int mix = FALSE; /* detected mixed encodings */ 6327# endif 6328 6329 /* 6330 * Find all *.txt files. 6331 */ 6332 STRCPY(NameBuff, dir); 6333 add_pathsep(NameBuff); 6334 STRCAT(NameBuff, "*"); 6335 STRCAT(NameBuff, ext); 6336 if (gen_expand_wildcards(1, &NameBuff, &filecount, &files, 6337 EW_FILE|EW_SILENT) == FAIL 6338 || filecount == 0) 6339 { 6340 if (!got_int) 6341 EMSG2("E151: No match: %s", NameBuff); 6342 return; 6343 } 6344 6345 /* 6346 * Open the tags file for writing. 6347 * Do this before scanning through all the files. 6348 */ 6349 STRCPY(NameBuff, dir); 6350 add_pathsep(NameBuff); 6351 STRCAT(NameBuff, tagfname); 6352 fd_tags = mch_fopen((char *)NameBuff, "w"); 6353 if (fd_tags == NULL) 6354 { 6355 EMSG2(_("E152: Cannot open %s for writing"), NameBuff); 6356 FreeWild(filecount, files); 6357 return; 6358 } 6359 6360 /* 6361 * If using the "++t" argument or generating tags for "$VIMRUNTIME/doc" 6362 * add the "help-tags" tag. 6363 */ 6364 ga_init2(&ga, (int)sizeof(char_u *), 100); 6365 if (add_help_tags || fullpathcmp((char_u *)"$VIMRUNTIME/doc", 6366 dir, FALSE) == FPC_SAME) 6367 { 6368 if (ga_grow(&ga, 1) == FAIL) 6369 got_int = TRUE; 6370 else 6371 { 6372 s = alloc(18 + (unsigned)STRLEN(tagfname)); 6373 if (s == NULL) 6374 got_int = TRUE; 6375 else 6376 { 6377 sprintf((char *)s, "help-tags\t%s\t1\n", tagfname); 6378 ((char_u **)ga.ga_data)[ga.ga_len] = s; 6379 ++ga.ga_len; 6380 } 6381 } 6382 } 6383 6384 /* 6385 * Go over all the files and extract the tags. 6386 */ 6387 for (fi = 0; fi < filecount && !got_int; ++fi) 6388 { 6389 fd = mch_fopen((char *)files[fi], "r"); 6390 if (fd == NULL) 6391 { 6392 EMSG2(_("E153: Unable to open %s for reading"), files[fi]); 6393 continue; 6394 } 6395 fname = gettail(files[fi]); 6396 6397# ifdef FEAT_MBYTE 6398 firstline = TRUE; 6399# endif 6400 while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) 6401 { 6402# ifdef FEAT_MBYTE 6403 if (firstline) 6404 { 6405 /* Detect utf-8 file by a non-ASCII char in the first line. */ 6406 this_utf8 = MAYBE; 6407 for (s = IObuff; *s != NUL; ++s) 6408 if (*s >= 0x80) 6409 { 6410 int l; 6411 6412 this_utf8 = TRUE; 6413 l = utf_ptr2len(s); 6414 if (l == 1) 6415 { 6416 /* Illegal UTF-8 byte sequence. */ 6417 this_utf8 = FALSE; 6418 break; 6419 } 6420 s += l - 1; 6421 } 6422 if (this_utf8 == MAYBE) /* only ASCII characters found */ 6423 this_utf8 = FALSE; 6424 if (utf8 == MAYBE) /* first file */ 6425 utf8 = this_utf8; 6426 else if (utf8 != this_utf8) 6427 { 6428 EMSG2(_("E670: Mix of help file encodings within a language: %s"), files[fi]); 6429 mix = !got_int; 6430 got_int = TRUE; 6431 } 6432 firstline = FALSE; 6433 } 6434# endif 6435 p1 = vim_strchr(IObuff, '*'); /* find first '*' */ 6436 while (p1 != NULL) 6437 { 6438 p2 = vim_strchr(p1 + 1, '*'); /* find second '*' */ 6439 if (p2 != NULL && p2 > p1 + 1) /* skip "*" and "**" */ 6440 { 6441 for (s = p1 + 1; s < p2; ++s) 6442 if (*s == ' ' || *s == '\t' || *s == '|') 6443 break; 6444 6445 /* 6446 * Only accept a *tag* when it consists of valid 6447 * characters, there is white space before it and is 6448 * followed by a white character or end-of-line. 6449 */ 6450 if (s == p2 6451 && (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t') 6452 && (vim_strchr((char_u *)" \t\n\r", s[1]) != NULL 6453 || s[1] == '\0')) 6454 { 6455 *p2 = '\0'; 6456 ++p1; 6457 if (ga_grow(&ga, 1) == FAIL) 6458 { 6459 got_int = TRUE; 6460 break; 6461 } 6462 s = alloc((unsigned)(p2 - p1 + STRLEN(fname) + 2)); 6463 if (s == NULL) 6464 { 6465 got_int = TRUE; 6466 break; 6467 } 6468 ((char_u **)ga.ga_data)[ga.ga_len] = s; 6469 ++ga.ga_len; 6470 sprintf((char *)s, "%s\t%s", p1, fname); 6471 6472 /* find next '*' */ 6473 p2 = vim_strchr(p2 + 1, '*'); 6474 } 6475 } 6476 p1 = p2; 6477 } 6478 line_breakcheck(); 6479 } 6480 6481 fclose(fd); 6482 } 6483 6484 FreeWild(filecount, files); 6485 6486 if (!got_int) 6487 { 6488 /* 6489 * Sort the tags. 6490 */ 6491 sort_strings((char_u **)ga.ga_data, ga.ga_len); 6492 6493 /* 6494 * Check for duplicates. 6495 */ 6496 for (i = 1; i < ga.ga_len; ++i) 6497 { 6498 p1 = ((char_u **)ga.ga_data)[i - 1]; 6499 p2 = ((char_u **)ga.ga_data)[i]; 6500 while (*p1 == *p2) 6501 { 6502 if (*p2 == '\t') 6503 { 6504 *p2 = NUL; 6505 vim_snprintf((char *)NameBuff, MAXPATHL, 6506 _("E154: Duplicate tag \"%s\" in file %s/%s"), 6507 ((char_u **)ga.ga_data)[i], dir, p2 + 1); 6508 EMSG(NameBuff); 6509 *p2 = '\t'; 6510 break; 6511 } 6512 ++p1; 6513 ++p2; 6514 } 6515 } 6516 6517# ifdef FEAT_MBYTE 6518 if (utf8 == TRUE) 6519 fprintf(fd_tags, "!_TAG_FILE_ENCODING\tutf-8\t//\n"); 6520# endif 6521 6522 /* 6523 * Write the tags into the file. 6524 */ 6525 for (i = 0; i < ga.ga_len; ++i) 6526 { 6527 s = ((char_u **)ga.ga_data)[i]; 6528 if (STRNCMP(s, "help-tags\t", 10) == 0) 6529 /* help-tags entry was added in formatted form */ 6530 fputs((char *)s, fd_tags); 6531 else 6532 { 6533 fprintf(fd_tags, "%s\t/*", s); 6534 for (p1 = s; *p1 != '\t'; ++p1) 6535 { 6536 /* insert backslash before '\\' and '/' */ 6537 if (*p1 == '\\' || *p1 == '/') 6538 putc('\\', fd_tags); 6539 putc(*p1, fd_tags); 6540 } 6541 fprintf(fd_tags, "*\n"); 6542 } 6543 } 6544 } 6545#ifdef FEAT_MBYTE 6546 if (mix) 6547 got_int = FALSE; /* continue with other languages */ 6548#endif 6549 6550 for (i = 0; i < ga.ga_len; ++i) 6551 vim_free(((char_u **)ga.ga_data)[i]); 6552 ga_clear(&ga); 6553 fclose(fd_tags); /* there is no check for an error... */ 6554} 6555#endif 6556 6557#if defined(FEAT_SIGNS) || defined(PROTO) 6558 6559/* 6560 * Struct to hold the sign properties. 6561 */ 6562typedef struct sign sign_T; 6563 6564struct sign 6565{ 6566 sign_T *sn_next; /* next sign in list */ 6567 int sn_typenr; /* type number of sign (negative if not equal 6568 to name) */ 6569 char_u *sn_name; /* name of sign */ 6570 char_u *sn_icon; /* name of pixmap */ 6571#ifdef FEAT_SIGN_ICONS 6572 void *sn_image; /* icon image */ 6573#endif 6574 char_u *sn_text; /* text used instead of pixmap */ 6575 int sn_line_hl; /* highlight ID for line */ 6576 int sn_text_hl; /* highlight ID for text */ 6577}; 6578 6579static sign_T *first_sign = NULL; 6580static int last_sign_typenr = MAX_TYPENR; /* is decremented */ 6581 6582static int sign_cmd_idx __ARGS((char_u *begin_cmd, char_u *end_cmd)); 6583static void sign_list_defined __ARGS((sign_T *sp)); 6584static void sign_undefine __ARGS((sign_T *sp, sign_T *sp_prev)); 6585 6586static char *cmds[] = { 6587 "define", 6588#define SIGNCMD_DEFINE 0 6589 "undefine", 6590#define SIGNCMD_UNDEFINE 1 6591 "list", 6592#define SIGNCMD_LIST 2 6593 "place", 6594#define SIGNCMD_PLACE 3 6595 "unplace", 6596#define SIGNCMD_UNPLACE 4 6597 "jump", 6598#define SIGNCMD_JUMP 5 6599 NULL 6600#define SIGNCMD_LAST 6 6601}; 6602 6603/* 6604 * Find index of a ":sign" subcmd from its name. 6605 * "*end_cmd" must be writable. 6606 */ 6607 static int 6608sign_cmd_idx(begin_cmd, end_cmd) 6609 char_u *begin_cmd; /* begin of sign subcmd */ 6610 char_u *end_cmd; /* just after sign subcmd */ 6611{ 6612 int idx; 6613 char save = *end_cmd; 6614 6615 *end_cmd = NUL; 6616 for (idx = 0; ; ++idx) 6617 if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0) 6618 break; 6619 *end_cmd = save; 6620 return idx; 6621} 6622 6623/* 6624 * ":sign" command 6625 */ 6626 void 6627ex_sign(eap) 6628 exarg_T *eap; 6629{ 6630 char_u *arg = eap->arg; 6631 char_u *p; 6632 int idx; 6633 sign_T *sp; 6634 sign_T *sp_prev; 6635 buf_T *buf; 6636 6637 /* Parse the subcommand. */ 6638 p = skiptowhite(arg); 6639 idx = sign_cmd_idx(arg, p); 6640 if (idx == SIGNCMD_LAST) 6641 { 6642 EMSG2(_("E160: Unknown sign command: %s"), arg); 6643 return; 6644 } 6645 arg = skipwhite(p); 6646 6647 if (idx <= SIGNCMD_LIST) 6648 { 6649 /* 6650 * Define, undefine or list signs. 6651 */ 6652 if (idx == SIGNCMD_LIST && *arg == NUL) 6653 { 6654 /* ":sign list": list all defined signs */ 6655 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 6656 sign_list_defined(sp); 6657 } 6658 else if (*arg == NUL) 6659 EMSG(_("E156: Missing sign name")); 6660 else 6661 { 6662 p = skiptowhite(arg); 6663 if (*p != NUL) 6664 *p++ = NUL; 6665 sp_prev = NULL; 6666 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 6667 { 6668 if (STRCMP(sp->sn_name, arg) == 0) 6669 break; 6670 sp_prev = sp; 6671 } 6672 if (idx == SIGNCMD_DEFINE) 6673 { 6674 /* ":sign define {name} ...": define a sign */ 6675 if (sp == NULL) 6676 { 6677 /* Allocate a new sign. */ 6678 sp = (sign_T *)alloc_clear((unsigned)sizeof(sign_T)); 6679 if (sp == NULL) 6680 return; 6681 if (sp_prev == NULL) 6682 first_sign = sp; 6683 else 6684 sp_prev->sn_next = sp; 6685 sp->sn_name = vim_strnsave(arg, (int)(p - arg)); 6686 6687 /* If the name is a number use that for the typenr, 6688 * otherwise use a negative number. */ 6689 if (VIM_ISDIGIT(*arg)) 6690 sp->sn_typenr = atoi((char *)arg); 6691 else 6692 { 6693 sign_T *lp; 6694 int start = last_sign_typenr; 6695 6696 for (lp = first_sign; lp != NULL; lp = lp->sn_next) 6697 { 6698 if (lp->sn_typenr == last_sign_typenr) 6699 { 6700 --last_sign_typenr; 6701 if (last_sign_typenr == 0) 6702 last_sign_typenr = MAX_TYPENR; 6703 if (last_sign_typenr == start) 6704 { 6705 EMSG(_("E612: Too many signs defined")); 6706 return; 6707 } 6708 lp = first_sign; 6709 continue; 6710 } 6711 } 6712 6713 sp->sn_typenr = last_sign_typenr--; 6714 if (last_sign_typenr == 0) 6715 last_sign_typenr = MAX_TYPENR; /* wrap around */ 6716 } 6717 } 6718 6719 /* set values for a defined sign. */ 6720 for (;;) 6721 { 6722 arg = skipwhite(p); 6723 if (*arg == NUL) 6724 break; 6725 p = skiptowhite_esc(arg); 6726 if (STRNCMP(arg, "icon=", 5) == 0) 6727 { 6728 arg += 5; 6729 vim_free(sp->sn_icon); 6730 sp->sn_icon = vim_strnsave(arg, (int)(p - arg)); 6731 backslash_halve(sp->sn_icon); 6732#ifdef FEAT_SIGN_ICONS 6733 if (gui.in_use) 6734 { 6735 out_flush(); 6736 if (sp->sn_image != NULL) 6737 gui_mch_destroy_sign(sp->sn_image); 6738 sp->sn_image = gui_mch_register_sign(sp->sn_icon); 6739 } 6740#endif 6741 } 6742 else if (STRNCMP(arg, "text=", 5) == 0) 6743 { 6744 char_u *s; 6745 int cells; 6746 int len; 6747 6748 arg += 5; 6749#ifdef FEAT_MBYTE 6750 /* Count cells and check for non-printable chars */ 6751 if (has_mbyte) 6752 { 6753 cells = 0; 6754 for (s = arg; s < p; s += (*mb_ptr2len)(s)) 6755 { 6756 if (!vim_isprintc((*mb_ptr2char)(s))) 6757 break; 6758 cells += (*mb_ptr2cells)(s); 6759 } 6760 } 6761 else 6762#endif 6763 { 6764 for (s = arg; s < p; ++s) 6765 if (!vim_isprintc(*s)) 6766 break; 6767 cells = (int)(s - arg); 6768 } 6769 /* Currently must be one or two display cells */ 6770 if (s != p || cells < 1 || cells > 2) 6771 { 6772 *p = NUL; 6773 EMSG2(_("E239: Invalid sign text: %s"), arg); 6774 return; 6775 } 6776 6777 vim_free(sp->sn_text); 6778 /* Allocate one byte more if we need to pad up 6779 * with a space. */ 6780 len = (int)(p - arg + ((cells == 1) ? 1 : 0)); 6781 sp->sn_text = vim_strnsave(arg, len); 6782 6783 if (sp->sn_text != NULL && cells == 1) 6784 STRCPY(sp->sn_text + len - 1, " "); 6785 } 6786 else if (STRNCMP(arg, "linehl=", 7) == 0) 6787 { 6788 arg += 7; 6789 sp->sn_line_hl = syn_check_group(arg, (int)(p - arg)); 6790 } 6791 else if (STRNCMP(arg, "texthl=", 7) == 0) 6792 { 6793 arg += 7; 6794 sp->sn_text_hl = syn_check_group(arg, (int)(p - arg)); 6795 } 6796 else 6797 { 6798 EMSG2(_(e_invarg2), arg); 6799 return; 6800 } 6801 } 6802 } 6803 else if (sp == NULL) 6804 EMSG2(_("E155: Unknown sign: %s"), arg); 6805 else if (idx == SIGNCMD_LIST) 6806 /* ":sign list {name}" */ 6807 sign_list_defined(sp); 6808 else 6809 /* ":sign undefine {name}" */ 6810 sign_undefine(sp, sp_prev); 6811 } 6812 } 6813 else 6814 { 6815 int id = -1; 6816 linenr_T lnum = -1; 6817 char_u *sign_name = NULL; 6818 char_u *arg1; 6819 6820 if (*arg == NUL) 6821 { 6822 if (idx == SIGNCMD_PLACE) 6823 { 6824 /* ":sign place": list placed signs in all buffers */ 6825 sign_list_placed(NULL); 6826 } 6827 else if (idx == SIGNCMD_UNPLACE) 6828 { 6829 /* ":sign unplace": remove placed sign at cursor */ 6830 id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum); 6831 if (id > 0) 6832 { 6833 buf_delsign(curwin->w_buffer, id); 6834 update_debug_sign(curwin->w_buffer, curwin->w_cursor.lnum); 6835 } 6836 else 6837 EMSG(_("E159: Missing sign number")); 6838 } 6839 else 6840 EMSG(_(e_argreq)); 6841 return; 6842 } 6843 6844 if (idx == SIGNCMD_UNPLACE && arg[0] == '*' && arg[1] == NUL) 6845 { 6846 /* ":sign unplace *": remove all placed signs */ 6847 buf_delete_all_signs(); 6848 return; 6849 } 6850 6851 /* first arg could be placed sign id */ 6852 arg1 = arg; 6853 if (VIM_ISDIGIT(*arg)) 6854 { 6855 id = getdigits(&arg); 6856 if (!vim_iswhite(*arg) && *arg != NUL) 6857 { 6858 id = -1; 6859 arg = arg1; 6860 } 6861 else 6862 { 6863 arg = skipwhite(arg); 6864 if (idx == SIGNCMD_UNPLACE && *arg == NUL) 6865 { 6866 /* ":sign unplace {id}": remove placed sign by number */ 6867 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 6868 if ((lnum = buf_delsign(buf, id)) != 0) 6869 update_debug_sign(buf, lnum); 6870 return; 6871 } 6872 } 6873 } 6874 6875 /* 6876 * Check for line={lnum} name={name} and file={fname} or buffer={nr}. 6877 * Leave "arg" pointing to {fname}. 6878 */ 6879 for (;;) 6880 { 6881 if (STRNCMP(arg, "line=", 5) == 0) 6882 { 6883 arg += 5; 6884 lnum = atoi((char *)arg); 6885 arg = skiptowhite(arg); 6886 } 6887 else if (STRNCMP(arg, "name=", 5) == 0) 6888 { 6889 arg += 5; 6890 sign_name = arg; 6891 arg = skiptowhite(arg); 6892 if (*arg != NUL) 6893 *arg++ = NUL; 6894 } 6895 else if (STRNCMP(arg, "file=", 5) == 0) 6896 { 6897 arg += 5; 6898 buf = buflist_findname(arg); 6899 break; 6900 } 6901 else if (STRNCMP(arg, "buffer=", 7) == 0) 6902 { 6903 arg += 7; 6904 buf = buflist_findnr((int)getdigits(&arg)); 6905 if (*skipwhite(arg) != NUL) 6906 EMSG(_(e_trailing)); 6907 break; 6908 } 6909 else 6910 { 6911 EMSG(_(e_invarg)); 6912 return; 6913 } 6914 arg = skipwhite(arg); 6915 } 6916 6917 if (buf == NULL) 6918 { 6919 EMSG2(_("E158: Invalid buffer name: %s"), arg); 6920 } 6921 else if (id <= 0) 6922 { 6923 if (lnum >= 0 || sign_name != NULL) 6924 EMSG(_(e_invarg)); 6925 else 6926 /* ":sign place file={fname}": list placed signs in one file */ 6927 sign_list_placed(buf); 6928 } 6929 else if (idx == SIGNCMD_JUMP) 6930 { 6931 /* ":sign jump {id} file={fname}" */ 6932 if (lnum >= 0 || sign_name != NULL) 6933 EMSG(_(e_invarg)); 6934 else if ((lnum = buf_findsign(buf, id)) > 0) 6935 { /* goto a sign ... */ 6936 if (buf_jump_open_win(buf) != NULL) 6937 { /* ... in a current window */ 6938 curwin->w_cursor.lnum = lnum; 6939 check_cursor_lnum(); 6940 beginline(BL_WHITE); 6941 } 6942 else 6943 { /* ... not currently in a window */ 6944 char_u *cmd; 6945 6946 cmd = alloc((unsigned)STRLEN(buf->b_fname) + 25); 6947 if (cmd == NULL) 6948 return; 6949 sprintf((char *)cmd, "e +%ld %s", (long)lnum, buf->b_fname); 6950 do_cmdline_cmd(cmd); 6951 vim_free(cmd); 6952 } 6953#ifdef FEAT_FOLDING 6954 foldOpenCursor(); 6955#endif 6956 } 6957 else 6958 EMSGN(_("E157: Invalid sign ID: %ld"), id); 6959 } 6960 else if (idx == SIGNCMD_UNPLACE) 6961 { 6962 /* ":sign unplace {id} file={fname}" */ 6963 if (lnum >= 0 || sign_name != NULL) 6964 EMSG(_(e_invarg)); 6965 else 6966 { 6967 lnum = buf_delsign(buf, id); 6968 update_debug_sign(buf, lnum); 6969 } 6970 } 6971 /* idx == SIGNCMD_PLACE */ 6972 else if (sign_name != NULL) 6973 { 6974 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 6975 if (STRCMP(sp->sn_name, sign_name) == 0) 6976 break; 6977 if (sp == NULL) 6978 { 6979 EMSG2(_("E155: Unknown sign: %s"), sign_name); 6980 return; 6981 } 6982 if (lnum > 0) 6983 /* ":sign place {id} line={lnum} name={name} file={fname}": 6984 * place a sign */ 6985 buf_addsign(buf, id, lnum, sp->sn_typenr); 6986 else 6987 /* ":sign place {id} file={fname}": change sign type */ 6988 lnum = buf_change_sign_type(buf, id, sp->sn_typenr); 6989 update_debug_sign(buf, lnum); 6990 } 6991 else 6992 EMSG(_(e_invarg)); 6993 } 6994} 6995 6996#if defined(FEAT_SIGN_ICONS) || defined(PROTO) 6997/* 6998 * Allocate the icons. Called when the GUI has started. Allows defining 6999 * signs before it starts. 7000 */ 7001 void 7002sign_gui_started() 7003{ 7004 sign_T *sp; 7005 7006 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 7007 if (sp->sn_icon != NULL) 7008 sp->sn_image = gui_mch_register_sign(sp->sn_icon); 7009} 7010#endif 7011 7012/* 7013 * List one sign. 7014 */ 7015 static void 7016sign_list_defined(sp) 7017 sign_T *sp; 7018{ 7019 char_u *p; 7020 7021 smsg((char_u *)"sign %s", sp->sn_name); 7022 if (sp->sn_icon != NULL) 7023 { 7024 MSG_PUTS(" icon="); 7025 msg_outtrans(sp->sn_icon); 7026#ifdef FEAT_SIGN_ICONS 7027 if (sp->sn_image == NULL) 7028 MSG_PUTS(_(" (NOT FOUND)")); 7029#else 7030 MSG_PUTS(_(" (not supported)")); 7031#endif 7032 } 7033 if (sp->sn_text != NULL) 7034 { 7035 MSG_PUTS(" text="); 7036 msg_outtrans(sp->sn_text); 7037 } 7038 if (sp->sn_line_hl > 0) 7039 { 7040 MSG_PUTS(" linehl="); 7041 p = get_highlight_name(NULL, sp->sn_line_hl - 1); 7042 if (p == NULL) 7043 MSG_PUTS("NONE"); 7044 else 7045 msg_puts(p); 7046 } 7047 if (sp->sn_text_hl > 0) 7048 { 7049 MSG_PUTS(" texthl="); 7050 p = get_highlight_name(NULL, sp->sn_text_hl - 1); 7051 if (p == NULL) 7052 MSG_PUTS("NONE"); 7053 else 7054 msg_puts(p); 7055 } 7056} 7057 7058/* 7059 * Undefine a sign and free its memory. 7060 */ 7061 static void 7062sign_undefine(sp, sp_prev) 7063 sign_T *sp; 7064 sign_T *sp_prev; 7065{ 7066 vim_free(sp->sn_name); 7067 vim_free(sp->sn_icon); 7068#ifdef FEAT_SIGN_ICONS 7069 if (sp->sn_image != NULL) 7070 { 7071 out_flush(); 7072 gui_mch_destroy_sign(sp->sn_image); 7073 } 7074#endif 7075 vim_free(sp->sn_text); 7076 if (sp_prev == NULL) 7077 first_sign = sp->sn_next; 7078 else 7079 sp_prev->sn_next = sp->sn_next; 7080 vim_free(sp); 7081} 7082 7083/* 7084 * Get highlighting attribute for sign "typenr". 7085 * If "line" is TRUE: line highl, if FALSE: text highl. 7086 */ 7087 int 7088sign_get_attr(typenr, line) 7089 int typenr; 7090 int line; 7091{ 7092 sign_T *sp; 7093 7094 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 7095 if (sp->sn_typenr == typenr) 7096 { 7097 if (line) 7098 { 7099 if (sp->sn_line_hl > 0) 7100 return syn_id2attr(sp->sn_line_hl); 7101 } 7102 else 7103 { 7104 if (sp->sn_text_hl > 0) 7105 return syn_id2attr(sp->sn_text_hl); 7106 } 7107 break; 7108 } 7109 return 0; 7110} 7111 7112/* 7113 * Get text mark for sign "typenr". 7114 * Returns NULL if there isn't one. 7115 */ 7116 char_u * 7117sign_get_text(typenr) 7118 int typenr; 7119{ 7120 sign_T *sp; 7121 7122 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 7123 if (sp->sn_typenr == typenr) 7124 return sp->sn_text; 7125 return NULL; 7126} 7127 7128#if defined(FEAT_SIGN_ICONS) || defined(PROTO) 7129 void * 7130sign_get_image(typenr) 7131 int typenr; /* the attribute which may have a sign */ 7132{ 7133 sign_T *sp; 7134 7135 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 7136 if (sp->sn_typenr == typenr) 7137 return sp->sn_image; 7138 return NULL; 7139} 7140#endif 7141 7142/* 7143 * Get the name of a sign by its typenr. 7144 */ 7145 char_u * 7146sign_typenr2name(typenr) 7147 int typenr; 7148{ 7149 sign_T *sp; 7150 7151 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 7152 if (sp->sn_typenr == typenr) 7153 return sp->sn_name; 7154 return (char_u *)_("[Deleted]"); 7155} 7156 7157#if defined(EXITFREE) || defined(PROTO) 7158/* 7159 * Undefine/free all signs. 7160 */ 7161 void 7162free_signs() 7163{ 7164 while (first_sign != NULL) 7165 sign_undefine(first_sign, NULL); 7166} 7167#endif 7168 7169#if defined(FEAT_CMDL_COMPL) || defined(PROTO) 7170static enum 7171{ 7172 EXP_SUBCMD, /* expand :sign sub-commands */ 7173 EXP_DEFINE, /* expand :sign define {name} args */ 7174 EXP_PLACE, /* expand :sign place {id} args */ 7175 EXP_UNPLACE, /* expand :sign unplace" */ 7176 EXP_SIGN_NAMES /* expand with name of placed signs */ 7177} expand_what; 7178 7179/* 7180 * Function given to ExpandGeneric() to obtain the sign command 7181 * expansion. 7182 */ 7183 char_u * 7184get_sign_name(xp, idx) 7185 expand_T *xp UNUSED; 7186 int idx; 7187{ 7188 sign_T *sp; 7189 int current_idx; 7190 7191 switch (expand_what) 7192 { 7193 case EXP_SUBCMD: 7194 return (char_u *)cmds[idx]; 7195 case EXP_DEFINE: 7196 { 7197 char *define_arg[] = 7198 { 7199 "icon=", "linehl=", "text=", "texthl=", NULL 7200 }; 7201 return (char_u *)define_arg[idx]; 7202 } 7203 case EXP_PLACE: 7204 { 7205 char *place_arg[] = 7206 { 7207 "line=", "name=", "file=", "buffer=", NULL 7208 }; 7209 return (char_u *)place_arg[idx]; 7210 } 7211 case EXP_UNPLACE: 7212 { 7213 char *unplace_arg[] = { "file=", "buffer=", NULL }; 7214 return (char_u *)unplace_arg[idx]; 7215 } 7216 case EXP_SIGN_NAMES: 7217 /* Complete with name of signs already defined */ 7218 current_idx = 0; 7219 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 7220 if (current_idx++ == idx) 7221 return sp->sn_name; 7222 return NULL; 7223 default: 7224 return NULL; 7225 } 7226} 7227 7228/* 7229 * Handle command line completion for :sign command. 7230 */ 7231 void 7232set_context_in_sign_cmd(xp, arg) 7233 expand_T *xp; 7234 char_u *arg; 7235{ 7236 char_u *p; 7237 char_u *end_subcmd; 7238 char_u *last; 7239 int cmd_idx; 7240 char_u *begin_subcmd_args; 7241 7242 /* Default: expand subcommands. */ 7243 xp->xp_context = EXPAND_SIGN; 7244 expand_what = EXP_SUBCMD; 7245 xp->xp_pattern = arg; 7246 7247 end_subcmd = skiptowhite(arg); 7248 if (*end_subcmd == NUL) 7249 /* expand subcmd name 7250 * :sign {subcmd}<CTRL-D>*/ 7251 return; 7252 7253 cmd_idx = sign_cmd_idx(arg, end_subcmd); 7254 7255 /* :sign {subcmd} {subcmd_args} 7256 * | 7257 * begin_subcmd_args */ 7258 begin_subcmd_args = skipwhite(end_subcmd); 7259 p = skiptowhite(begin_subcmd_args); 7260 if (*p == NUL) 7261 { 7262 /* 7263 * Expand first argument of subcmd when possible. 7264 * For ":jump {id}" and ":unplace {id}", we could 7265 * possibly expand the ids of all signs already placed. 7266 */ 7267 xp->xp_pattern = begin_subcmd_args; 7268 switch (cmd_idx) 7269 { 7270 case SIGNCMD_LIST: 7271 case SIGNCMD_UNDEFINE: 7272 /* :sign list <CTRL-D> 7273 * :sign undefine <CTRL-D> */ 7274 expand_what = EXP_SIGN_NAMES; 7275 break; 7276 default: 7277 xp->xp_context = EXPAND_NOTHING; 7278 } 7279 return; 7280 } 7281 7282 /* expand last argument of subcmd */ 7283 7284 /* :sign define {name} {args}... 7285 * | 7286 * p */ 7287 7288 /* Loop until reaching last argument. */ 7289 do 7290 { 7291 p = skipwhite(p); 7292 last = p; 7293 p = skiptowhite(p); 7294 } while (*p != NUL); 7295 7296 p = vim_strchr(last, '='); 7297 7298 /* :sign define {name} {args}... {last}= 7299 * | | 7300 * last p */ 7301 if (p == NUL) 7302 { 7303 /* Expand last argument name (before equal sign). */ 7304 xp->xp_pattern = last; 7305 switch (cmd_idx) 7306 { 7307 case SIGNCMD_DEFINE: 7308 expand_what = EXP_DEFINE; 7309 break; 7310 case SIGNCMD_PLACE: 7311 expand_what = EXP_PLACE; 7312 break; 7313 case SIGNCMD_JUMP: 7314 case SIGNCMD_UNPLACE: 7315 expand_what = EXP_UNPLACE; 7316 break; 7317 default: 7318 xp->xp_context = EXPAND_NOTHING; 7319 } 7320 } 7321 else 7322 { 7323 /* Expand last argument value (after equal sign). */ 7324 xp->xp_pattern = p + 1; 7325 switch (cmd_idx) 7326 { 7327 case SIGNCMD_DEFINE: 7328 if (STRNCMP(last, "texthl", p - last) == 0 || 7329 STRNCMP(last, "linehl", p - last) == 0) 7330 xp->xp_context = EXPAND_HIGHLIGHT; 7331 else if (STRNCMP(last, "icon", p - last) == 0) 7332 xp->xp_context = EXPAND_FILES; 7333 else 7334 xp->xp_context = EXPAND_NOTHING; 7335 break; 7336 case SIGNCMD_PLACE: 7337 if (STRNCMP(last, "name", p - last) == 0) 7338 expand_what = EXP_SIGN_NAMES; 7339 else 7340 xp->xp_context = EXPAND_NOTHING; 7341 break; 7342 default: 7343 xp->xp_context = EXPAND_NOTHING; 7344 } 7345 } 7346} 7347#endif 7348#endif 7349 7350#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO) 7351/* 7352 * ":drop" 7353 * Opens the first argument in a window. When there are two or more arguments 7354 * the argument list is redefined. 7355 */ 7356 void 7357ex_drop(eap) 7358 exarg_T *eap; 7359{ 7360 int split = FALSE; 7361 win_T *wp; 7362 buf_T *buf; 7363# ifdef FEAT_WINDOWS 7364 tabpage_T *tp; 7365# endif 7366 7367 /* 7368 * Check if the first argument is already being edited in a window. If 7369 * so, jump to that window. 7370 * We would actually need to check all arguments, but that's complicated 7371 * and mostly only one file is dropped. 7372 * This also ignores wildcards, since it is very unlikely the user is 7373 * editing a file name with a wildcard character. 7374 */ 7375 set_arglist(eap->arg); 7376 7377 /* 7378 * Expanding wildcards may result in an empty argument list. E.g. when 7379 * editing "foo.pyc" and ".pyc" is in 'wildignore'. Assume that we 7380 * already did an error message for this. 7381 */ 7382 if (ARGCOUNT == 0) 7383 return; 7384 7385# ifdef FEAT_WINDOWS 7386 if (cmdmod.tab) 7387 { 7388 /* ":tab drop file ...": open a tab for each argument that isn't 7389 * edited in a window yet. It's like ":tab all" but without closing 7390 * windows or tabs. */ 7391 ex_all(eap); 7392 } 7393 else 7394# endif 7395 { 7396 /* ":drop file ...": Edit the first argument. Jump to an existing 7397 * window if possible, edit in current window if the current buffer 7398 * can be abandoned, otherwise open a new window. */ 7399 buf = buflist_findnr(ARGLIST[0].ae_fnum); 7400 7401 FOR_ALL_TAB_WINDOWS(tp, wp) 7402 { 7403 if (wp->w_buffer == buf) 7404 { 7405# ifdef FEAT_WINDOWS 7406 goto_tabpage_win(tp, wp); 7407# endif 7408 curwin->w_arg_idx = 0; 7409 return; 7410 } 7411 } 7412 7413 /* 7414 * Check whether the current buffer is changed. If so, we will need 7415 * to split the current window or data could be lost. 7416 * Skip the check if the 'hidden' option is set, as in this case the 7417 * buffer won't be lost. 7418 */ 7419 if (!P_HID(curbuf)) 7420 { 7421# ifdef FEAT_WINDOWS 7422 ++emsg_off; 7423# endif 7424 split = check_changed(curbuf, TRUE, FALSE, FALSE, FALSE); 7425# ifdef FEAT_WINDOWS 7426 --emsg_off; 7427# else 7428 if (split) 7429 return; 7430# endif 7431 } 7432 7433 /* Fake a ":sfirst" or ":first" command edit the first argument. */ 7434 if (split) 7435 { 7436 eap->cmdidx = CMD_sfirst; 7437 eap->cmd[0] = 's'; 7438 } 7439 else 7440 eap->cmdidx = CMD_first; 7441 ex_rewind(eap); 7442 } 7443} 7444#endif 7445