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