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