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