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 && !cmdmod.keepalt) 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 if (!cmdmod.keepalt) 2693 curwin->w_alt_fnum = curbuf->b_fnum; 2694 buflist_altfpos(); 2695 } 2696 2697 if (fnum) 2698 buf = buflist_findnr(fnum); 2699 else 2700 { 2701 #ifdef FEAT_LISTCMDS 2702 if (flags & ECMD_ADDBUF) 2703 { 2704 linenr_T tlnum = 1L; 2705 2706 if (command != NULL) 2707 { 2708 tlnum = atol((char *)command); 2709 if (tlnum <= 0) 2710 tlnum = 1L; 2711 } 2712 (void)buflist_new(ffname, sfname, tlnum, BLN_LISTED); 2713 goto theend; 2714 } 2715 #endif 2716 buf = buflist_new(ffname, sfname, 0L, 2717 BLN_CURBUF | ((flags & ECMD_SET_HELP) ? 0 : BLN_LISTED)); 2718 } 2719 if (buf == NULL) 2720 goto theend; 2721 if (buf->b_ml.ml_mfp == NULL) /* no memfile yet */ 2722 { 2723 oldbuf = FALSE; 2724 buf->b_nwindows = 0; 2725 } 2726 else /* existing memfile */ 2727 { 2728 oldbuf = TRUE; 2729 (void)buf_check_timestamp(buf, FALSE); 2730 /* Check if autocommands made buffer invalid or changed the current 2731 * buffer. */ 2732 if (!buf_valid(buf) 2733 #ifdef FEAT_AUTOCMD 2734 || curbuf != old_curbuf 2735 #endif 2736 ) 2737 goto theend; 2738 #ifdef FEAT_EVAL 2739 if (aborting()) /* autocmds may abort script processing */ 2740 goto theend; 2741 #endif 2742 } 2743 2744 /* May jump to last used line number for a loaded buffer or when asked 2745 * for explicitly */ 2746 if ((oldbuf && newlnum == ECMD_LASTL) || newlnum == ECMD_LAST) 2747 { 2748 pos = buflist_findfpos(buf); 2749 newlnum = pos->lnum; 2750 solcol = pos->col; 2751 } 2752 2753 /* 2754 * Make the (new) buffer the one used by the current window. 2755 * If the old buffer becomes unused, free it if ECMD_HIDE is FALSE. 2756 * If the current buffer was empty and has no file name, curbuf 2757 * is returned by buflist_new(). 2758 */ 2759 if (buf != curbuf) 2760 { 2761 #ifdef FEAT_AUTOCMD 2762 /* 2763 * Be careful: The autocommands may delete any buffer and change 2764 * the current buffer. 2765 * - If the buffer we are going to edit is deleted, give up. 2766 * - If the current buffer is deleted, prefer to load the new 2767 * buffer when loading a buffer is required. This avoids 2768 * loading another buffer which then must be closed again. 2769 * - If we ended up in the new buffer already, need to skip a few 2770 * things, set auto_buf. 2771 */ 2772 if (buf->b_fname != NULL) 2773 new_name = vim_strsave(buf->b_fname); 2774 au_new_curbuf = buf; 2775 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf); 2776 if (!buf_valid(buf)) /* new buffer has been deleted */ 2777 { 2778 delbuf_msg(new_name); /* frees new_name */ 2779 goto theend; 2780 } 2781 # ifdef FEAT_EVAL 2782 if (aborting()) /* autocmds may abort script processing */ 2783 { 2784 vim_free(new_name); 2785 goto theend; 2786 } 2787 # endif 2788 if (buf == curbuf) /* already in new buffer */ 2789 auto_buf = TRUE; 2790 else 2791 { 2792 if (curbuf == old_curbuf) 2793 #endif 2794 buf_copy_options(buf, BCO_ENTER); 2795 2796 /* close the link to the current buffer */ 2797 close_buffer(curwin, curbuf, 2798 (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD); 2799 2800 #ifdef FEAT_AUTOCMD 2801 # ifdef FEAT_EVAL 2802 if (aborting()) /* autocmds may abort script processing */ 2803 { 2804 vim_free(new_name); 2805 goto theend; 2806 } 2807 # endif 2808 /* Be careful again, like above. */ 2809 if (!buf_valid(buf)) /* new buffer has been deleted */ 2810 { 2811 delbuf_msg(new_name); /* frees new_name */ 2812 goto theend; 2813 } 2814 if (buf == curbuf) /* already in new buffer */ 2815 auto_buf = TRUE; 2816 else 2817 #endif 2818 { 2819 curwin->w_buffer = buf; 2820 curbuf = buf; 2821 ++curbuf->b_nwindows; 2822 /* set 'fileformat' */ 2823 if (*p_ffs && !oldbuf) 2824 set_fileformat(default_fileformat(), OPT_LOCAL); 2825 } 2826 2827 /* May get the window options from the last time this buffer 2828 * was in this window (or another window). If not used 2829 * before, reset the local window options to the global 2830 * values. Also restores old folding stuff. */ 2831 get_winopts(buf); 2832 2833 #ifdef FEAT_AUTOCMD 2834 } 2835 vim_free(new_name); 2836 au_new_curbuf = NULL; 2837 #endif 2838 } 2839 else 2840 ++curbuf->b_nwindows; 2841 2842 curwin->w_pcmark.lnum = 1; 2843 curwin->w_pcmark.col = 0; 2844 } 2845 else /* !other_file */ 2846 { 2847 if ( 2848 #ifdef FEAT_LISTCMDS 2849 (flags & ECMD_ADDBUF) || 2850 #endif 2851 check_fname() == FAIL) 2852 goto theend; 2853 oldbuf = (flags & ECMD_OLDBUF); 2854 } 2855 2856 if ((flags & ECMD_SET_HELP) || keep_help_flag) 2857 { 2858 char_u *p; 2859 2860 curbuf->b_help = TRUE; 2861 #ifdef FEAT_QUICKFIX 2862 set_string_option_direct((char_u *)"buftype", -1, 2863 (char_u *)"help", OPT_FREE|OPT_LOCAL); 2864 #endif 2865 2866 /* 2867 * Always set these options after jumping to a help tag, because the 2868 * user may have an autocommand that gets in the way. 2869 * Accept all ASCII chars for keywords, except ' ', '*', '"', '|', and 2870 * latin1 word characters (for translated help files). 2871 * Only set it when needed, buf_init_chartab() is some work. 2872 */ 2873 p = 2874 #ifdef EBCDIC 2875 (char_u *)"65-255,^*,^|,^\""; 2876 #else 2877 (char_u *)"!-~,^*,^|,^\",192-255"; 2878 #endif 2879 if (STRCMP(curbuf->b_p_isk, p) != 0) 2880 { 2881 set_string_option_direct((char_u *)"isk", -1, p, 2882 OPT_FREE|OPT_LOCAL); 2883 check_buf_options(curbuf); 2884 (void)buf_init_chartab(curbuf, FALSE); 2885 } 2886 2887 curbuf->b_p_ts = 8; /* 'tabstop' is 8 */ 2888 curwin->w_p_list = FALSE; /* no list mode */ 2889 2890 curbuf->b_p_ma = FALSE; /* not modifiable */ 2891 curbuf->b_p_bin = FALSE; /* reset 'bin' before reading file */ 2892 curwin->w_p_nu = 0; /* no line numbers */ 2893 #ifdef FEAT_SCROLLBIND 2894 curwin->w_p_scb = FALSE; /* no scroll binding */ 2895 #endif 2896 #ifdef FEAT_ARABIC 2897 curwin->w_p_arab = FALSE; /* no arabic mode */ 2898 #endif 2899 #ifdef FEAT_RIGHTLEFT 2900 curwin->w_p_rl = FALSE; /* help window is left-to-right */ 2901 #endif 2902 #ifdef FEAT_FOLDING 2903 curwin->w_p_fen = FALSE; /* No folding in the help window */ 2904 #endif 2905 #ifdef FEAT_DIFF 2906 curwin->w_p_diff = FALSE; /* No 'diff' */ 2907 #endif 2908 2909 #ifdef FEAT_AUTOCMD 2910 buf = curbuf; 2911 #endif 2912 set_buflisted(FALSE); 2913 } 2914 else 2915 { 2916 #ifdef FEAT_AUTOCMD 2917 buf = curbuf; 2918 #endif 2919 /* Don't make a buffer listed if it's a help buffer. Useful when 2920 * using CTRL-O to go back to a help file. */ 2921 if (!curbuf->b_help) 2922 set_buflisted(TRUE); 2923 } 2924 2925 #ifdef FEAT_AUTOCMD 2926 /* If autocommands change buffers under our fingers, forget about 2927 * editing the file. */ 2928 if (buf != curbuf) 2929 goto theend; 2930 # ifdef FEAT_EVAL 2931 if (aborting()) /* autocmds may abort script processing */ 2932 goto theend; 2933 # endif 2934 2935 /* Since we are starting to edit a file, consider the filetype to be 2936 * unset. Helps for when an autocommand changes files and expects syntax 2937 * highlighting to work in the other file. */ 2938 did_filetype = FALSE; 2939 #endif 2940 2941 /* 2942 * other_file oldbuf 2943 * FALSE FALSE re-edit same file, buffer is re-used 2944 * FALSE TRUE re-edit same file, nothing changes 2945 * TRUE FALSE start editing new file, new buffer 2946 * TRUE TRUE start editing in existing buffer (nothing to do) 2947 */ 2948 if (!other_file && !oldbuf) /* re-use the buffer */ 2949 { 2950 set_last_cursor(curwin); /* may set b_last_cursor */ 2951 if (newlnum == ECMD_LAST || newlnum == ECMD_LASTL) 2952 { 2953 newlnum = curwin->w_cursor.lnum; 2954 solcol = curwin->w_cursor.col; 2955 } 2956 #ifdef FEAT_AUTOCMD 2957 buf = curbuf; 2958 if (buf->b_fname != NULL) 2959 new_name = vim_strsave(buf->b_fname); 2960 else 2961 new_name = NULL; 2962 #endif 2963 buf_freeall(curbuf, FALSE, FALSE); /* free all things for buffer */ 2964 #ifdef FEAT_AUTOCMD 2965 /* If autocommands deleted the buffer we were going to re-edit, give 2966 * up and jump to the end. */ 2967 if (!buf_valid(buf)) 2968 { 2969 delbuf_msg(new_name); /* frees new_name */ 2970 goto theend; 2971 } 2972 vim_free(new_name); 2973 2974 /* If autocommands change buffers under our fingers, forget about 2975 * re-editing the file. Should do the buf_clear_file(), but perhaps 2976 * the autocommands changed the buffer... */ 2977 if (buf != curbuf) 2978 goto theend; 2979 # ifdef FEAT_EVAL 2980 if (aborting()) /* autocmds may abort script processing */ 2981 goto theend; 2982 # endif 2983 #endif 2984 buf_clear_file(curbuf); 2985 curbuf->b_op_start.lnum = 0; /* clear '[ and '] marks */ 2986 curbuf->b_op_end.lnum = 0; 2987 } 2988 2989 /* 2990 * If we get here we are sure to start editing 2991 */ 2992 /* don't redraw until the cursor is in the right line */ 2993 ++RedrawingDisabled; 2994 2995 /* Assume success now */ 2996 retval = OK; 2997 2998 /* 2999 * Reset cursor position, could be used by autocommands. 3000 */ 3001 check_cursor(); 3002 3003 /* 3004 * Check if we are editing the w_arg_idx file in the argument list. 3005 */ 3006 check_arg_idx(curwin); 3007 3008 #ifdef FEAT_AUTOCMD 3009 if (!auto_buf) 3010 #endif 3011 { 3012 /* 3013 * Set cursor and init window before reading the file and executing 3014 * autocommands. This allows for the autocommands to position the 3015 * cursor. 3016 */ 3017 win_init(curwin); 3018 3019 #ifdef FEAT_FOLDING 3020 /* It's like all lines in the buffer changed. Need to update 3021 * automatic folding. */ 3022 foldUpdateAll(curwin); 3023 #endif 3024 3025 #if defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG) 3026 if (p_acd && curbuf->b_ffname != NULL 3027 && vim_chdirfile(curbuf->b_ffname) == OK) 3028 shorten_fnames(TRUE); 3029 #endif 3030 /* 3031 * Careful: open_buffer() and apply_autocmds() may change the current 3032 * buffer and window. 3033 */ 3034 lnum = curwin->w_cursor.lnum; 3035 topline = curwin->w_topline; 3036 if (!oldbuf) /* need to read the file */ 3037 { 3038 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 3039 swap_exists_action = SEA_DIALOG; 3040 #endif 3041 curbuf->b_flags |= BF_CHECK_RO; /* set/reset 'ro' flag */ 3042 3043 /* 3044 * Open the buffer and read the file. 3045 */ 3046 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 3047 if (should_abort(open_buffer(FALSE, eap))) 3048 retval = FAIL; 3049 #else 3050 (void)open_buffer(FALSE, eap); 3051 #endif 3052 3053 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 3054 if (swap_exists_action == SEA_QUIT) 3055 retval = FAIL; 3056 handle_swap_exists(old_curbuf); 3057 #endif 3058 } 3059 #ifdef FEAT_AUTOCMD 3060 else 3061 { 3062 /* Read the modelines, but only to set window-local options. Any 3063 * buffer-local options have already been set and may have been 3064 * changed by the user. */ 3065 do_modelines(TRUE); 3066 3067 apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, 3068 &retval); 3069 apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf, 3070 &retval); 3071 } 3072 check_arg_idx(curwin); 3073 #endif 3074 3075 /* 3076 * If autocommands change the cursor position or topline, we should 3077 * keep it. 3078 */ 3079 if (curwin->w_cursor.lnum != lnum) 3080 { 3081 newlnum = curwin->w_cursor.lnum; 3082 newcol = curwin->w_cursor.col; 3083 } 3084 if (curwin->w_topline == topline) 3085 topline = 0; 3086 3087 /* Even when cursor didn't move we need to recompute topline. */ 3088 changed_line_abv_curs(); 3089 3090 #ifdef FEAT_TITLE 3091 maketitle(); 3092 #endif 3093 } 3094 3095 #ifdef FEAT_DIFF 3096 /* Tell the diff stuff that this buffer is new and/or needs updating. 3097 * Also needed when re-editing the same buffer, because unloading will 3098 * have removed it as a diff buffer. */ 3099 diff_new_buffer(); 3100 diff_invalidate(); 3101 #endif 3102 3103 if (command == NULL) 3104 { 3105 if (newcol >= 0) /* position set by autocommands */ 3106 { 3107 curwin->w_cursor.lnum = newlnum; 3108 curwin->w_cursor.col = newcol; 3109 check_cursor(); 3110 } 3111 else if (newlnum > 0) /* line number from caller or old position */ 3112 { 3113 curwin->w_cursor.lnum = newlnum; 3114 check_cursor_lnum(); 3115 if (solcol >= 0 && !p_sol) 3116 { 3117 /* 'sol' is off: Use last known column. */ 3118 curwin->w_cursor.col = solcol; 3119 check_cursor_col(); 3120 #ifdef FEAT_VIRTUALEDIT 3121 curwin->w_cursor.coladd = 0; 3122 #endif 3123 curwin->w_set_curswant = TRUE; 3124 } 3125 else 3126 beginline(BL_SOL | BL_FIX); 3127 } 3128 else /* no line number, go to last line in Ex mode */ 3129 { 3130 if (exmode_active) 3131 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 3132 beginline(BL_WHITE | BL_FIX); 3133 } 3134 } 3135 3136 #ifdef FEAT_WINDOWS 3137 /* Check if cursors in other windows on the same buffer are still valid */ 3138 check_lnums(FALSE); 3139 #endif 3140 3141 /* 3142 * Did not read the file, need to show some info about the file. 3143 * Do this after setting the cursor. 3144 */ 3145 if (oldbuf 3146 #ifdef FEAT_AUTOCMD 3147 && !auto_buf 3148 #endif 3149 ) 3150 { 3151 int msg_scroll_save = msg_scroll; 3152 3153 /* Obey the 'O' flag in 'cpoptions': overwrite any previous file 3154 * message. */ 3155 if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) 3156 msg_scroll = FALSE; 3157 if (!msg_scroll) /* wait a bit when overwriting an error msg */ 3158 check_for_delay(FALSE); 3159 msg_start(); 3160 msg_scroll = msg_scroll_save; 3161 msg_scrolled_ign = TRUE; 3162 3163 fileinfo(FALSE, TRUE, FALSE); 3164 3165 msg_scrolled_ign = FALSE; 3166 } 3167 3168 if (command != NULL) 3169 do_cmdline(command, NULL, NULL, DOCMD_VERBOSE); 3170 3171 #ifdef FEAT_KEYMAP 3172 if (curbuf->b_kmap_state & KEYMAP_INIT) 3173 keymap_init(); 3174 #endif 3175 3176 --RedrawingDisabled; 3177 if (!skip_redraw) 3178 { 3179 n = p_so; 3180 if (topline == 0 && command == NULL) 3181 p_so = 999; /* force cursor halfway the window */ 3182 update_topline(); 3183 #ifdef FEAT_SCROLLBIND 3184 curwin->w_scbind_pos = curwin->w_topline; 3185 #endif 3186 p_so = n; 3187 redraw_curbuf_later(NOT_VALID); /* redraw this buffer later */ 3188 } 3189 3190 if (p_im) 3191 need_start_insertmode = TRUE; 3192 3193 #if defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG) 3194 /* Change directories when the acd option is set on. */ 3195 if (p_acd && curbuf->b_ffname != NULL 3196 && vim_chdirfile(curbuf->b_ffname) == OK) 3197 shorten_fnames(TRUE); 3198 3199 if (gui.in_use && curbuf->b_ffname != NULL) 3200 { 3201 # ifdef FEAT_SUN_WORKSHOP 3202 if (usingSunWorkShop) 3203 workshop_file_opened((char *)curbuf->b_ffname, curbuf->b_p_ro); 3204 # endif 3205 # ifdef FEAT_NETBEANS_INTG 3206 if (usingNetbeans) 3207 netbeans_file_opened((char *)curbuf->b_ffname); 3208 # endif 3209 } 3210 #endif 3211 3212 theend: 3213 #ifdef FEAT_BROWSE 3214 vim_free(browse_file); 3215 #endif 3216 vim_free(free_fname); 3217 return retval; 3218 } 3219 3220 #ifdef FEAT_AUTOCMD 3221 static void 3222 delbuf_msg(name) 3223 char_u *name; 3224 { 3225 EMSG2(_("E143: Autocommands unexpectedly deleted new buffer %s"), 3226 name == NULL ? (char_u *)"" : name); 3227 vim_free(name); 3228 au_new_curbuf = NULL; 3229 } 3230 #endif 3231 3232 /* 3233 * ":insert" and ":append", also used by ":change" 3234 */ 3235 void 3236 ex_append(eap) 3237 exarg_T *eap; 3238 { 3239 char_u *theline; 3240 int did_undo = FALSE; 3241 linenr_T lnum = eap->line2; 3242 3243 if (eap->cmdidx != CMD_append) 3244 --lnum; 3245 3246 State = INSERT; /* behave like in Insert mode */ 3247 if (curbuf->b_p_iminsert == B_IMODE_LMAP) 3248 State |= LANGMAP; 3249 while (1) 3250 { 3251 msg_scroll = TRUE; 3252 need_wait_return = FALSE; 3253 if (eap->getline == NULL) 3254 theline = getcmdline( 3255 #ifdef FEAT_EVAL 3256 eap->cstack->cs_whilelevel > 0 ? -1 : 3257 #endif 3258 NUL, 0L, 0); 3259 else 3260 theline = eap->getline( 3261 #ifdef FEAT_EVAL 3262 eap->cstack->cs_whilelevel > 0 ? -1 : 3263 #endif 3264 NUL, eap->cookie, 0); 3265 lines_left = Rows - 1; 3266 if (theline == NULL || (theline[0] == '.' && theline[1] == NUL) 3267 || (!did_undo && u_save(lnum, lnum + 1) == FAIL)) 3268 { 3269 vim_free(theline); 3270 break; 3271 } 3272 3273 did_undo = TRUE; 3274 ml_append(lnum, theline, (colnr_T)0, FALSE); 3275 appended_lines_mark(lnum, 1L); 3276 3277 vim_free(theline); 3278 ++lnum; 3279 msg_didout = TRUE; /* also scroll for empty line */ 3280 } 3281 State = NORMAL; 3282 3283 /* "start" is set to eap->line2+1 unless that position is invalid (when 3284 * eap->line2 pointed to the end of the buffer and nothig was appended) 3285 * "end" is set to lnum when something has been appended, otherwise 3286 * it is the same than "start" -- Acevedo */ 3287 curbuf->b_op_start.lnum = (eap->line2 < curbuf->b_ml.ml_line_count) ? 3288 eap->line2 + 1 : curbuf->b_ml.ml_line_count; 3289 if (eap->cmdidx != CMD_append) 3290 --curbuf->b_op_start.lnum; 3291 curbuf->b_op_end.lnum = (eap->line2 < lnum) 3292 ? lnum : curbuf->b_op_start.lnum; 3293 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 3294 curwin->w_cursor.lnum = lnum; 3295 check_cursor_lnum(); 3296 beginline(BL_SOL | BL_FIX); 3297 3298 need_wait_return = FALSE; /* don't use wait_return() now */ 3299 ex_no_reprint = TRUE; 3300 } 3301 3302 /* 3303 * ":change" 3304 */ 3305 void 3306 ex_change(eap) 3307 exarg_T *eap; 3308 { 3309 linenr_T lnum; 3310 3311 if (eap->line2 >= eap->line1 3312 && u_save(eap->line1 - 1, eap->line2 + 1) == FAIL) 3313 return; 3314 3315 for (lnum = eap->line2; lnum >= eap->line1; --lnum) 3316 { 3317 if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */ 3318 break; 3319 ml_delete(eap->line1, FALSE); 3320 } 3321 deleted_lines_mark(eap->line1, (long)(eap->line2 - lnum)); 3322 3323 /* ":append" on the line above the deleted lines. */ 3324 eap->line2 = eap->line1; 3325 ex_append(eap); 3326 } 3327 3328 void 3329 ex_z(eap) 3330 exarg_T *eap; 3331 { 3332 char_u *x; 3333 int bigness = curwin->w_height - 3; 3334 char_u kind; 3335 int numbered = FALSE; 3336 int minus = 0; 3337 linenr_T start, end, curs, i; 3338 int j; 3339 linenr_T lnum = eap->line2; 3340 3341 if (bigness < 1) 3342 bigness = 1; 3343 3344 x = eap->arg; 3345 if (*x == '#') 3346 { 3347 numbered = TRUE; 3348 ++x; 3349 } 3350 3351 kind = *x; 3352 if (kind == '-' || kind == '+' || kind == '=' || kind == '^' || kind == '.') 3353 ++x; 3354 3355 if (*x != 0) 3356 { 3357 if (!VIM_ISDIGIT(*x)) 3358 { 3359 EMSG(_("E144: non-numeric argument to :z")); 3360 return; 3361 } 3362 else 3363 bigness = atoi((char *)x); 3364 } 3365 3366 switch (kind) 3367 { 3368 case '-': 3369 start = lnum - bigness; 3370 end = lnum; 3371 curs = lnum; 3372 break; 3373 3374 case '=': 3375 start = lnum - bigness / 2 + 1; 3376 end = lnum + bigness / 2 - 1; 3377 curs = lnum; 3378 minus = 1; 3379 break; 3380 3381 case '^': 3382 start = lnum - bigness * 2; 3383 end = lnum - bigness; 3384 curs = lnum - bigness; 3385 break; 3386 3387 case '.': 3388 start = lnum - bigness / 2; 3389 end = lnum + bigness / 2; 3390 curs = end; 3391 break; 3392 3393 default: /* '+' */ 3394 start = lnum; 3395 end = lnum + bigness; 3396 curs = end; 3397 break; 3398 } 3399 3400 if (start < 1) 3401 start = 1; 3402 3403 if (end > curbuf->b_ml.ml_line_count) 3404 end = curbuf->b_ml.ml_line_count; 3405 3406 if (curs > curbuf->b_ml.ml_line_count) 3407 curs = curbuf->b_ml.ml_line_count; 3408 3409 for (i = start; i <= end; i++) 3410 { 3411 if (minus && i == lnum) 3412 { 3413 msg_putchar('\n'); 3414 3415 for (j = 1; j < Columns; j++) 3416 msg_putchar('-'); 3417 } 3418 3419 print_line(i, numbered); 3420 3421 if (minus && i == lnum) 3422 { 3423 msg_putchar('\n'); 3424 3425 for (j = 1; j < Columns; j++) 3426 msg_putchar('-'); 3427 } 3428 } 3429 3430 curwin->w_cursor.lnum = curs; 3431 ex_no_reprint = TRUE; 3432 } 3433 3434 /* 3435 * Check if the restricted flag is set. 3436 * If so, give an error message and return TRUE. 3437 * Otherwise, return FALSE. 3438 */ 3439 int 3440 check_restricted() 3441 { 3442 if (restricted) 3443 { 3444 EMSG(_("E145: Shell commands not allowed in rvim")); 3445 return TRUE; 3446 } 3447 return FALSE; 3448 } 3449 3450 /* 3451 * Check if the secure flag is set (.exrc or .vimrc in current directory). 3452 * If so, give an error message and return TRUE. 3453 * Otherwise, return FALSE. 3454 */ 3455 int 3456 check_secure() 3457 { 3458 if (secure) 3459 { 3460 secure = 2; 3461 EMSG(_(e_curdir)); 3462 return TRUE; 3463 } 3464 #ifdef HAVE_SANDBOX 3465 /* 3466 * In the sandbox more things are not allowed, including the things 3467 * disallowed in secure mode. 3468 */ 3469 if (sandbox != 0) 3470 { 3471 EMSG(_(e_sandbox)); 3472 return TRUE; 3473 } 3474 #endif 3475 return FALSE; 3476 } 3477 3478 static char_u *old_sub = NULL; /* previous substitute pattern */ 3479 static int global_need_beginline; /* call beginline() after ":g" */ 3480 3481 /* 3482 * When ":global" is used to number of substitutions and changed lines is 3483 * accumulated until it's finished. 3484 */ 3485 static long sub_nsubs; /* total number of substitutions */ 3486 static linenr_T sub_nlines; /* total number of lines changed */ 3487 3488 /* do_sub() 3489 * 3490 * Perform a substitution from line eap->line1 to line eap->line2 using the 3491 * command pointed to by eap->arg which should be of the form: 3492 * 3493 * /pattern/substitution/{flags} 3494 * 3495 * The usual escapes are supported as described in the regexp docs. 3496 */ 3497 void 3498 do_sub(eap) 3499 exarg_T *eap; 3500 { 3501 linenr_T lnum; 3502 long i = 0; 3503 regmmatch_T regmatch; 3504 static int do_all = FALSE; /* do multiple substitutions per line */ 3505 static int do_ask = FALSE; /* ask for confirmation */ 3506 static int do_error = TRUE; /* if false, ignore errors */ 3507 static int do_print = FALSE; /* print last line with subs. */ 3508 static int do_ic = 0; /* ignore case flag */ 3509 char_u *pat = NULL, *sub = NULL; /* init for GCC */ 3510 int delimiter; 3511 int sublen; 3512 int got_quit = FALSE; 3513 int got_match = FALSE; 3514 int temp; 3515 int which_pat; 3516 char_u *cmd; 3517 int save_State; 3518 linenr_T first_line = 0; /* first changed line */ 3519 linenr_T last_line= 0; /* below last changed line AFTER the 3520 * change */ 3521 linenr_T old_line_count = curbuf->b_ml.ml_line_count; 3522 linenr_T line2; 3523 long nmatch; /* number of lines in match */ 3524 linenr_T sub_firstlnum; /* nr of first sub line */ 3525 char_u *sub_firstline; /* allocated copy of first sub line */ 3526 3527 cmd = eap->arg; 3528 if (!global_busy) 3529 { 3530 sub_nsubs = 0; 3531 sub_nlines = 0; 3532 } 3533 3534 #ifdef FEAT_FKMAP /* reverse the flow of the Farsi characters */ 3535 if (p_altkeymap && curwin->w_p_rl) 3536 lrF_sub(cmd); 3537 #endif 3538 3539 if (eap->cmdidx == CMD_tilde) 3540 which_pat = RE_LAST; /* use last used regexp */ 3541 else 3542 which_pat = RE_SUBST; /* use last substitute regexp */ 3543 3544 /* new pattern and substitution */ 3545 if (eap->cmd[0] == 's' && *cmd != NUL && !vim_iswhite(*cmd) 3546 && vim_strchr((char_u *)"0123456789cegriIp|\"", *cmd) == NULL) 3547 { 3548 /* don't accept alphanumeric for separator */ 3549 if (isalpha(*cmd)) 3550 { 3551 EMSG(_("E146: Regular expressions can't be delimited by letters")); 3552 return; 3553 } 3554 /* 3555 * undocumented vi feature: 3556 * "\/sub/" and "\?sub?" use last used search pattern (almost like 3557 * //sub/r). "\&sub&" use last substitute pattern (like //sub/). 3558 */ 3559 if (*cmd == '\\') 3560 { 3561 ++cmd; 3562 if (vim_strchr((char_u *)"/?&", *cmd) == NULL) 3563 { 3564 EMSG(_(e_backslash)); 3565 return; 3566 } 3567 if (*cmd != '&') 3568 which_pat = RE_SEARCH; /* use last '/' pattern */ 3569 pat = (char_u *)""; /* empty search pattern */ 3570 delimiter = *cmd++; /* remember delimiter character */ 3571 } 3572 else /* find the end of the regexp */ 3573 { 3574 which_pat = RE_LAST; /* use last used regexp */ 3575 delimiter = *cmd++; /* remember delimiter character */ 3576 pat = cmd; /* remember start of search pat */ 3577 cmd = skip_regexp(cmd, delimiter, p_magic, &eap->arg); 3578 if (cmd[0] == delimiter) /* end delimiter found */ 3579 *cmd++ = NUL; /* replace it with a NUL */ 3580 } 3581 3582 /* 3583 * Small incompatibility: vi sees '\n' as end of the command, but in 3584 * Vim we want to use '\n' to find/substitute a NUL. 3585 */ 3586 sub = cmd; /* remember the start of the substitution */ 3587 3588 while (cmd[0]) 3589 { 3590 if (cmd[0] == delimiter) /* end delimiter found */ 3591 { 3592 *cmd++ = NUL; /* replace it with a NUL */ 3593 break; 3594 } 3595 if (cmd[0] == '\\' && cmd[1] != 0) /* skip escaped characters */ 3596 ++cmd; 3597 #ifdef FEAT_MBYTE 3598 if (has_mbyte) 3599 cmd += (*mb_ptr2len_check)(cmd); 3600 else 3601 #endif 3602 ++cmd; 3603 } 3604 3605 if (!eap->skip) 3606 { 3607 vim_free(old_sub); 3608 old_sub = vim_strsave(sub); 3609 } 3610 } 3611 else if (!eap->skip) /* use previous pattern and substitution */ 3612 { 3613 if (old_sub == NULL) /* there is no previous command */ 3614 { 3615 EMSG(_(e_nopresub)); 3616 return; 3617 } 3618 pat = NULL; /* search_regcomp() will use previous pattern */ 3619 sub = old_sub; 3620 } 3621 3622 /* 3623 * Find trailing options. When '&' is used, keep old options. 3624 */ 3625 if (*cmd == '&') 3626 ++cmd; 3627 else 3628 { 3629 if (!p_ed) 3630 { 3631 if (p_gd) /* default is global on */ 3632 do_all = TRUE; 3633 else 3634 do_all = FALSE; 3635 do_ask = FALSE; 3636 } 3637 do_error = TRUE; 3638 do_print = FALSE; 3639 do_ic = 0; 3640 } 3641 while (*cmd) 3642 { 3643 /* 3644 * Note that 'g' and 'c' are always inverted, also when p_ed is off. 3645 * 'r' is never inverted. 3646 */ 3647 if (*cmd == 'g') 3648 do_all = !do_all; 3649 else if (*cmd == 'c') 3650 do_ask = !do_ask; 3651 else if (*cmd == 'e') 3652 do_error = !do_error; 3653 else if (*cmd == 'r') /* use last used regexp */ 3654 which_pat = RE_LAST; 3655 else if (*cmd == 'p') 3656 do_print = TRUE; 3657 else if (*cmd == 'i') /* ignore case */ 3658 do_ic = 'i'; 3659 else if (*cmd == 'I') /* don't ignore case */ 3660 do_ic = 'I'; 3661 else 3662 break; 3663 ++cmd; 3664 } 3665 3666 /* 3667 * check for a trailing count 3668 */ 3669 cmd = skipwhite(cmd); 3670 if (VIM_ISDIGIT(*cmd)) 3671 { 3672 i = getdigits(&cmd); 3673 if (i <= 0 && !eap->skip && do_error) 3674 { 3675 EMSG(_(e_zerocount)); 3676 return; 3677 } 3678 eap->line1 = eap->line2; 3679 eap->line2 += i - 1; 3680 if (eap->line2 > curbuf->b_ml.ml_line_count) 3681 eap->line2 = curbuf->b_ml.ml_line_count; 3682 } 3683 3684 /* 3685 * check for trailing command or garbage 3686 */ 3687 cmd = skipwhite(cmd); 3688 if (*cmd && *cmd != '"') /* if not end-of-line or comment */ 3689 { 3690 eap->nextcmd = check_nextcmd(cmd); 3691 if (eap->nextcmd == NULL) 3692 { 3693 EMSG(_(e_trailing)); 3694 return; 3695 } 3696 } 3697 3698 if (eap->skip) /* not executing commands, only parsing */ 3699 return; 3700 3701 if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, ®match) == FAIL) 3702 { 3703 if (do_error) 3704 EMSG(_(e_invcmd)); 3705 return; 3706 } 3707 3708 /* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */ 3709 if (do_ic == 'i') 3710 regmatch.rmm_ic = TRUE; 3711 else if (do_ic == 'I') 3712 regmatch.rmm_ic = FALSE; 3713 3714 sub_firstline = NULL; 3715 3716 /* 3717 * ~ in the substitute pattern is replaced with the old pattern. 3718 * We do it here once to avoid it to be replaced over and over again. 3719 * But don't do it when it starts with "\=", then it's an expression. 3720 */ 3721 if (!(sub[0] == '\\' && sub[1] == '=')) 3722 sub = regtilde(sub, p_magic); 3723 3724 /* 3725 * Check for a match on each line. 3726 */ 3727 line2 = eap->line2; 3728 for (lnum = eap->line1; lnum <= line2 && !(got_quit 3729 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD) 3730 || aborting() 3731 #endif 3732 ); ++lnum) 3733 { 3734 sub_firstlnum = lnum; 3735 nmatch = vim_regexec_multi(®match, curwin, curbuf, lnum, (colnr_T)0); 3736 if (nmatch) 3737 { 3738 colnr_T copycol; 3739 colnr_T matchcol; 3740 colnr_T prev_matchcol = MAXCOL; 3741 char_u *new_end, *new_start = NULL; 3742 unsigned new_start_len = 0; 3743 char_u *p1; 3744 int did_sub = FALSE; 3745 int lastone; 3746 unsigned len, needed_len; 3747 long nmatch_tl = 0; /* nr of lines matched below lnum */ 3748 int do_again; /* do it again after joining lines */ 3749 int skip_match = FALSE; 3750 3751 /* 3752 * The new text is build up step by step, to avoid too much 3753 * copying. There are these pieces: 3754 * sub_firstline The old text, unmodifed. 3755 * copycol Column in the old text where we started 3756 * looking for a match; from here old text still 3757 * needs to be copied to the new text. 3758 * matchcol Column number of the old text where to look 3759 * for the next match. It's just after the 3760 * previous match or one further. 3761 * prev_matchcol Column just after the previous match (if any). 3762 * Mostly equal to matchcol, except for the first 3763 * match and after skipping an empty match. 3764 * regmatch.*pos Where the pattern matched in the old text. 3765 * new_start The new text, all that has been produced so 3766 * far. 3767 * new_end The new text, where to append new text. 3768 * 3769 * lnum The line number where we were looking for the 3770 * first match in the old line. 3771 * sub_firstlnum The line number in the buffer where to look 3772 * for a match. Can be different from "lnum" 3773 * when the pattern or substitute string contains 3774 * line breaks. 3775 * 3776 * Special situations: 3777 * - When the substitute string contains a line break, the part up 3778 * to the line break is inserted in the text, but the copy of 3779 * the original line is kept. "sub_firstlnum" is adjusted for 3780 * the inserted lines. 3781 * - When the matched pattern contains a line break, the old line 3782 * is taken from the line at the end of the pattern. The lines 3783 * in the match are deleted later, "sub_firstlnum" is adjusted 3784 * accordingly. 3785 * 3786 * The new text is built up in new_start[]. It has some extra 3787 * room to avoid using alloc()/free() too often. new_start_len is 3788 * the lenght of the allocated memory at new_start. 3789 * 3790 * Make a copy of the old line, so it won't be taken away when 3791 * updating the screen or handling a multi-line match. The "old_" 3792 * pointers point into this copy. 3793 */ 3794 sub_firstline = vim_strsave(ml_get(sub_firstlnum)); 3795 if (sub_firstline == NULL) 3796 { 3797 vim_free(new_start); 3798 goto outofmem; 3799 } 3800 copycol = 0; 3801 matchcol = 0; 3802 3803 /* At first match, remember current cursor position. */ 3804 if (!got_match) 3805 { 3806 setpcmark(); 3807 got_match = TRUE; 3808 } 3809 3810 /* 3811 * Loop until nothing more to replace in this line. 3812 * 1. Handle match with empty string. 3813 * 2. If do_ask is set, ask for confirmation. 3814 * 3. substitute the string. 3815 * 4. if do_all is set, find next match 3816 * 5. break if there isn't another match in this line 3817 */ 3818 for (;;) 3819 { 3820 /* Save the line number of the last change for the final 3821 * cursor position (just like Vi). */ 3822 curwin->w_cursor.lnum = lnum; 3823 do_again = FALSE; 3824 3825 /* 3826 * 1. Match empty string does not count, except for first 3827 * match. This reproduces the strange vi behaviour. 3828 * This also catches endless loops. 3829 */ 3830 if (matchcol == prev_matchcol 3831 && regmatch.endpos[0].lnum == 0 3832 && matchcol == regmatch.endpos[0].col) 3833 { 3834 if (sub_firstline[matchcol] == NUL) 3835 /* We already were at the end of the line. Don't look 3836 * for a match in this line again. */ 3837 skip_match = TRUE; 3838 else 3839 ++matchcol; /* search for a match at next column */ 3840 goto skip; 3841 } 3842 3843 /* Normally we continue searching for a match just after the 3844 * previous match. */ 3845 matchcol = regmatch.endpos[0].col; 3846 prev_matchcol = matchcol; 3847 3848 /* 3849 * 2. If do_ask is set, ask for confirmation. 3850 */ 3851 if (do_ask) 3852 { 3853 /* change State to CONFIRM, so that the mouse works 3854 * properly */ 3855 save_State = State; 3856 State = CONFIRM; 3857 #ifdef FEAT_MOUSE 3858 setmouse(); /* disable mouse in xterm */ 3859 #endif 3860 curwin->w_cursor.col = regmatch.startpos[0].col; 3861 3862 /* When 'cpoptions' contains "u" don't sync undo when 3863 * asking for confirmation. */ 3864 if (vim_strchr(p_cpo, CPO_UNDO) != NULL) 3865 ++no_u_sync; 3866 3867 /* 3868 * Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed. 3869 */ 3870 while (do_ask) 3871 { 3872 #ifdef FEAT_FOLDING 3873 int save_p_fen = curwin->w_p_fen; 3874 3875 curwin->w_p_fen = FALSE; 3876 #endif 3877 /* Invert the matched string. 3878 * Remove the inversion afterwards. */ 3879 temp = RedrawingDisabled; 3880 RedrawingDisabled = 0; 3881 3882 search_match_lines = regmatch.endpos[0].lnum; 3883 search_match_endcol = regmatch.endpos[0].col; 3884 highlight_match = TRUE; 3885 3886 update_topline(); 3887 validate_cursor(); 3888 update_screen(NOT_VALID); 3889 highlight_match = FALSE; 3890 redraw_later(NOT_VALID); 3891 3892 #ifdef FEAT_FOLDING 3893 curwin->w_p_fen = save_p_fen; 3894 #endif 3895 if (msg_row == Rows - 1) 3896 msg_didout = FALSE; /* avoid a scroll-up */ 3897 msg_starthere(); 3898 i = msg_scroll; 3899 msg_scroll = 0; /* truncate msg when needed */ 3900 msg_no_more = TRUE; 3901 /* write message same highlighting as for wait_return */ 3902 smsg_attr(hl_attr(HLF_R), 3903 (char_u *)_("replace with %s (y/n/a/q/l/^E/^Y)?"), 3904 sub); 3905 msg_no_more = FALSE; 3906 msg_scroll = i; 3907 showruler(TRUE); 3908 windgoto(msg_row, msg_col); 3909 RedrawingDisabled = temp; 3910 3911 #ifdef USE_ON_FLY_SCROLL 3912 dont_scroll = FALSE; /* allow scrolling here */ 3913 #endif 3914 ++no_mapping; /* don't map this key */ 3915 ++allow_keys; /* allow special keys */ 3916 i = safe_vgetc(); 3917 --allow_keys; 3918 --no_mapping; 3919 3920 /* clear the question */ 3921 msg_didout = FALSE; /* don't scroll up */ 3922 msg_col = 0; 3923 gotocmdline(TRUE); 3924 need_wait_return = FALSE; /* no hit-return prompt */ 3925 if (i == 'q' || i == ESC || i == Ctrl_C 3926 #ifdef UNIX 3927 || i == intr_char 3928 #endif 3929 ) 3930 { 3931 got_quit = TRUE; 3932 break; 3933 } 3934 if (i == 'n') 3935 break; 3936 if (i == 'y') 3937 break; 3938 if (i == 'l') 3939 { 3940 /* last: replace and then stop */ 3941 do_all = FALSE; 3942 line2 = lnum; 3943 break; 3944 } 3945 if (i == 'a') 3946 { 3947 do_ask = FALSE; 3948 break; 3949 } 3950 #ifdef FEAT_INS_EXPAND 3951 if (i == Ctrl_E) 3952 scrollup_clamp(); 3953 else if (i == Ctrl_Y) 3954 scrolldown_clamp(); 3955 #endif 3956 } 3957 State = save_State; 3958 #ifdef FEAT_MOUSE 3959 setmouse(); 3960 #endif 3961 if (vim_strchr(p_cpo, CPO_UNDO) != NULL) 3962 --no_u_sync; 3963 3964 if (i == 'n') 3965 { 3966 /* For a multi-line match, put matchcol at the NUL at 3967 * the end of the line and set nmatch to one, so that 3968 * we continue looking for a match on the next line. 3969 * Avoids that ":s/\nB\@=//gc" get stuck. */ 3970 if (nmatch > 1) 3971 { 3972 matchcol = STRLEN(sub_firstline); 3973 nmatch = 1; 3974 } 3975 goto skip; 3976 } 3977 if (got_quit) 3978 break; 3979 } 3980 3981 /* Move the cursor to the start of the match, so that we can 3982 * use "\=col("."). */ 3983 curwin->w_cursor.col = regmatch.startpos[0].col; 3984 3985 /* 3986 * 3. substitute the string. 3987 */ 3988 /* get length of substitution part */ 3989 sublen = vim_regsub_multi(®match, sub_firstlnum, 3990 sub, sub_firstline, FALSE, p_magic, TRUE); 3991 3992 /* Need room for: 3993 * - result so far in new_start (not for first sub in line) 3994 * - original text up to match 3995 * - length of substituted part 3996 * - original text after match 3997 */ 3998 if (nmatch == 1) 3999 p1 = sub_firstline; 4000 else 4001 { 4002 p1 = ml_get(sub_firstlnum + nmatch - 1); 4003 nmatch_tl += nmatch - 1; 4004 } 4005 i = regmatch.startpos[0].col - copycol; 4006 needed_len = i + ((unsigned)STRLEN(p1) - regmatch.endpos[0].col) 4007 + sublen + 1; 4008 if (new_start == NULL) 4009 { 4010 /* 4011 * Get some space for a temporary buffer to do the 4012 * substitution into (and some extra space to avoid 4013 * too many calls to alloc()/free()). 4014 */ 4015 new_start_len = needed_len + 50; 4016 if ((new_start = alloc_check(new_start_len)) == NULL) 4017 goto outofmem; 4018 *new_start = NUL; 4019 new_end = new_start; 4020 } 4021 else 4022 { 4023 /* 4024 * Check if the temporary buffer is long enough to do the 4025 * substitution into. If not, make it larger (with a bit 4026 * extra to avoid too many calls to alloc()/free()). 4027 */ 4028 len = (unsigned)STRLEN(new_start); 4029 needed_len += len; 4030 if (needed_len > new_start_len) 4031 { 4032 new_start_len = needed_len + 50; 4033 if ((p1 = alloc_check(new_start_len)) == NULL) 4034 { 4035 vim_free(new_start); 4036 goto outofmem; 4037 } 4038 mch_memmove(p1, new_start, (size_t)(len + 1)); 4039 vim_free(new_start); 4040 new_start = p1; 4041 } 4042 new_end = new_start + len; 4043 } 4044 4045 /* 4046 * copy the text up to the part that matched 4047 */ 4048 mch_memmove(new_end, sub_firstline + copycol, (size_t)i); 4049 new_end += i; 4050 4051 (void)vim_regsub_multi(®match, sub_firstlnum, 4052 sub, new_end, TRUE, p_magic, TRUE); 4053 sub_nsubs++; 4054 did_sub = TRUE; 4055 4056 /* Move the cursor to the start of the line, to avoid that it 4057 * is beyond the end of the line after the substitution. */ 4058 curwin->w_cursor.col = 0; 4059 4060 /* For a multi-line match, make a copy of the last matched 4061 * line and continue in that one. */ 4062 if (nmatch > 1) 4063 { 4064 sub_firstlnum += nmatch - 1; 4065 vim_free(sub_firstline); 4066 sub_firstline = vim_strsave(ml_get(sub_firstlnum)); 4067 /* When going beyond the last line, stop substituting. */ 4068 if (sub_firstlnum <= line2) 4069 do_again = TRUE; 4070 else 4071 do_all = FALSE; 4072 } 4073 4074 /* Remember next character to be copied. */ 4075 copycol = regmatch.endpos[0].col; 4076 4077 /* 4078 * Now the trick is to replace CTRL-M chars with a real line 4079 * break. This would make it impossible to insert a CTRL-M in 4080 * the text. The line break can be avoided by preceding the 4081 * CTRL-M with a backslash. To be able to insert a backslash, 4082 * they must be doubled in the string and are halved here. 4083 * That is Vi compatible. 4084 */ 4085 for (p1 = new_end; *p1; ++p1) 4086 { 4087 if (p1[0] == '\\' && p1[1] != NUL) /* remove backslash */ 4088 mch_memmove(p1, p1 + 1, STRLEN(p1)); 4089 else if (*p1 == CAR) 4090 { 4091 if (u_inssub(lnum) == OK) /* prepare for undo */ 4092 { 4093 *p1 = NUL; /* truncate up to the CR */ 4094 ml_append(lnum - 1, new_start, 4095 (colnr_T)(p1 - new_start + 1), FALSE); 4096 mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L); 4097 if (do_ask) 4098 appended_lines(lnum - 1, 1L); 4099 else 4100 { 4101 if (first_line == 0) 4102 first_line = lnum; 4103 last_line = lnum + 1; 4104 } 4105 /* All line numbers increase. */ 4106 ++sub_firstlnum; 4107 ++lnum; 4108 ++line2; 4109 /* move the cursor to the new line, like Vi */ 4110 ++curwin->w_cursor.lnum; 4111 STRCPY(new_start, p1 + 1); /* copy the rest */ 4112 p1 = new_start - 1; 4113 } 4114 } 4115 #ifdef FEAT_MBYTE 4116 else if (has_mbyte) 4117 p1 += (*mb_ptr2len_check)(p1) - 1; 4118 #endif 4119 } 4120 4121 /* 4122 * 4. If do_all is set, find next match. 4123 * Prevent endless loop with patterns that match empty 4124 * strings, e.g. :s/$/pat/g or :s/[a-z]* /(&)/g. 4125 * But ":s/\n/#/" is OK. 4126 */ 4127 skip: 4128 /* We already know that we did the last subst when we are at 4129 * the end of the line, except that a pattern like 4130 * "bar\|\nfoo" may match at the NUL. */ 4131 lastone = (skip_match 4132 || got_int 4133 || got_quit 4134 || !(do_all || do_again) 4135 || (sub_firstline[matchcol] == NUL && nmatch <= 1 4136 && !re_multiline(regmatch.regprog))); 4137 nmatch = -1; 4138 4139 /* 4140 * Replace the line in the buffer when needed. This is 4141 * skipped when there are more matches. 4142 * The check for nmatch_tl is needed for when multi-line 4143 * matching must replace the lines before trying to do another 4144 * match, otherwise "\@<=" won't work. 4145 * When asking the user we like to show the already replaced 4146 * text, but don't do it when "\<@=" or "\<@!" is used, it 4147 * changes what matches. 4148 */ 4149 if (lastone 4150 || (do_ask && !re_lookbehind(regmatch.regprog)) 4151 || nmatch_tl > 0 4152 || (nmatch = vim_regexec_multi(®match, curwin, 4153 curbuf, sub_firstlnum, matchcol)) == 0) 4154 { 4155 if (new_start != NULL) 4156 { 4157 /* 4158 * Copy the rest of the line, that didn't match. 4159 * "matchcol" has to be adjusted, we use the end of 4160 * the line as reference, because the substitute may 4161 * have changed the number of characters. Same for 4162 * "prev_matchcol". 4163 */ 4164 STRCAT(new_start, sub_firstline + copycol); 4165 matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol; 4166 prev_matchcol = (colnr_T)STRLEN(sub_firstline) 4167 - prev_matchcol; 4168 4169 if (u_savesub(lnum) != OK) 4170 break; 4171 ml_replace(lnum, new_start, TRUE); 4172 4173 if (nmatch_tl > 0) 4174 { 4175 /* 4176 * Matched lines have now been substituted and are 4177 * useless, delete them. The part after the match 4178 * has been appended to new_start, we don't need 4179 * it in the buffer. 4180 */ 4181 ++lnum; 4182 if (u_savedel(lnum, nmatch_tl) != OK) 4183 break; 4184 for (i = 0; i < nmatch_tl; ++i) 4185 ml_delete(lnum, (int)FALSE); 4186 mark_adjust(lnum, lnum + nmatch_tl - 1, 4187 (long)MAXLNUM, -nmatch_tl); 4188 if (do_ask) 4189 deleted_lines(lnum, nmatch_tl); 4190 --lnum; 4191 line2 -= nmatch_tl; /* nr of lines decreases */ 4192 nmatch_tl = 0; 4193 } 4194 4195 /* When asking, undo is saved each time, must also set 4196 * changed flag each time. */ 4197 if (do_ask) 4198 changed_bytes(lnum, 0); 4199 else 4200 { 4201 if (first_line == 0) 4202 first_line = lnum; 4203 last_line = lnum + 1; 4204 } 4205 4206 sub_firstlnum = lnum; 4207 vim_free(sub_firstline); /* free the temp buffer */ 4208 sub_firstline = new_start; 4209 new_start = NULL; 4210 matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol; 4211 prev_matchcol = (colnr_T)STRLEN(sub_firstline) 4212 - prev_matchcol; 4213 copycol = 0; 4214 } 4215 if (nmatch == -1 && !lastone) 4216 nmatch = vim_regexec_multi(®match, curwin, curbuf, 4217 sub_firstlnum, matchcol); 4218 4219 /* 4220 * 5. break if there isn't another match in this line 4221 */ 4222 if (nmatch <= 0) 4223 break; 4224 } 4225 4226 line_breakcheck(); 4227 } 4228 4229 if (did_sub) 4230 ++sub_nlines; 4231 vim_free(sub_firstline); /* free the copy of the original line */ 4232 sub_firstline = NULL; 4233 } 4234 4235 line_breakcheck(); 4236 } 4237 4238 if (first_line != 0) 4239 { 4240 /* Need to subtract the number of added lines from "last_line" to get 4241 * the line number before the change (same as adding the number of 4242 * deleted lines). */ 4243 i = curbuf->b_ml.ml_line_count - old_line_count; 4244 changed_lines(first_line, 0, last_line - i, i); 4245 } 4246 4247 outofmem: 4248 vim_free(sub_firstline); /* may have to free allocated copy of the line */ 4249 if (sub_nsubs) 4250 { 4251 /* Set the '[ and '] marks. */ 4252 curbuf->b_op_start.lnum = eap->line1; 4253 curbuf->b_op_end.lnum = line2; 4254 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 4255 4256 if (!global_busy) 4257 { 4258 beginline(BL_WHITE | BL_FIX); 4259 if (!do_sub_msg() && do_ask) 4260 MSG(""); 4261 } 4262 else 4263 global_need_beginline = TRUE; 4264 if (do_print) 4265 print_line(curwin->w_cursor.lnum, FALSE); 4266 } 4267 else if (!global_busy) 4268 { 4269 if (got_int) /* interrupted */ 4270 EMSG(_(e_interr)); 4271 else if (got_match) /* did find something but nothing substituted */ 4272 MSG(""); 4273 else if (do_error) /* nothing found */ 4274 EMSG2(_(e_patnotf2), get_search_pat()); 4275 } 4276 4277 vim_free(regmatch.regprog); 4278 } 4279 4280 /* 4281 * Give message for number of substitutions. 4282 * Can also be used after a ":global" command. 4283 * Return TRUE if a message was given. 4284 */ 4285 static int 4286 do_sub_msg() 4287 { 4288 /* 4289 * Only report substitutions when: 4290 * - more than 'report' substitutions 4291 * - command was typed by user, or number of changed lines > 'report' 4292 * - giving messages is not disabled by 'lazyredraw' 4293 */ 4294 if (sub_nsubs > p_report 4295 && (KeyTyped || sub_nlines > 1 || p_report < 1) 4296 && messaging()) 4297 { 4298 if (got_int) 4299 STRCPY(msg_buf, _("(Interrupted) ")); 4300 else 4301 msg_buf[0] = NUL; 4302 if (sub_nsubs == 1) 4303 STRCAT(msg_buf, _("1 substitution")); 4304 else 4305 sprintf((char *)msg_buf + STRLEN(msg_buf), _("%ld substitutions"), 4306 sub_nsubs); 4307 if (sub_nlines == 1) 4308 STRCAT(msg_buf, _(" on 1 line")); 4309 else 4310 sprintf((char *)msg_buf + STRLEN(msg_buf), _(" on %ld lines"), 4311 (long)sub_nlines); 4312 if (msg(msg_buf)) 4313 { 4314 /* save message to display it after redraw */ 4315 set_keep_msg(msg_buf); 4316 keep_msg_attr = 0; 4317 } 4318 return TRUE; 4319 } 4320 if (got_int) 4321 { 4322 EMSG(_(e_interr)); 4323 return TRUE; 4324 } 4325 return FALSE; 4326 } 4327 4328 /* 4329 * Execute a global command of the form: 4330 * 4331 * g/pattern/X : execute X on all lines where pattern matches 4332 * v/pattern/X : execute X on all lines where pattern does not match 4333 * 4334 * where 'X' is an EX command 4335 * 4336 * The command character (as well as the trailing slash) is optional, and 4337 * is assumed to be 'p' if missing. 4338 * 4339 * This is implemented in two passes: first we scan the file for the pattern and 4340 * set a mark for each line that (not) matches. secondly we execute the command 4341 * for each line that has a mark. This is required because after deleting 4342 * lines we do not know where to search for the next match. 4343 */ 4344 void 4345 ex_global(eap) 4346 exarg_T *eap; 4347 { 4348 linenr_T lnum; /* line number according to old situation */ 4349 int ndone; 4350 int type; /* first char of cmd: 'v' or 'g' */ 4351 char_u *cmd; /* command argument */ 4352 4353 char_u delim; /* delimiter, normally '/' */ 4354 char_u *pat; 4355 regmmatch_T regmatch; 4356 int match; 4357 int which_pat; 4358 4359 if (global_busy) 4360 { 4361 EMSG(_("E147: Cannot do :global recursive")); /* will increment global_busy */ 4362 return; 4363 } 4364 4365 if (eap->forceit) /* ":global!" is like ":vglobal" */ 4366 type = 'v'; 4367 else 4368 type = *eap->cmd; 4369 cmd = eap->arg; 4370 which_pat = RE_LAST; /* default: use last used regexp */ 4371 sub_nsubs = 0; 4372 sub_nlines = 0; 4373 4374 /* 4375 * undocumented vi feature: 4376 * "\/" and "\?": use previous search pattern. 4377 * "\&": use previous substitute pattern. 4378 */ 4379 if (*cmd == '\\') 4380 { 4381 ++cmd; 4382 if (vim_strchr((char_u *)"/?&", *cmd) == NULL) 4383 { 4384 EMSG(_(e_backslash)); 4385 return; 4386 } 4387 if (*cmd == '&') 4388 which_pat = RE_SUBST; /* use previous substitute pattern */ 4389 else 4390 which_pat = RE_SEARCH; /* use previous search pattern */ 4391 ++cmd; 4392 pat = (char_u *)""; 4393 } 4394 else if (*cmd == NUL) 4395 { 4396 EMSG(_("E148: Regular expression missing from global")); 4397 return; 4398 } 4399 else 4400 { 4401 delim = *cmd; /* get the delimiter */ 4402 if (delim) 4403 ++cmd; /* skip delimiter if there is one */ 4404 pat = cmd; /* remember start of pattern */ 4405 cmd = skip_regexp(cmd, delim, p_magic, &eap->arg); 4406 if (cmd[0] == delim) /* end delimiter found */ 4407 *cmd++ = NUL; /* replace it with a NUL */ 4408 } 4409 4410 #ifdef FEAT_FKMAP /* when in Farsi mode, reverse the character flow */ 4411 if (p_altkeymap && curwin->w_p_rl) 4412 lrFswap(pat,0); 4413 #endif 4414 4415 if (search_regcomp(pat, RE_BOTH, which_pat, SEARCH_HIS, ®match) == FAIL) 4416 { 4417 EMSG(_(e_invcmd)); 4418 return; 4419 } 4420 4421 /* 4422 * pass 1: set marks for each (not) matching line 4423 */ 4424 ndone = 0; 4425 for (lnum = eap->line1; lnum <= eap->line2 && !got_int; ++lnum) 4426 { 4427 /* a match on this line? */ 4428 match = vim_regexec_multi(®match, curwin, curbuf, lnum, (colnr_T)0); 4429 if ((type == 'g' && match) || (type == 'v' && !match)) 4430 { 4431 ml_setmarked(lnum); 4432 ndone++; 4433 } 4434 line_breakcheck(); 4435 } 4436 4437 /* 4438 * pass 2: execute the command for each line that has been marked 4439 */ 4440 if (got_int) 4441 MSG(_(e_interr)); 4442 else if (ndone == 0) 4443 { 4444 if (type == 'v') 4445 msg_str((char_u *)_("Pattern found in every line: %s"), pat); 4446 else 4447 msg_str((char_u *)_(e_patnotf2), pat); 4448 } 4449 else 4450 global_exe(cmd); 4451 4452 ml_clearmarked(); /* clear rest of the marks */ 4453 vim_free(regmatch.regprog); 4454 } 4455 4456 /* 4457 * Execute "cmd" on lines marked with ml_setmarked(). 4458 */ 4459 void 4460 global_exe(cmd) 4461 char_u *cmd; 4462 { 4463 linenr_T old_lcount; /* b_ml.ml_line_count before the command */ 4464 linenr_T lnum; /* line number according to old situation */ 4465 4466 /* 4467 * Set current position only once for a global command. 4468 * If global_busy is set, setpcmark() will not do anything. 4469 * If there is an error, global_busy will be incremented. 4470 */ 4471 setpcmark(); 4472 4473 /* When the command writes a message, don't overwrite the command. */ 4474 msg_didout = TRUE; 4475 4476 global_need_beginline = FALSE; 4477 global_busy = 1; 4478 old_lcount = curbuf->b_ml.ml_line_count; 4479 while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1) 4480 { 4481 curwin->w_cursor.lnum = lnum; 4482 curwin->w_cursor.col = 0; 4483 if (*cmd == NUL || *cmd == '\n') 4484 do_cmdline((char_u *)"p", NULL, NULL, DOCMD_NOWAIT); 4485 else 4486 do_cmdline(cmd, NULL, NULL, DOCMD_NOWAIT); 4487 ui_breakcheck(); 4488 } 4489 4490 global_busy = 0; 4491 if (global_need_beginline) 4492 beginline(BL_WHITE | BL_FIX); 4493 else 4494 check_cursor(); /* cursor may be beyond the end of the line */ 4495 4496 /* If it looks like no message was written, allow overwriting the 4497 * command with the report for number of changes. */ 4498 if (msg_col == 0 && msg_scrolled == 0) 4499 msg_didout = FALSE; 4500 4501 /* If subsitutes done, report number of substitues, otherwise report 4502 * number of extra or deleted lines. */ 4503 if (!do_sub_msg()) 4504 msgmore(curbuf->b_ml.ml_line_count - old_lcount); 4505 } 4506 4507 #ifdef FEAT_VIMINFO 4508 int 4509 read_viminfo_sub_string(virp, force) 4510 vir_T *virp; 4511 int force; 4512 { 4513 if (old_sub != NULL && force) 4514 vim_free(old_sub); 4515 if (force || old_sub == NULL) 4516 old_sub = viminfo_readstring(virp, 1, TRUE); 4517 return viminfo_readline(virp); 4518 } 4519 4520 void 4521 write_viminfo_sub_string(fp) 4522 FILE *fp; 4523 { 4524 if (get_viminfo_parameter('/') != 0 && old_sub != NULL) 4525 { 4526 fprintf(fp, _("\n# Last Substitute String:\n$")); 4527 viminfo_writestring(fp, old_sub); 4528 } 4529 } 4530 #endif /* FEAT_VIMINFO */ 4531 4532 #if (defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)) || defined(PROTO) 4533 /* 4534 * Set up for a tagpreview. 4535 */ 4536 void 4537 prepare_tagpreview() 4538 { 4539 win_T *wp; 4540 4541 # ifdef FEAT_GUI 4542 need_mouse_correct = TRUE; 4543 # endif 4544 4545 /* 4546 * If there is already a preview window open, use that one. 4547 */ 4548 if (!curwin->w_p_pvw) 4549 { 4550 for (wp = firstwin; wp != NULL; wp = wp->w_next) 4551 if (wp->w_p_pvw) 4552 break; 4553 if (wp != NULL) 4554 win_enter(wp, TRUE); 4555 else 4556 { 4557 /* 4558 * There is no preview window open yet. Create one. 4559 */ 4560 if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0) 4561 == FAIL) 4562 return; 4563 curwin->w_p_pvw = TRUE; 4564 curwin->w_p_wfh = TRUE; 4565 # ifdef FEAT_SCROLLBIND 4566 curwin->w_p_scb = FALSE; /* don't take over 'scrollbind' */ 4567 # endif 4568 # ifdef FEAT_DIFF 4569 curwin->w_p_diff = FALSE; /* no 'diff' */ 4570 # endif 4571 # ifdef FEAT_FOLDING 4572 curwin->w_p_fdc = 0; /* no 'foldcolumn' */ 4573 # endif 4574 } 4575 } 4576 } 4577 4578 #endif 4579 4580 4581 /* 4582 * ":help": open a read-only window on a help file 4583 */ 4584 void 4585 ex_help(eap) 4586 exarg_T *eap; 4587 { 4588 char_u *arg; 4589 char_u *tag; 4590 FILE *helpfd; /* file descriptor of help file */ 4591 int n; 4592 int i; 4593 #ifdef FEAT_WINDOWS 4594 win_T *wp; 4595 #endif 4596 int num_matches; 4597 char_u **matches; 4598 char_u *p; 4599 int empty_fnum = 0; 4600 int alt_fnum = 0; 4601 buf_T *buf; 4602 #ifdef FEAT_MULTI_LANG 4603 int len; 4604 char_u *lang; 4605 #endif 4606 4607 if (eap != NULL) 4608 { 4609 /* 4610 * A ":help" command ends at the first LF, or at a '|' that is 4611 * followed by some text. Set nextcmd to the following command. 4612 */ 4613 for (arg = eap->arg; *arg; ++arg) 4614 { 4615 if (*arg == '\n' || *arg == '\r' 4616 || (*arg == '|' && arg[1] != NUL && arg[1] != '|')) 4617 { 4618 *arg++ = NUL; 4619 eap->nextcmd = arg; 4620 break; 4621 } 4622 } 4623 arg = eap->arg; 4624 4625 if (eap->forceit && *arg == NUL) 4626 { 4627 EMSG(_("E478: Don't panic!")); 4628 return; 4629 } 4630 4631 if (eap->skip) /* not executing commands */ 4632 return; 4633 } 4634 else 4635 arg = (char_u *)""; 4636 4637 /* remove trailing blanks */ 4638 p = arg + STRLEN(arg) - 1; 4639 while (p > arg && vim_iswhite(*p) && p[-1] != '\\') 4640 *p-- = NUL; 4641 4642 #ifdef FEAT_MULTI_LANG 4643 /* Check for a specified language */ 4644 lang = check_help_lang(arg); 4645 #endif 4646 4647 /* When no argument given go to the index. */ 4648 if (*arg == NUL) 4649 arg = (char_u *)"help.txt"; 4650 4651 /* 4652 * Check if there is a match for the argument. 4653 */ 4654 n = find_help_tags(arg, &num_matches, &matches, 4655 eap != NULL && eap->forceit); 4656 4657 i = 0; 4658 #ifdef FEAT_MULTI_LANG 4659 if (n != FAIL && lang != NULL) 4660 /* Find first item with the requested language. */ 4661 for (i = 0; i < num_matches; ++i) 4662 { 4663 len = STRLEN(matches[i]); 4664 if (len > 3 && matches[i][len - 3] == '@' 4665 && STRICMP(matches[i] + len - 2, lang) == 0) 4666 break; 4667 } 4668 #endif 4669 if (i >= num_matches || n == FAIL) 4670 { 4671 #ifdef FEAT_MULTI_LANG 4672 if (lang != NULL) 4673 EMSG3(_("E661: Sorry, no '%s' help for %s"), lang, arg); 4674 else 4675 #endif 4676 EMSG2(_("E149: Sorry, no help for %s"), arg); 4677 if (n != FAIL) 4678 FreeWild(num_matches, matches); 4679 return; 4680 } 4681 4682 /* The first match (in the requested language) is the best match. */ 4683 tag = vim_strsave(matches[i]); 4684 FreeWild(num_matches, matches); 4685 4686 #ifdef FEAT_GUI 4687 need_mouse_correct = TRUE; 4688 #endif 4689 4690 /* 4691 * Re-use an existing help window or open a new one. 4692 */ 4693 if (!curwin->w_buffer->b_help) 4694 { 4695 #ifdef FEAT_WINDOWS 4696 for (wp = firstwin; wp != NULL; wp = wp->w_next) 4697 if (wp->w_buffer != NULL && wp->w_buffer->b_help) 4698 break; 4699 if (wp != NULL && wp->w_buffer->b_nwindows > 0) 4700 win_enter(wp, TRUE); 4701 else 4702 #endif 4703 { 4704 /* 4705 * There is no help window yet. 4706 * Try to open the file specified by the "helpfile" option. 4707 */ 4708 if ((helpfd = mch_fopen((char *)p_hf, READBIN)) == NULL) 4709 { 4710 msg_str((char_u *)_("Sorry, help file \"%s\" not found"), 4711 p_hf); 4712 goto erret; 4713 } 4714 fclose(helpfd); 4715 4716 #ifdef FEAT_WINDOWS 4717 /* Split off help window; put it at far top if no position 4718 * specified, the current window is vertically split and narrow. */ 4719 n = WSP_HELP; 4720 # ifdef FEAT_VERTSPLIT 4721 if (cmdmod.split == 0 && curwin->w_width != Columns 4722 && curwin->w_width < 80) 4723 n |= WSP_TOP; 4724 # endif 4725 if (win_split(0, n) == FAIL) 4726 #else 4727 /* use current window */ 4728 if (!can_abandon(curbuf, FALSE)) 4729 #endif 4730 goto erret; 4731 4732 #ifdef FEAT_WINDOWS 4733 if (curwin->w_height < p_hh) 4734 win_setheight((int)p_hh); 4735 #endif 4736 4737 /* 4738 * Open help file (do_ecmd() will set b_help flag, readfile() will 4739 * set b_p_ro flag). 4740 * Set the alternate file to the previously edited file. 4741 */ 4742 alt_fnum = curbuf->b_fnum; 4743 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_LASTL, 4744 ECMD_HIDE + ECMD_SET_HELP); 4745 if (!cmdmod.keepalt) 4746 curwin->w_alt_fnum = alt_fnum; 4747 empty_fnum = curbuf->b_fnum; 4748 } 4749 } 4750 4751 if (!p_im) 4752 restart_edit = 0; /* don't want insert mode in help file */ 4753 4754 if (tag != NULL) 4755 do_tag(tag, DT_HELP, 1, FALSE, TRUE); 4756 4757 /* Delete the empty buffer if we're not using it. */ 4758 if (empty_fnum != 0 && curbuf->b_fnum != empty_fnum) 4759 { 4760 buf = buflist_findnr(empty_fnum); 4761 if (buf != NULL) 4762 wipe_buffer(buf, TRUE); 4763 } 4764 4765 /* keep the previous alternate file */ 4766 if (alt_fnum != 0 && curwin->w_alt_fnum == empty_fnum && !cmdmod.keepalt) 4767 curwin->w_alt_fnum = alt_fnum; 4768 4769 erret: 4770 vim_free(tag); 4771 } 4772 4773 4774 #if defined(FEAT_MULTI_LANG) || defined(PROTO) 4775 /* 4776 * In an argument search for a language specifiers in the form "@xx". 4777 * Changes the "@" to NUL if found, and returns a pointer to "xx". 4778 * Returns NULL if not found. 4779 */ 4780 char_u * 4781 check_help_lang(arg) 4782 char_u *arg; 4783 { 4784 int len = STRLEN(arg); 4785 4786 if (len >= 3 && arg[len - 3] == '@' && ASCII_ISALPHA(arg[len - 2]) 4787 && ASCII_ISALPHA(arg[len - 1])) 4788 { 4789 arg[len - 3] = NUL; /* remove the '@' */ 4790 return arg + len - 2; 4791 } 4792 return NULL; 4793 } 4794 #endif 4795 4796 /* 4797 * Return a heuristic indicating how well the given string matches. The 4798 * smaller the number, the better the match. This is the order of priorities, 4799 * from best match to worst match: 4800 * - Match with least alpha-numeric characters is better. 4801 * - Match with least total characters is better. 4802 * - Match towards the start is better. 4803 * - Match starting with "+" is worse (feature instead of command) 4804 * Assumption is made that the matched_string passed has already been found to 4805 * match some string for which help is requested. webb. 4806 */ 4807 int 4808 help_heuristic(matched_string, offset, wrong_case) 4809 char_u *matched_string; 4810 int offset; /* offset for match */ 4811 int wrong_case; /* no matching case */ 4812 { 4813 int num_letters; 4814 char_u *p; 4815 4816 num_letters = 0; 4817 for (p = matched_string; *p; p++) 4818 if (ASCII_ISALNUM(*p)) 4819 num_letters++; 4820 4821 /* 4822 * Multiply the number of letters by 100 to give it a much bigger 4823 * weighting than the number of characters. 4824 * If there only is a match while ignoring case, add 5000. 4825 * If the match starts in the middle of a word, add 10000 to put it 4826 * somewhere in the last half. 4827 * If the match is more than 2 chars from the start, multiply by 200 to 4828 * put it after matches at the start. 4829 */ 4830 if (ASCII_ISALNUM(matched_string[offset]) && offset > 0 4831 && ASCII_ISALNUM(matched_string[offset - 1])) 4832 offset += 10000; 4833 else if (offset > 2) 4834 offset *= 200; 4835 if (wrong_case) 4836 offset += 5000; 4837 /* Features are less interesting than the subjects themselves, but "+" 4838 * alone is not a feature. */ 4839 if (matched_string[0] == '+' && matched_string[1] != NUL) 4840 offset += 100; 4841 return (int)(100 * num_letters + STRLEN(matched_string) + offset); 4842 } 4843 4844 /* 4845 * Compare functions for qsort() below, that checks the help heuristics number 4846 * that has been put after the tagname by find_tags(). 4847 */ 4848 static int 4849 #ifdef __BORLANDC__ 4850 _RTLENTRYF 4851 #endif 4852 help_compare(s1, s2) 4853 const void *s1; 4854 const void *s2; 4855 { 4856 char *p1; 4857 char *p2; 4858 4859 p1 = *(char **)s1 + strlen(*(char **)s1) + 1; 4860 p2 = *(char **)s2 + strlen(*(char **)s2) + 1; 4861 return strcmp(p1, p2); 4862 } 4863 4864 /* 4865 * Find all help tags matching "arg", sort them and return in matches[], with 4866 * the number of matches in num_matches. 4867 * The matches will be sorted with a "best" match algorithm. 4868 * When "keep_lang" is TRUE try keeping the language of the current buffer. 4869 */ 4870 int 4871 find_help_tags(arg, num_matches, matches, keep_lang) 4872 char_u *arg; 4873 int *num_matches; 4874 char_u ***matches; 4875 int keep_lang; 4876 { 4877 char_u *s, *d; 4878 int i; 4879 static char *(mtable[]) = {"*", "g*", "[*", "]*", ":*", 4880 "/*", "/\\*", "\"*", "/\\(\\)", 4881 "?", ":?", "?<CR>", "g?", "g?g?", "g??", 4882 "/\\?", "/\\z(\\)", 4883 "[count]", "[quotex]", "[range]", 4884 "[pattern]", "\\|", "\\%$"}; 4885 static char *(rtable[]) = {"star", "gstar", "[star", "]star", ":star", 4886 "/star", "/\\\\star", "quotestar", "/\\\\(\\\\)", 4887 "?", ":?", "?<CR>", "g?", "g?g?", "g??", 4888 "/\\\\?", "/\\\\z(\\\\)", 4889 "\\[count]", "\\[quotex]", "\\[range]", 4890 "\\[pattern]", "\\\\bar", "/\\\\%\\$"}; 4891 int flags; 4892 4893 d = IObuff; /* assume IObuff is long enough! */ 4894 4895 /* 4896 * Recognize a few exceptions to the rule. Some strings that contain '*' 4897 * with "star". Otherwise '*' is recognized as a wildcard. 4898 */ 4899 for (i = sizeof(mtable) / sizeof(char *); --i >= 0; ) 4900 if (STRCMP(arg, mtable[i]) == 0) 4901 { 4902 STRCPY(d, rtable[i]); 4903 break; 4904 } 4905 4906 if (i < 0) /* no match in table */ 4907 { 4908 /* Replace "\S" with "/\\S", etc. Otherwise every tag is matched. 4909 * Also replace "\%^" and "\%(", they match every tag too. 4910 * Also "\zs", "\z1", etc. 4911 * Also "\@<", "\@=", "\@<=", etc. 4912 * And also "\_$" and "\_^". */ 4913 if (arg[0] == '\\' 4914 && ((arg[1] != NUL && arg[2] == NUL) 4915 || (vim_strchr((char_u *)"%_z@", arg[1]) != NULL 4916 && arg[2] != NUL))) 4917 { 4918 STRCPY(d, "/\\\\"); 4919 STRCPY(d + 3, arg + 1); 4920 /* Check for "/\\_$", should be "/\\_\$" */ 4921 if (d[3] == '_' && d[4] == '$') 4922 STRCPY(d + 4, "\\$"); 4923 } 4924 else 4925 { 4926 /* replace "[:...:]" with "\[:...:]"; "[+...]" with "\[++...]" */ 4927 if (arg[0] == '[' && (arg[1] == ':' 4928 || (arg[1] == '+' && arg[2] == '+'))) 4929 *d++ = '\\'; 4930 4931 for (s = arg; *s; ++s) 4932 { 4933 /* 4934 * Replace "|" with "bar" and '"' with "quote" to match the name of 4935 * the tags for these commands. 4936 * Replace "*" with ".*" and "?" with "." to match command line 4937 * completion. 4938 * Insert a backslash before '~', '$' and '.' to avoid their 4939 * special meaning. 4940 */ 4941 if (d - IObuff > IOSIZE - 10) /* getting too long!? */ 4942 break; 4943 switch (*s) 4944 { 4945 case '|': STRCPY(d, "bar"); 4946 d += 3; 4947 continue; 4948 case '"': STRCPY(d, "quote"); 4949 d += 5; 4950 continue; 4951 case '*': *d++ = '.'; 4952 break; 4953 case '?': *d++ = '.'; 4954 continue; 4955 case '$': 4956 case '.': 4957 case '~': *d++ = '\\'; 4958 break; 4959 } 4960 4961 /* 4962 * Replace "^x" by "CTRL-X". Don't do this for "^_" to make 4963 * ":help i_^_CTRL-D" work. 4964 * Insert '-' before and after "CTRL-X" when applicable. 4965 */ 4966 if (*s < ' ' || (*s == '^' && s[1] && (ASCII_ISALPHA(s[1]) 4967 || vim_strchr((char_u *)"?@[\\]^", s[1]) != NULL))) 4968 { 4969 if (d > IObuff && d[-1] != '_') 4970 *d++ = '_'; /* prepend a '_' */ 4971 STRCPY(d, "CTRL-"); 4972 d += 5; 4973 if (*s < ' ') 4974 { 4975 #ifdef EBCDIC 4976 *d++ = CtrlChar(*s); 4977 #else 4978 *d++ = *s + '@'; 4979 #endif 4980 if (d[-1] == '\\') 4981 *d++ = '\\'; /* double a backslash */ 4982 } 4983 else 4984 *d++ = *++s; 4985 if (s[1] != NUL && s[1] != '_') 4986 *d++ = '_'; /* append a '_' */ 4987 continue; 4988 } 4989 else if (*s == '^') /* "^" or "CTRL-^" or "^_" */ 4990 *d++ = '\\'; 4991 4992 /* 4993 * Insert a backslash before a backslash after a slash, for search 4994 * pattern tags: "/\|" --> "/\\|". 4995 */ 4996 else if (s[0] == '\\' && s[1] != '\\' 4997 && *arg == '/' && s == arg + 1) 4998 *d++ = '\\'; 4999 5000 /* "CTRL-\_" -> "CTRL-\\_" to avoid the special meaning of "\_" in 5001 * "CTRL-\_CTRL-N" */ 5002 if (STRNICMP(s, "CTRL-\\_", 7) == 0) 5003 { 5004 STRCPY(d, "CTRL-\\\\"); 5005 d += 7; 5006 s += 6; 5007 } 5008 5009 *d++ = *s; 5010 5011 /* 5012 * If tag starts with ', toss everything after a second '. Fixes 5013 * CTRL-] on 'option'. (would include the trailing '.'). 5014 */ 5015 if (*s == '\'' && s > arg && *arg == '\'') 5016 break; 5017 } 5018 *d = NUL; 5019 } 5020 } 5021 5022 *matches = (char_u **)""; 5023 *num_matches = 0; 5024 flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE; 5025 if (keep_lang) 5026 flags |= TAG_KEEP_LANG; 5027 if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL, NULL) == OK 5028 && *num_matches > 0) 5029 /* Sort the matches found on the heuristic number that is after the 5030 * tag name. */ 5031 qsort((void *)*matches, (size_t)*num_matches, 5032 sizeof(char_u *), help_compare); 5033 return OK; 5034 } 5035 5036 /* 5037 * After reading a help file: May cleanup a help buffer when syntax 5038 * highlighting is not used. 5039 */ 5040 void 5041 fix_help_buffer() 5042 { 5043 linenr_T lnum; 5044 char_u *line; 5045 int in_example = FALSE; 5046 int len; 5047 char_u *p; 5048 char_u *rt; 5049 int mustfree; 5050 5051 /* set filetype to "help". */ 5052 set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL); 5053 5054 #ifdef FEAT_SYN_HL 5055 if (!syntax_present(curbuf)) 5056 #endif 5057 { 5058 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) 5059 { 5060 line = ml_get_buf(curbuf, lnum, FALSE); 5061 len = (int)STRLEN(line); 5062 if (in_example && len > 0 && !vim_iswhite(line[0])) 5063 { 5064 /* End of example: non-white or '<' in first column. */ 5065 if (line[0] == '<') 5066 { 5067 /* blank-out a '<' in the first column */ 5068 line = ml_get_buf(curbuf, lnum, TRUE); 5069 line[0] = ' '; 5070 } 5071 in_example = FALSE; 5072 } 5073 if (!in_example && len > 0) 5074 { 5075 if (line[len - 1] == '>' && (len == 1 || line[len - 2] == ' ')) 5076 { 5077 /* blank-out a '>' in the last column (start of example) */ 5078 line = ml_get_buf(curbuf, lnum, TRUE); 5079 line[len - 1] = ' '; 5080 in_example = TRUE; 5081 } 5082 else if (line[len - 1] == '~') 5083 { 5084 /* blank-out a '~' at the end of line (header marker) */ 5085 line = ml_get_buf(curbuf, lnum, TRUE); 5086 line[len - 1] = ' '; 5087 } 5088 } 5089 } 5090 } 5091 5092 /* 5093 * In the "help.txt" file, add the locally added help files. 5094 * This uses the very first line in the help file. 5095 */ 5096 if (fnamecmp(gettail(curbuf->b_fname), "help.txt") == 0) 5097 { 5098 for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; ++lnum) 5099 { 5100 line = ml_get_buf(curbuf, lnum, FALSE); 5101 if (strstr((char *)line, "*local-additions*") != NULL) 5102 { 5103 /* Go through all directories in 'runtimepath', skipping 5104 * $VIMRUNTIME. */ 5105 p = p_rtp; 5106 while (*p != NUL) 5107 { 5108 copy_option_part(&p, NameBuff, MAXPATHL, ","); 5109 mustfree = FALSE; 5110 rt = vim_getenv((char_u *)"VIMRUNTIME", &mustfree); 5111 if (fullpathcmp(rt, NameBuff, FALSE) != FPC_SAME) 5112 { 5113 int fcount; 5114 char_u **fnames; 5115 FILE *fd; 5116 char_u *s; 5117 int fi; 5118 #ifdef FEAT_MBYTE 5119 vimconv_T vc; 5120 char_u *cp; 5121 #endif 5122 5123 /* Find all "doc/ *.txt" files in this directory. */ 5124 add_pathsep(NameBuff); 5125 STRCAT(NameBuff, "doc/*.txt"); 5126 if (gen_expand_wildcards(1, &NameBuff, &fcount, 5127 &fnames, EW_FILE|EW_SILENT) == OK 5128 && fcount > 0) 5129 { 5130 for (fi = 0; fi < fcount; ++fi) 5131 { 5132 fd = fopen((char *)fnames[fi], "r"); 5133 if (fd != NULL) 5134 { 5135 vim_fgets(IObuff, IOSIZE, fd); 5136 if (IObuff[0] == '*' 5137 && (s = vim_strchr(IObuff + 1, '*')) 5138 != NULL) 5139 { 5140 #ifdef FEAT_MBYTE 5141 int this_utf = MAYBE; 5142 #endif 5143 /* Change tag definition to a 5144 * reference and remove <CR>/<NL>. */ 5145 IObuff[0] = '|'; 5146 *s = '|'; 5147 while (*s != NUL) 5148 { 5149 if (*s == '\r' || *s == '\n') 5150 *s = NUL; 5151 #ifdef FEAT_MBYTE 5152 /* The text is utf-8 when a byte 5153 * above 127 is found and no 5154 * illegal byte sequence is found. 5155 */ 5156 if (*s >= 0x80 && this_utf != FALSE) 5157 { 5158 int l; 5159 5160 this_utf = TRUE; 5161 l = utf_ptr2len_check(s); 5162 if (l == 1) 5163 this_utf = FALSE; 5164 s += l - 1; 5165 } 5166 #endif 5167 ++s; 5168 } 5169 #ifdef FEAT_MBYTE 5170 /* The help file is latin1 or utf-8; 5171 * conversion to the current 5172 * 'encoding' may be required. */ 5173 vc.vc_type = CONV_NONE; 5174 convert_setup(&vc, (char_u *)( 5175 this_utf == TRUE ? "utf-8" 5176 : "latin1"), p_enc); 5177 if (vc.vc_type == CONV_NONE) 5178 /* No conversion needed. */ 5179 cp = IObuff; 5180 else 5181 { 5182 /* Do the conversion. If it fails 5183 * use the unconverted text. */ 5184 cp = string_convert(&vc, IObuff, 5185 NULL); 5186 if (cp == NULL) 5187 cp = IObuff; 5188 } 5189 convert_setup(&vc, NULL, NULL); 5190 5191 ml_append(lnum, cp, (colnr_T)0, FALSE); 5192 if (cp != IObuff) 5193 vim_free(cp); 5194 #else 5195 ml_append(lnum, IObuff, (colnr_T)0, 5196 FALSE); 5197 #endif 5198 ++lnum; 5199 } 5200 fclose(fd); 5201 } 5202 } 5203 FreeWild(fcount, fnames); 5204 } 5205 } 5206 if (mustfree) 5207 vim_free(rt); 5208 } 5209 break; 5210 } 5211 } 5212 } 5213 } 5214 5215 #if defined(FEAT_EX_EXTRA) || defined(PROTO) 5216 static void helptags_one __ARGS((char_u *dir, char_u *ext, char_u *lang)); 5217 5218 /* 5219 * ":helptags" 5220 */ 5221 void 5222 ex_helptags(eap) 5223 exarg_T *eap; 5224 { 5225 garray_T ga; 5226 int i, j; 5227 int len; 5228 #ifdef FEAT_MULTI_LANG 5229 char_u lang[2]; 5230 #endif 5231 char_u ext[5]; 5232 char_u fname[8]; 5233 int filecount; 5234 char_u **files; 5235 5236 if (!mch_isdir(eap->arg)) 5237 { 5238 EMSG2(_("E150: Not a directory: %s"), eap->arg); 5239 return; 5240 } 5241 5242 #ifdef FEAT_MULTI_LANG 5243 /* Get a list of all files in the directory. */ 5244 STRCPY(NameBuff, eap->arg); 5245 add_pathsep(NameBuff); 5246 STRCAT(NameBuff, "*"); 5247 if (gen_expand_wildcards(1, &NameBuff, &filecount, &files, 5248 EW_FILE|EW_SILENT) == FAIL 5249 || filecount == 0) 5250 { 5251 EMSG2("E151: No match: %s", NameBuff); 5252 return; 5253 } 5254 5255 /* Go over all files in the directory to find out what languages are 5256 * present. */ 5257 ga_init2(&ga, 1, 10); 5258 for (i = 0; i < filecount; ++i) 5259 { 5260 len = STRLEN(files[i]); 5261 if (len > 4) 5262 { 5263 if (STRICMP(files[i] + len - 4, ".txt") == 0) 5264 { 5265 /* ".txt" -> language "en" */ 5266 lang[0] = 'e'; 5267 lang[1] = 'n'; 5268 } 5269 else if (files[i][len - 4] == '.' 5270 && ASCII_ISALPHA(files[i][len - 3]) 5271 && ASCII_ISALPHA(files[i][len - 2]) 5272 && TOLOWER_ASC(files[i][len - 1]) == 'x') 5273 { 5274 /* ".abx" -> language "ab" */ 5275 lang[0] = TOLOWER_ASC(files[i][len - 3]); 5276 lang[1] = TOLOWER_ASC(files[i][len - 2]); 5277 } 5278 else 5279 continue; 5280 5281 /* Did we find this language already? */ 5282 for (j = 0; j < ga.ga_len; j += 2) 5283 if (STRNCMP(lang, ((char_u *)ga.ga_data) + j, 2) == 0) 5284 break; 5285 if (j == ga.ga_len) 5286 { 5287 /* New language, add it. */ 5288 if (ga_grow(&ga, 2) == FAIL) 5289 break; 5290 ((char_u *)ga.ga_data)[ga.ga_len++] = lang[0]; 5291 ((char_u *)ga.ga_data)[ga.ga_len++] = lang[1]; 5292 ga.ga_room -= 2; 5293 } 5294 } 5295 } 5296 5297 /* 5298 * Loop over the found languages to generate a tags file for each one. 5299 */ 5300 for (j = 0; j < ga.ga_len; j += 2) 5301 { 5302 STRCPY(fname, "tags-xx"); 5303 fname[5] = ((char_u *)ga.ga_data)[j]; 5304 fname[6] = ((char_u *)ga.ga_data)[j + 1]; 5305 if (fname[5] == 'e' && fname[6] == 'n') 5306 { 5307 /* English is an exception: use ".txt" and "tags". */ 5308 fname[4] = NUL; 5309 STRCPY(ext, ".txt"); 5310 } 5311 else 5312 { 5313 /* Language "ab" uses ".abx" and "tags-ab". */ 5314 STRCPY(ext, ".xxx"); 5315 ext[1] = fname[5]; 5316 ext[2] = fname[6]; 5317 } 5318 helptags_one(eap->arg, ext, fname); 5319 } 5320 5321 ga_clear(&ga); 5322 FreeWild(filecount, files); 5323 5324 #else 5325 /* No language support, just use "*.txt" and "tags". */ 5326 helptags_one(eap->arg, (char_u *)".txt", (char_u *)"tags"); 5327 #endif 5328 } 5329 5330 static void 5331 helptags_one(dir, ext, tagfname) 5332 char_u *dir; /* doc directory */ 5333 char_u *ext; /* suffix, ".txt", ".itx", ".frx", etc. */ 5334 char_u *tagfname; /* "tags" for English, "tags-it" for Italian. */ 5335 { 5336 FILE *fd_tags; 5337 FILE *fd; 5338 garray_T ga; 5339 int filecount; 5340 char_u **files; 5341 char_u *p1, *p2; 5342 int fi; 5343 char_u *s; 5344 int i; 5345 char_u *fname; 5346 # ifdef FEAT_MBYTE 5347 int utf8 = MAYBE; 5348 int this_utf8; 5349 int firstline; 5350 int mix = FALSE; /* detected mixed encodings */ 5351 # endif 5352 5353 /* 5354 * Find all *.txt files. 5355 */ 5356 STRCPY(NameBuff, dir); 5357 add_pathsep(NameBuff); 5358 STRCAT(NameBuff, "*"); 5359 STRCAT(NameBuff, ext); 5360 if (gen_expand_wildcards(1, &NameBuff, &filecount, &files, 5361 EW_FILE|EW_SILENT) == FAIL 5362 || filecount == 0) 5363 { 5364 if (!got_int) 5365 EMSG2("E151: No match: %s", NameBuff); 5366 return; 5367 } 5368 5369 /* 5370 * Open the tags file for writing. 5371 * Do this before scanning through all the files. 5372 */ 5373 STRCPY(NameBuff, dir); 5374 add_pathsep(NameBuff); 5375 STRCAT(NameBuff, tagfname); 5376 fd_tags = fopen((char *)NameBuff, "w"); 5377 if (fd_tags == NULL) 5378 { 5379 EMSG2(_("E152: Cannot open %s for writing"), NameBuff); 5380 FreeWild(filecount, files); 5381 return; 5382 } 5383 5384 /* 5385 * If generating tags for "$VIMRUNTIME/doc" add the "help-tags" tag. 5386 */ 5387 ga_init2(&ga, (int)sizeof(char_u *), 100); 5388 if (fullpathcmp((char_u *)"$VIMRUNTIME/doc", dir, FALSE) == FPC_SAME) 5389 { 5390 if (ga_grow(&ga, 1) == FAIL) 5391 got_int = TRUE; 5392 else 5393 { 5394 s = alloc(30); 5395 if (s == NULL) 5396 got_int = TRUE; 5397 else 5398 { 5399 sprintf((char *)s, "help-tags\t%s\t1\n", tagfname); 5400 ((char_u **)ga.ga_data)[ga.ga_len] = s; 5401 ++ga.ga_len; 5402 --ga.ga_room; 5403 } 5404 } 5405 } 5406 5407 /* 5408 * Go over all the files and extract the tags. 5409 */ 5410 for (fi = 0; fi < filecount && !got_int; ++fi) 5411 { 5412 fd = fopen((char *)files[fi], "r"); 5413 if (fd == NULL) 5414 { 5415 EMSG2(_("E153: Unable to open %s for reading"), files[fi]); 5416 continue; 5417 } 5418 fname = gettail(files[fi]); 5419 5420 # ifdef FEAT_MBYTE 5421 firstline = TRUE; 5422 # endif 5423 while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) 5424 { 5425 # ifdef FEAT_MBYTE 5426 if (firstline) 5427 { 5428 /* Detect utf-8 file by a non-ASCII char in the first line. */ 5429 this_utf8 = MAYBE; 5430 for (s = IObuff; *s != NUL; ++s) 5431 if (*s >= 0x80) 5432 { 5433 int l; 5434 5435 this_utf8 = TRUE; 5436 l = utf_ptr2len_check(s); 5437 if (l == 1) 5438 { 5439 /* Illegal UTF-8 byte sequence. */ 5440 this_utf8 = FALSE; 5441 break; 5442 } 5443 s += l - 1; 5444 } 5445 if (this_utf8 == MAYBE) /* only ASCII characters found */ 5446 this_utf8 = FALSE; 5447 if (utf8 == MAYBE) /* first file */ 5448 utf8 = this_utf8; 5449 else if (utf8 != this_utf8) 5450 { 5451 EMSG2(_("E670: Mix of help file encodings within a language: %s"), files[fi]); 5452 mix = !got_int; 5453 got_int = TRUE; 5454 } 5455 firstline = FALSE; 5456 } 5457 # endif 5458 p1 = vim_strchr(IObuff, '*'); /* find first '*' */ 5459 while (p1 != NULL) 5460 { 5461 p2 = vim_strchr(p1 + 1, '*'); /* find second '*' */ 5462 if (p2 != NULL && p2 > p1 + 1) /* skip "*" and "**" */ 5463 { 5464 for (s = p1 + 1; s < p2; ++s) 5465 if (*s == ' ' || *s == '\t' || *s == '|') 5466 break; 5467 5468 /* 5469 * Only accept a *tag* when it consists of valid 5470 * characters, there is white space before it and is 5471 * followed by a white character or end-of-line. 5472 */ 5473 if (s == p2 5474 && (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t') 5475 && (vim_strchr((char_u *)" \t\n\r", s[1]) != NULL 5476 || s[1] == '\0')) 5477 { 5478 *p2 = '\0'; 5479 ++p1; 5480 if (ga_grow(&ga, 1) == FAIL) 5481 { 5482 got_int = TRUE; 5483 break; 5484 } 5485 s = alloc((unsigned)(p2 - p1 + STRLEN(fname) + 2)); 5486 if (s == NULL) 5487 { 5488 got_int = TRUE; 5489 break; 5490 } 5491 ((char_u **)ga.ga_data)[ga.ga_len] = s; 5492 ++ga.ga_len; 5493 --ga.ga_room; 5494 sprintf((char *)s, "%s\t%s", p1, fname); 5495 5496 /* find next '*' */ 5497 p2 = vim_strchr(p2 + 1, '*'); 5498 } 5499 } 5500 p1 = p2; 5501 } 5502 line_breakcheck(); 5503 } 5504 5505 fclose(fd); 5506 } 5507 5508 FreeWild(filecount, files); 5509 5510 if (!got_int) 5511 { 5512 /* 5513 * Sort the tags. 5514 */ 5515 sort_strings((char_u **)ga.ga_data, ga.ga_len); 5516 5517 /* 5518 * Check for duplicates. 5519 */ 5520 for (i = 1; i < ga.ga_len; ++i) 5521 { 5522 p1 = ((char_u **)ga.ga_data)[i - 1]; 5523 p2 = ((char_u **)ga.ga_data)[i]; 5524 while (*p1 == *p2) 5525 { 5526 if (*p2 == '\t') 5527 { 5528 *p2 = NUL; 5529 sprintf((char *)NameBuff, 5530 _("E154: Duplicate tag \"%s\" in file %s/%s"), 5531 ((char_u **)ga.ga_data)[i], dir, p2 + 1); 5532 EMSG(NameBuff); 5533 *p2 = '\t'; 5534 break; 5535 } 5536 ++p1; 5537 ++p2; 5538 } 5539 } 5540 5541 # ifdef FEAT_MBYTE 5542 if (utf8 == TRUE) 5543 fprintf(fd_tags, "!_TAG_FILE_ENCODING\tutf-8\t//\n"); 5544 # endif 5545 5546 /* 5547 * Write the tags into the file. 5548 */ 5549 for (i = 0; i < ga.ga_len; ++i) 5550 { 5551 s = ((char_u **)ga.ga_data)[i]; 5552 if (STRNCMP(s, "help-tags", 9) == 0) 5553 /* help-tags entry was added in formatted form */ 5554 fprintf(fd_tags, (char *)s); 5555 else 5556 { 5557 fprintf(fd_tags, "%s\t/*", s); 5558 for (p1 = s; *p1 != '\t'; ++p1) 5559 { 5560 /* insert backslash before '\\' and '/' */ 5561 if (*p1 == '\\' || *p1 == '/') 5562 putc('\\', fd_tags); 5563 putc(*p1, fd_tags); 5564 } 5565 fprintf(fd_tags, "*\n"); 5566 } 5567 } 5568 } 5569 #ifdef FEAT_MBYTE 5570 if (mix) 5571 got_int = FALSE; /* continue with other languages */ 5572 #endif 5573 5574 for (i = 0; i < ga.ga_len; ++i) 5575 vim_free(((char_u **)ga.ga_data)[i]); 5576 ga_clear(&ga); 5577 fclose(fd_tags); /* there is no check for an error... */ 5578 } 5579 #endif 5580 5581 #if defined(FEAT_SIGNS) || defined(PROTO) 5582 5583 /* 5584 * Struct to hold the sign properties. 5585 */ 5586 typedef struct sign sign_T; 5587 5588 struct sign 5589 { 5590 sign_T *sn_next; /* next sign in list */ 5591 int sn_typenr; /* type number of sign (negative if not equal 5592 to name) */ 5593 char_u *sn_name; /* name of sign */ 5594 char_u *sn_icon; /* name of pixmap */ 5595 #ifdef FEAT_SIGN_ICONS 5596 void *sn_image; /* icon image */ 5597 #endif 5598 char_u *sn_text; /* text used instead of pixmap */ 5599 int sn_line_hl; /* highlight ID for line */ 5600 int sn_text_hl; /* highlight ID for text */ 5601 }; 5602 5603 #define MAX_TYPENR 255 /* depends on sattr_T */ 5604 static sign_T *first_sign = NULL; 5605 static int last_sign_typenr = MAX_TYPENR; /* is decremented */ 5606 5607 static void sign_list_defined __ARGS((sign_T *sp)); 5608 5609 /* 5610 * ":sign" command 5611 */ 5612 void 5613 ex_sign(eap) 5614 exarg_T *eap; 5615 { 5616 char_u *arg = eap->arg; 5617 char_u *p; 5618 int idx; 5619 sign_T *sp; 5620 sign_T *sp_prev; 5621 buf_T *buf; 5622 static char *cmds[] = { 5623 "define", 5624 #define SIGNCMD_DEFINE 0 5625 "undefine", 5626 #define SIGNCMD_UNDEFINE 1 5627 "list", 5628 #define SIGNCMD_LIST 2 5629 "place", 5630 #define SIGNCMD_PLACE 3 5631 "unplace", 5632 #define SIGNCMD_UNPLACE 4 5633 "jump", 5634 #define SIGNCMD_JUMP 5 5635 #define SIGNCMD_LAST 6 5636 }; 5637 5638 /* Parse the subcommand. */ 5639 p = skiptowhite(arg); 5640 if (*p != NUL) 5641 *p++ = NUL; 5642 for (idx = 0; ; ++idx) 5643 { 5644 if (idx == SIGNCMD_LAST) 5645 { 5646 EMSG2(_("E160: Unknown sign command: %s"), arg); 5647 return; 5648 } 5649 if (STRCMP(arg, cmds[idx]) == 0) 5650 break; 5651 } 5652 arg = skipwhite(p); 5653 5654 if (idx <= SIGNCMD_LIST) 5655 { 5656 /* 5657 * Define, undefine or list signs. 5658 */ 5659 if (idx == SIGNCMD_LIST && *arg == NUL) 5660 { 5661 /* ":sign list": list all defined signs */ 5662 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 5663 sign_list_defined(sp); 5664 } 5665 else if (*arg == NUL) 5666 EMSG(_("E156: Missing sign name")); 5667 else 5668 { 5669 p = skiptowhite(arg); 5670 if (*p != NUL) 5671 *p++ = NUL; 5672 sp_prev = NULL; 5673 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 5674 { 5675 if (STRCMP(sp->sn_name, arg) == 0) 5676 break; 5677 sp_prev = sp; 5678 } 5679 if (idx == SIGNCMD_DEFINE) 5680 { 5681 /* ":sign define {name} ...": define a sign */ 5682 if (sp == NULL) 5683 { 5684 /* Allocate a new sign. */ 5685 sp = (sign_T *)alloc_clear((unsigned)sizeof(sign_T)); 5686 if (sp == NULL) 5687 return; 5688 if (sp_prev == NULL) 5689 first_sign = sp; 5690 else 5691 sp_prev->sn_next = sp; 5692 sp->sn_name = vim_strnsave(arg, (int)(p - arg)); 5693 5694 /* If the name is a number use that for the typenr, 5695 * otherwise use a negative number. */ 5696 if (VIM_ISDIGIT(*arg)) 5697 sp->sn_typenr = atoi((char *)arg); 5698 else 5699 { 5700 sign_T *lp; 5701 int start = last_sign_typenr; 5702 5703 for (lp = first_sign; lp != NULL; lp = lp->sn_next) 5704 { 5705 if (lp->sn_typenr == last_sign_typenr) 5706 { 5707 --last_sign_typenr; 5708 if (last_sign_typenr == 0) 5709 last_sign_typenr = MAX_TYPENR; 5710 if (last_sign_typenr == start) 5711 { 5712 EMSG(_("E612: Too many signs defined")); 5713 return; 5714 } 5715 lp = first_sign; 5716 continue; 5717 } 5718 } 5719 5720 sp->sn_typenr = last_sign_typenr--; 5721 if (last_sign_typenr == 0) 5722 last_sign_typenr = MAX_TYPENR; /* wrap around */ 5723 } 5724 } 5725 5726 /* set values for a defined sign. */ 5727 for (;;) 5728 { 5729 arg = skipwhite(p); 5730 if (*arg == NUL) 5731 break; 5732 p = skiptowhite_esc(arg); 5733 if (STRNCMP(arg, "icon=", 5) == 0) 5734 { 5735 arg += 5; 5736 vim_free(sp->sn_icon); 5737 sp->sn_icon = vim_strnsave(arg, (int)(p - arg)); 5738 backslash_halve(sp->sn_icon); 5739 #ifdef FEAT_SIGN_ICONS 5740 if (gui.in_use) 5741 { 5742 out_flush(); 5743 if (sp->sn_image != NULL) 5744 gui_mch_destroy_sign(sp->sn_image); 5745 sp->sn_image = gui_mch_register_sign(sp->sn_icon); 5746 } 5747 #endif 5748 } 5749 else if (STRNCMP(arg, "text=", 5) == 0) 5750 { 5751 char_u *s; 5752 int cells; 5753 int len; 5754 5755 arg += 5; 5756 #ifdef FEAT_MBYTE 5757 /* Count cells and check for non-printable chars */ 5758 if (has_mbyte) 5759 { 5760 cells = 0; 5761 for (s = arg; s < p; s += (*mb_ptr2len_check)(s)) 5762 { 5763 if (!vim_isprintc((*mb_ptr2char)(s))) 5764 break; 5765 cells += (*mb_ptr2cells)(s); 5766 } 5767 } 5768 else 5769 #endif 5770 { 5771 for (s = arg; s < p; ++s) 5772 if (!vim_isprintc(*s)) 5773 break; 5774 cells = s - arg; 5775 } 5776 /* Currently must be one or two display cells */ 5777 if (s != p || cells < 1 || cells > 2) 5778 { 5779 *p = NUL; 5780 EMSG2(_("E239: Invalid sign text: %s"), arg); 5781 return; 5782 } 5783 5784 vim_free(sp->sn_text); 5785 /* Allocate one byte more if we need to pad up 5786 * with a space. */ 5787 len = p - arg + ((cells == 1) ? 1 : 0); 5788 sp->sn_text = vim_strnsave(arg, len); 5789 5790 if (sp->sn_text != NULL && cells == 1) 5791 STRCPY(sp->sn_text + len - 1, " "); 5792 } 5793 else if (STRNCMP(arg, "linehl=", 7) == 0) 5794 { 5795 arg += 7; 5796 sp->sn_line_hl = syn_check_group(arg, (int)(p - arg)); 5797 } 5798 else if (STRNCMP(arg, "texthl=", 7) == 0) 5799 { 5800 arg += 7; 5801 sp->sn_text_hl = syn_check_group(arg, (int)(p - arg)); 5802 } 5803 else 5804 { 5805 EMSG2(_(e_invarg2), arg); 5806 return; 5807 } 5808 } 5809 } 5810 else if (sp == NULL) 5811 EMSG2(_("E155: Unknown sign: %s"), arg); 5812 else if (idx == SIGNCMD_LIST) 5813 /* ":sign list {name}" */ 5814 sign_list_defined(sp); 5815 else 5816 { 5817 /* ":sign undefine {name}" */ 5818 vim_free(sp->sn_name); 5819 vim_free(sp->sn_icon); 5820 #ifdef FEAT_SIGN_ICONS 5821 if (sp->sn_image != NULL) 5822 { 5823 out_flush(); 5824 gui_mch_destroy_sign(sp->sn_image); 5825 } 5826 #endif 5827 vim_free(sp->sn_text); 5828 if (sp_prev == NULL) 5829 first_sign = sp->sn_next; 5830 else 5831 sp_prev->sn_next = sp->sn_next; 5832 vim_free(sp); 5833 } 5834 } 5835 } 5836 else 5837 { 5838 int id = -1; 5839 linenr_T lnum = -1; 5840 char_u *sign_name = NULL; 5841 char_u *arg1; 5842 5843 if (*arg == NUL) 5844 { 5845 if (idx == SIGNCMD_PLACE) 5846 { 5847 /* ":sign place": list placed signs in all buffers */ 5848 sign_list_placed(NULL); 5849 } 5850 else if (idx == SIGNCMD_UNPLACE) 5851 { 5852 /* ":sign unplace": remove placed sign at cursor */ 5853 id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum); 5854 if (id > 0) 5855 { 5856 buf_delsign(curwin->w_buffer, id); 5857 update_debug_sign(curwin->w_buffer, curwin->w_cursor.lnum); 5858 } 5859 else 5860 EMSG(_("E159: Missing sign number")); 5861 } 5862 else 5863 EMSG(_(e_argreq)); 5864 return; 5865 } 5866 5867 if (idx == SIGNCMD_UNPLACE && arg[0] == '*' && arg[1] == NUL) 5868 { 5869 /* ":sign unplace *": remove all placed signs */ 5870 buf_delete_all_signs(); 5871 return; 5872 } 5873 5874 /* first arg could be placed sign id */ 5875 arg1 = arg; 5876 if (VIM_ISDIGIT(*arg)) 5877 { 5878 id = getdigits(&arg); 5879 if (!vim_iswhite(*arg) && *arg != NUL) 5880 { 5881 id = -1; 5882 arg = arg1; 5883 } 5884 else 5885 { 5886 arg = skipwhite(arg); 5887 if (idx == SIGNCMD_UNPLACE && *arg == NUL) 5888 { 5889 /* ":sign unplace {id}": remove placed sign by number */ 5890 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 5891 if ((lnum = buf_delsign(buf, id)) != 0) 5892 update_debug_sign(buf, lnum); 5893 return; 5894 } 5895 } 5896 } 5897 5898 /* 5899 * Check for line={lnum} name={name} and file={fname} or buffer={nr}. 5900 * Leave "arg" pointing to {fname}. 5901 */ 5902 for (;;) 5903 { 5904 if (STRNCMP(arg, "line=", 5) == 0) 5905 { 5906 arg += 5; 5907 lnum = atoi((char *)arg); 5908 arg = skiptowhite(arg); 5909 } 5910 else if (STRNCMP(arg, "name=", 5) == 0) 5911 { 5912 arg += 5; 5913 sign_name = arg; 5914 arg = skiptowhite(arg); 5915 if (*arg != NUL) 5916 *arg++ = NUL; 5917 } 5918 else if (STRNCMP(arg, "file=", 5) == 0) 5919 { 5920 arg += 5; 5921 buf = buflist_findname(arg); 5922 break; 5923 } 5924 else if (STRNCMP(arg, "buffer=", 7) == 0) 5925 { 5926 arg += 7; 5927 buf = buflist_findnr((int)getdigits(&arg)); 5928 if (*skipwhite(arg) != NUL) 5929 EMSG(_(e_trailing)); 5930 break; 5931 } 5932 else 5933 { 5934 EMSG(_(e_invarg)); 5935 return; 5936 } 5937 arg = skipwhite(arg); 5938 } 5939 5940 if (buf == NULL) 5941 { 5942 EMSG2(_("E158: Invalid buffer name: %s"), arg); 5943 } 5944 else if (id <= 0) 5945 { 5946 if (lnum >= 0 || sign_name != NULL) 5947 EMSG(_(e_invarg)); 5948 else 5949 /* ":sign place file={fname}": list placed signs in one file */ 5950 sign_list_placed(buf); 5951 } 5952 else if (idx == SIGNCMD_JUMP) 5953 { 5954 /* ":sign jump {id} file={fname}" */ 5955 if (lnum >= 0 || sign_name != NULL) 5956 EMSG(_(e_invarg)); 5957 else if ((lnum = buf_findsign(buf, id)) > 0) 5958 { /* goto a sign ... */ 5959 if (buf_jump_open_win(buf) != NULL) 5960 { /* ... in a current window */ 5961 curwin->w_cursor.lnum = lnum; 5962 check_cursor_lnum(); 5963 beginline(BL_WHITE); 5964 } 5965 else 5966 { /* ... not currently in a window */ 5967 char_u *cmd; 5968 5969 cmd = alloc((unsigned)STRLEN(buf->b_fname) + 25); 5970 if (cmd == NULL) 5971 return; 5972 sprintf((char *)cmd, "e +%ld %s", (long)lnum, buf->b_fname); 5973 do_cmdline_cmd(cmd); 5974 vim_free(cmd); 5975 } 5976 #ifdef FEAT_FOLDING 5977 foldOpenCursor(); 5978 #endif 5979 } 5980 else 5981 EMSGN(_("E157: Invalid sign ID: %ld"), id); 5982 } 5983 else if (idx == SIGNCMD_UNPLACE) 5984 { 5985 /* ":sign unplace {id} file={fname}" */ 5986 if (lnum >= 0 || sign_name != NULL) 5987 EMSG(_(e_invarg)); 5988 else 5989 { 5990 lnum = buf_delsign(buf, id); 5991 update_debug_sign(buf, lnum); 5992 } 5993 } 5994 /* idx == SIGNCMD_PLACE */ 5995 else if (sign_name != NULL) 5996 { 5997 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 5998 if (STRCMP(sp->sn_name, sign_name) == 0) 5999 break; 6000 if (sp == NULL) 6001 { 6002 EMSG2(_("E155: Unknown sign: %s"), sign_name); 6003 return; 6004 } 6005 if (lnum > 0) 6006 /* ":sign place {id} line={lnum} name={name} file={fname}": 6007 * place a sign */ 6008 buf_addsign(buf, id, lnum, sp->sn_typenr); 6009 else 6010 /* ":sign place {id} file={fname}": change sign type */ 6011 lnum = buf_change_sign_type(buf, id, sp->sn_typenr); 6012 update_debug_sign(buf, lnum); 6013 } 6014 else 6015 EMSG(_(e_invarg)); 6016 } 6017 } 6018 6019 #if defined(FEAT_SIGN_ICONS) || defined(PROTO) 6020 /* 6021 * Allocate the icons. Called when the GUI has started. Allows defining 6022 * signs before it starts. 6023 */ 6024 void 6025 sign_gui_started() 6026 { 6027 sign_T *sp; 6028 6029 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 6030 if (sp->sn_icon != NULL) 6031 sp->sn_image = gui_mch_register_sign(sp->sn_icon); 6032 } 6033 #endif 6034 6035 /* 6036 * List one sign. 6037 */ 6038 static void 6039 sign_list_defined(sp) 6040 sign_T *sp; 6041 { 6042 char_u *p; 6043 6044 smsg((char_u *)"sign %s", sp->sn_name); 6045 if (sp->sn_icon != NULL) 6046 { 6047 MSG_PUTS(" icon="); 6048 msg_outtrans(sp->sn_icon); 6049 #ifdef FEAT_SIGN_ICONS 6050 if (sp->sn_image == NULL) 6051 MSG_PUTS(_(" (NOT FOUND)")); 6052 #else 6053 MSG_PUTS(_(" (not supported)")); 6054 #endif 6055 } 6056 if (sp->sn_text != NULL) 6057 { 6058 MSG_PUTS(" text="); 6059 msg_outtrans(sp->sn_text); 6060 } 6061 if (sp->sn_line_hl > 0) 6062 { 6063 MSG_PUTS(" linehl="); 6064 p = get_highlight_name(NULL, sp->sn_line_hl - 1); 6065 if (p == NULL) 6066 MSG_PUTS("NONE"); 6067 else 6068 msg_puts(p); 6069 } 6070 if (sp->sn_text_hl > 0) 6071 { 6072 MSG_PUTS(" texthl="); 6073 p = get_highlight_name(NULL, sp->sn_text_hl - 1); 6074 if (p == NULL) 6075 MSG_PUTS("NONE"); 6076 else 6077 msg_puts(p); 6078 } 6079 } 6080 6081 /* 6082 * Get highlighting attribute for sign "typenr". 6083 * If "line" is TRUE: line highl, if FALSE: text highl. 6084 */ 6085 int 6086 sign_get_attr(typenr, line) 6087 int typenr; 6088 int line; 6089 { 6090 sign_T *sp; 6091 6092 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 6093 if (sp->sn_typenr == typenr) 6094 { 6095 if (line) 6096 { 6097 if (sp->sn_line_hl > 0) 6098 return syn_id2attr(sp->sn_line_hl); 6099 } 6100 else 6101 { 6102 if (sp->sn_text_hl > 0) 6103 return syn_id2attr(sp->sn_text_hl); 6104 } 6105 break; 6106 } 6107 return 0; 6108 } 6109 6110 /* 6111 * Get text mark for sign "typenr". 6112 * Returns NULL if there isn't one. 6113 */ 6114 char_u * 6115 sign_get_text(typenr) 6116 int typenr; 6117 { 6118 sign_T *sp; 6119 6120 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 6121 if (sp->sn_typenr == typenr) 6122 return sp->sn_text; 6123 return NULL; 6124 } 6125 6126 #if defined(FEAT_SIGN_ICONS) || defined(PROTO) 6127 void * 6128 sign_get_image(typenr) 6129 int typenr; /* the attribute which may have a sign */ 6130 { 6131 sign_T *sp; 6132 6133 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 6134 if (sp->sn_typenr == typenr) 6135 return sp->sn_image; 6136 return NULL; 6137 } 6138 #endif 6139 6140 /* 6141 * Get the name of a sign by its typenr. 6142 */ 6143 char_u * 6144 sign_typenr2name(typenr) 6145 int typenr; 6146 { 6147 sign_T *sp; 6148 6149 for (sp = first_sign; sp != NULL; sp = sp->sn_next) 6150 if (sp->sn_typenr == typenr) 6151 return sp->sn_name; 6152 return (char_u *)_("[Deleted]"); 6153 } 6154 6155 #endif 6156 6157 #if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO) 6158 /* 6159 * ":drop" 6160 * Opens the first argument in a window. When there are two or more arguments 6161 * the argument list is redefined. 6162 */ 6163 void 6164 ex_drop(eap) 6165 exarg_T *eap; 6166 { 6167 int split = FALSE; 6168 int incurwin = FALSE; 6169 char_u *arg; 6170 char_u *first = NULL; 6171 win_T *wp; 6172 buf_T *buf; 6173 6174 /* 6175 * Check if the first argument is already being edited in a window. If 6176 * so, jump to that window. 6177 * We would actually need to check all arguments, but that's complicated 6178 * and mostly only one file is dropped. 6179 * This also ignores wildcards, since it is very unlikely the user is 6180 * editing a file name with a wildcard character. 6181 */ 6182 arg = vim_strsave(eap->arg); 6183 if (arg != NULL) 6184 { 6185 /* Get the first argument, remove quotes, make it a full path. */ 6186 first = fix_fname(arg); 6187 if (first != NULL) 6188 { 6189 buf = buflist_findname(first); 6190 FOR_ALL_WINDOWS(wp) 6191 { 6192 if (wp->w_buffer == buf) 6193 { 6194 incurwin = TRUE; 6195 # ifdef FEAT_WINDOWS 6196 win_enter(wp, TRUE); 6197 break; 6198 # endif 6199 } 6200 } 6201 vim_free(first); 6202 6203 if (incurwin) 6204 { 6205 /* Already editing the file. Redefine the argument list. */ 6206 set_arglist(eap->arg); 6207 curwin->w_arg_idx = 0; 6208 vim_free(arg); 6209 return; 6210 } 6211 } 6212 vim_free(arg); 6213 } 6214 6215 /* 6216 * Check whether the current buffer is changed. If so, we will need 6217 * to split the current window or data could be lost. 6218 * Skip the check if the 'hidden' option is set, as in this case the 6219 * buffer won't be lost. 6220 */ 6221 if (!P_HID(curbuf)) 6222 { 6223 # ifdef FEAT_WINDOWS 6224 ++emsg_off; 6225 # endif 6226 split = check_changed(curbuf, TRUE, FALSE, FALSE, FALSE); 6227 # ifdef FEAT_WINDOWS 6228 --emsg_off; 6229 # else 6230 if (split) 6231 return; 6232 # endif 6233 } 6234 6235 /* Fake a ":snext" or ":next" command, redefine the arglist. */ 6236 if (split) 6237 { 6238 eap->cmdidx = CMD_snext; 6239 eap->cmd[0] = 's'; 6240 } 6241 else 6242 eap->cmdidx = CMD_next; 6243 ex_next(eap); 6244 } 6245 #endif 6246