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