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