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