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