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