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