1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 /* Copyright (c) 1981 Regents of the University of California */ 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 #include "ex.h" 36 #include "ex_tty.h" 37 #include "ex_vis.h" 38 39 /* 40 * This file defines the operation sequences which interface the 41 * logical changes to the file buffer with the internal and external 42 * display representations. 43 */ 44 45 /* 46 * Undo. 47 * 48 * Undo is accomplished in two ways. We often for small changes in the 49 * current line know how (in terms of a change operator) how the change 50 * occurred. Thus on an intelligent terminal we can undo the operation 51 * by another such operation, using insert and delete character 52 * stuff. The pointers vU[AD][12] index the buffer vutmp when this 53 * is possible and provide the necessary information. 54 * 55 * The other case is that the change involved multiple lines or that 56 * we have moved away from the line or forgotten how the change was 57 * accomplished. In this case we do a redisplay and hope that the 58 * low level optimization routines (which don't look for winning 59 * via insert/delete character) will not lose too badly. 60 */ 61 unsigned char *vUA1, *vUA2; 62 unsigned char *vUD1, *vUD2; 63 64 void 65 vUndo(void) 66 { 67 68 /* 69 * Avoid UU which clobbers ability to do u. 70 */ 71 if (vundkind == VNONE || vundkind == VCAPU || vUNDdot != dot) { 72 (void) beep(); 73 return; 74 } 75 CP(vutmp, linebuf); 76 vUD1 = linebuf; vUD2 = strend(linebuf); 77 putmk1(dot, vUNDsav); 78 getDOT(); 79 vUA1 = linebuf; vUA2 = strend(linebuf); 80 vundkind = VCAPU; 81 if (state == ONEOPEN || state == HARDOPEN) { 82 vjumpto(dot, vUNDcurs, 0); 83 return; 84 } 85 vdirty(vcline, 1); 86 if(MB_CUR_MAX > 1) 87 rewrite = _ON; 88 vsyncCL(); 89 if(MB_CUR_MAX > 1) 90 rewrite = _OFF; 91 cursor = linebuf; 92 vfixcurs(); 93 } 94 95 void 96 vundo(show) 97 bool show; /* if true update the screen */ 98 { 99 int cnt; 100 line *addr; 101 unsigned char *cp; 102 unsigned char temp[LBSIZE]; 103 bool savenote; 104 int (*OO)(); 105 short oldhold = hold; 106 unsigned multic[MULTI_BYTE_MAX]; 107 int length; 108 wchar_t wchar; 109 110 switch (vundkind) { 111 112 case VMANYINS: 113 wcursor = 0; 114 addr1 = undap1; 115 addr2 = undap2 - 1; 116 vsave(); 117 (void) YANKreg('1'); 118 notecnt = 0; 119 /* fall into ... */ 120 121 case VMANY: 122 case VMCHNG: 123 vsave(); 124 addr = dot - vcline; 125 notecnt = 1; 126 if (undkind == UNDPUT && undap1 == undap2) { 127 (void) beep(); 128 break; 129 } 130 /* 131 * Undo() call below basically replaces undap1 to undap2-1 132 * with dol through unddol-1. Hack screen image to 133 * reflect this replacement. 134 */ 135 if (show) 136 if (undkind == UNDMOVE) 137 vdirty(0, lines); 138 else 139 vreplace(undap1 - addr, undap2 - undap1, 140 undkind == UNDPUT ? 0 : unddol - dol); 141 savenote = notecnt; 142 undo(1); 143 if (show && (vundkind != VMCHNG || addr != dot)) 144 killU(); 145 vundkind = VMANY; 146 cnt = dot - addr; 147 if (cnt < 0 || cnt > vcnt || state != VISUAL) { 148 if (show) 149 vjumpto(dot, (unsigned char *)NOSTR, '.'); 150 break; 151 } 152 if (!savenote) 153 notecnt = 0; 154 if (show) { 155 vcline = cnt; 156 if(MB_CUR_MAX > 1) 157 rewrite = _ON; 158 vrepaint(vmcurs); 159 if(MB_CUR_MAX > 1) 160 rewrite = _OFF; 161 } 162 vmcurs = 0; 163 break; 164 165 case VCHNG: 166 case VCAPU: 167 vundkind = VCHNG; 168 strcpy(temp, vutmp); 169 strcpy(vutmp, linebuf); 170 doomed = lcolumn(vUA2) - lcolumn(vUA1); 171 strcLIN(temp); 172 cp = vUA1; vUA1 = vUD1; vUD1 = cp; 173 cp = vUA2; vUA2 = vUD2; vUD2 = cp; 174 if (!show) 175 break; 176 cursor = vUD1; 177 if (state == HARDOPEN) { 178 doomed = 0; 179 vsave(); 180 vopen(dot, WBOT); 181 vnline(cursor); 182 break; 183 } 184 /* 185 * Pseudo insert command. 186 */ 187 vcursat(cursor); 188 OO = Outchar; Outchar = vinschar; hold |= HOLDQIK; 189 vprepins(); 190 temp[vUA2 - linebuf] = 0; 191 for (cp = &temp[vUA1 - linebuf]; *cp;) { 192 length = mbtowc(&wchar, (char *)cp, MULTI_BYTE_MAX); 193 if(length < 0) { 194 putoctal = 1; 195 putchar(*cp++); 196 putoctal = 0; 197 } else { 198 putchar(wchar); 199 cp += length; 200 } 201 } 202 Outchar = OO; hold = oldhold; 203 endim(); 204 physdc(cindent(), cindent() + doomed); 205 doomed = 0; 206 vdirty(vcline, 1); 207 if(MB_CUR_MAX > 1) 208 rewrite = _ON; 209 vsyncCL(); 210 if(MB_CUR_MAX > 1) 211 rewrite = _OFF; 212 if (cursor > linebuf && cursor >= strend(linebuf)) 213 cursor = lastchr(linebuf, cursor); 214 vfixcurs(); 215 break; 216 217 case VNONE: 218 (void) beep(); 219 break; 220 } 221 } 222 223 /* 224 * Routine to handle a change inside a macro. 225 * Fromvis is true if we were called from a visual command (as 226 * opposed to an ex command). This has nothing to do with being 227 * in open/visual mode as :s/foo/bar is not fromvis. 228 */ 229 void 230 vmacchng(fromvis) 231 bool fromvis; 232 { 233 line *savedot, *savedol; 234 unsigned char *savecursor; 235 unsigned char savelb[LBSIZE]; 236 int nlines, more; 237 line *a1, *a2; 238 unsigned char ch; /* DEBUG */ 239 int copyw(), copywR(); 240 241 if (!inopen) 242 return; 243 if (!vmacp) 244 vch_mac = VC_NOTINMAC; 245 #ifdef UNDOTRACE 246 if (trace) 247 fprintf(trace, "vmacchng, vch_mac=%d, linebuf='%s', *dot=%o\n", vch_mac, linebuf, *dot); 248 #endif 249 if (vmacp && fromvis) 250 vsave(); 251 #ifdef UNDOTRACE 252 if (trace) 253 fprintf(trace, "after vsave, linebuf='%s', *dot=%o\n", linebuf, *dot); 254 #endif 255 switch(vch_mac) { 256 case VC_NOCHANGE: 257 vch_mac = VC_ONECHANGE; 258 break; 259 case VC_ONECHANGE: 260 /* Save current state somewhere */ 261 #ifdef UNDOTRACE 262 vudump("before vmacchng hairy case"); 263 #endif 264 savedot = dot; savedol = dol; savecursor = cursor; 265 CP(savelb, linebuf); 266 nlines = dol - zero; 267 while ((line *) endcore - truedol < nlines) 268 if (morelines() < 0) 269 return; /* or could be fatal error */ 270 copyw(truedol+1, zero+1, nlines); 271 truedol += nlines; 272 273 #ifdef UNDOTRACE 274 visdump("before vundo"); 275 #endif 276 /* Restore state as it was at beginning of macro */ 277 vundo(0); 278 #ifdef UNDOTRACE 279 visdump("after vundo"); 280 vudump("after vundo"); 281 #endif 282 283 /* Do the saveall we should have done then */ 284 saveall(); 285 #ifdef UNDOTRACE 286 vudump("after saveall"); 287 #endif 288 289 /* Restore current state from where saved */ 290 more = savedol - dol; /* amount we shift everything by */ 291 if (more) 292 (*(more>0 ? copywR : copyw))(savedol+1, dol+1, truedol-dol); 293 unddol += more; truedol += more; undap2 += more; 294 295 truedol -= nlines; 296 copyw(zero+1, truedol+1, nlines); 297 dot = savedot; dol = savedol ; cursor = savecursor; 298 CP(linebuf, savelb); 299 vch_mac = VC_MANYCHANGE; 300 301 /* Arrange that no further undo saving happens within macro */ 302 otchng = tchng; /* Copied this line blindly - bug? */ 303 inopen = -1; /* no need to save since it had to be 1 or -1 before */ 304 vundkind = VMANY; 305 #ifdef UNDOTRACE 306 vudump("after vmacchng"); 307 #endif 308 break; 309 case VC_NOTINMAC: 310 case VC_MANYCHANGE: 311 /* Nothing to do for various reasons. */ 312 break; 313 } 314 } 315 316 /* 317 * Initialize undo information before an append. 318 */ 319 void 320 vnoapp(void) 321 { 322 323 vUD1 = vUD2 = cursor; 324 } 325 326 /* 327 * All the rest of the motion sequences have one or more 328 * cases to deal with. In the case wdot == 0, operation 329 * is totally within current line, from cursor to wcursor. 330 * If wdot is given, but wcursor is 0, then operation affects 331 * the inclusive line range. The hardest case is when both wdot 332 * and wcursor are given, then operation affects from line dot at 333 * cursor to line wdot at wcursor. 334 */ 335 336 /* 337 * Move is simple, except for moving onto new lines in hardcopy open mode. 338 */ 339 int 340 vmove(void) 341 { 342 int cnt; 343 344 if (wdot) { 345 if (wdot < one || wdot > dol) { 346 (void) beep(); 347 return (0); 348 } 349 cnt = wdot - dot; 350 wdot = NOLINE; 351 if (cnt) 352 killU(); 353 vupdown(cnt, wcursor); 354 return (0); 355 } 356 357 /* 358 * When we move onto a new line, save information for U undo. 359 */ 360 if (vUNDdot != dot) { 361 vUNDsav = *dot; 362 vUNDcurs = wcursor; 363 vUNDdot = dot; 364 } 365 366 /* 367 * In hardcopy open, type characters to left of cursor 368 * on new line, or back cursor up if its to left of where we are. 369 * In any case if the current line is ``rubbled'' i.e. has trashy 370 * looking overstrikes on it or \'s from deletes, we reprint 371 * so it is more comprehensible (and also because we can't work 372 * if we let it get more out of sync since column() won't work right. 373 */ 374 if (state == HARDOPEN) { 375 unsigned char *cp; 376 if (rubble) { 377 int c; 378 int oldhold = hold; 379 380 sethard(); 381 cp = wcursor; 382 c = *cp; 383 *cp = 0; 384 hold |= HOLDDOL; 385 (void) vreopen(WTOP, lineDOT(), vcline); 386 hold = oldhold; 387 *cp = c; 388 } else if (wcursor > cursor) { 389 int length; 390 char multic[MULTI_BYTE_MAX]; 391 wchar_t wchar; 392 vfixcurs(); 393 for (cp = cursor; *cp && cp < wcursor;) { 394 length = mbtowc(&wchar, (char *)cp, MULTI_BYTE_MAX); 395 if(length == 0) 396 putchar(' '); 397 else if(length < 0) { 398 putoctal = 1; 399 putchar(*cp++); 400 putoctal = 0; 401 } else { 402 cp += length; 403 putchar(wchar); 404 } 405 } 406 } 407 } 408 vsetcurs(wcursor); 409 return (0); 410 } 411 412 /* 413 * Delete operator. 414 * 415 * Hard case of deleting a range where both wcursor and wdot 416 * are specified is treated as a special case of change and handled 417 * by vchange (although vchange may pass it back if it degenerates 418 * to a full line range delete.) 419 */ 420 int 421 vdelete(unsigned char c) 422 { 423 unsigned char *cp; 424 int i; 425 426 if (wdot) { 427 if (wcursor) { 428 (void) vchange('d'); 429 return (0); 430 } 431 if ((i = xdw()) < 0) 432 return (0); 433 if (state != VISUAL) { 434 vgoto(LINE(0), 0); 435 (void) vputchar('@'); 436 } 437 wdot = dot; 438 vremote(i, delete, 0); 439 notenam = (unsigned char *)"delete"; 440 DEL[0] = 0; 441 killU(); 442 vreplace(vcline, i, 0); 443 if (wdot > dol) 444 vcline--; 445 vrepaint(NOSTR); 446 return (0); 447 } 448 if (wcursor < linebuf) 449 wcursor = linebuf; 450 if (cursor == wcursor) { 451 (void) beep(); 452 return (0); 453 } 454 i = vdcMID(); 455 cp = cursor; 456 setDEL(); 457 CP(cp, wcursor); 458 if (cp > linebuf && (cp[0] == 0 || c == '#')) 459 cp = lastchr(linebuf, cp); 460 if (state == HARDOPEN) { 461 bleep(i, cp); 462 cursor = cp; 463 return (0); 464 } 465 physdc(lcolumn(cursor), i); 466 DEPTH(vcline) = 0; 467 if(MB_CUR_MAX > 1) 468 rewrite = _ON; 469 (void) vreopen(LINE(vcline), lineDOT(), vcline); 470 if(MB_CUR_MAX > 1) 471 rewrite = _OFF; 472 vsyncCL(); 473 vsetcurs(cp); 474 return (0); 475 } 476 477 /* 478 * Change operator. 479 * 480 * In a single line we mark the end of the changed area with '$'. 481 * On multiple whole lines, we clear the lines first. 482 * Across lines with both wcursor and wdot given, we delete 483 * and sync then append (but one operation for undo). 484 */ 485 int 486 vchange(unsigned char c) 487 { 488 unsigned char *cp; 489 int i, ind, cnt; 490 line *addr; 491 492 if (wdot) { 493 /* 494 * Change/delete of lines or across line boundaries. 495 */ 496 if ((cnt = xdw()) < 0) 497 return (0); 498 getDOT(); 499 if (wcursor && cnt == 1) { 500 /* 501 * Not really. 502 */ 503 wdot = 0; 504 if (c == 'd') { 505 (void) vdelete(c); 506 return (0); 507 } 508 goto smallchange; 509 } 510 if (cursor && wcursor) { 511 /* 512 * Across line boundaries, but not 513 * necessarily whole lines. 514 * Construct what will be left. 515 */ 516 *cursor = 0; 517 strcpy(genbuf, linebuf); 518 getline(*wdot); 519 if (strlen(genbuf) + strlen(wcursor) > LBSIZE - 2) { 520 getDOT(); 521 (void) beep(); 522 return (0); 523 } 524 strcat(genbuf, wcursor); 525 if (c == 'd' && *vpastwh(genbuf) == 0) { 526 /* 527 * Although this is a delete 528 * spanning line boundaries, what 529 * would be left is all white space, 530 * so take it all away. 531 */ 532 wcursor = 0; 533 getDOT(); 534 op = 0; 535 notpart(lastreg); 536 notpart('1'); 537 (void) vdelete(c); 538 return (0); 539 } 540 ind = -1; 541 } else if (c == 'd' && wcursor == 0) { 542 (void) vdelete(c); 543 return (0); 544 } else 545 /* 546 * We are just substituting text for whole lines, 547 * so determine the first autoindent. 548 */ 549 if (value(vi_LISP) && value(vi_AUTOINDENT)) 550 ind = lindent(dot); 551 else 552 ind = whitecnt(linebuf); 553 i = vcline >= 0 ? LINE(vcline) : WTOP; 554 555 /* 556 * Delete the lines from the buffer, 557 * and remember how the partial stuff came about in 558 * case we are told to put. 559 */ 560 addr = dot; 561 vremote(cnt, delete, 0); 562 setpk(); 563 notenam = (unsigned char *)"delete"; 564 if (c != 'd') 565 notenam = (unsigned char *)"change"; 566 /* 567 * If DEL[0] were nonzero, put would put it back 568 * rather than the deleted lines. 569 */ 570 DEL[0] = 0; 571 if (cnt > 1) 572 killU(); 573 574 /* 575 * Now hack the screen image coordination. 576 */ 577 vreplace(vcline, cnt, 0); 578 wdot = NOLINE; 579 noteit(0); 580 vcline--; 581 if (addr <= dol) 582 dot--; 583 584 /* 585 * If this is a across line delete/change, 586 * cursor stays where it is; just splice together the pieces 587 * of the new line. Otherwise generate a autoindent 588 * after a S command. 589 */ 590 if (ind >= 0) { 591 *genindent(ind) = 0; 592 vdoappend(genbuf); 593 } else { 594 vmcurs = cursor; 595 strcLIN(genbuf); 596 vdoappend(linebuf); 597 } 598 599 /* 600 * Indicate a change on hardcopies by 601 * erasing the current line. 602 */ 603 if (c != 'd' && state != VISUAL && state != HARDOPEN) { 604 int oldhold = hold; 605 606 hold |= HOLDAT, vclrlin(i, dot), hold = oldhold; 607 } 608 609 /* 610 * Open the line (logically) on the screen, and 611 * update the screen tail. Unless we are really a delete 612 * go off and gather up inserted characters. 613 */ 614 vcline++; 615 if (vcline < 0) 616 vcline = 0; 617 vopen(dot, i); 618 vsyncCL(); 619 noteit(1); 620 if (c != 'd') { 621 if (ind >= 0) { 622 cursor = linebuf; 623 linebuf[0] = 0; 624 vfixcurs(); 625 } else { 626 ind = 0; 627 vcursat(cursor); 628 } 629 vappend('x', 1, ind); 630 return (0); 631 } 632 if (*cursor == 0 && cursor > linebuf) 633 cursor = lastchr(linebuf, cursor); 634 vrepaint(cursor); 635 return (0); 636 } 637 638 smallchange: 639 /* 640 * The rest of this is just low level hacking on changes 641 * of small numbers of characters. 642 */ 643 if (wcursor < linebuf) 644 wcursor = linebuf; 645 if (cursor == wcursor) { 646 (void) beep(); 647 return (0); 648 } 649 i = vdcMID(); 650 cp = cursor; 651 if (state != HARDOPEN) 652 vfixcurs(); 653 654 /* 655 * Put out the \\'s indicating changed text in hardcopy, 656 * or mark the end of the change with $ if not hardcopy. 657 */ 658 if (state == HARDOPEN) 659 bleep(i, cp); 660 else { 661 vcursbef(wcursor); 662 putchar('$'); 663 i = cindent(); 664 } 665 666 /* 667 * Remember the deleted text for possible put, 668 * and then prepare and execute the input portion of the change. 669 */ 670 cursor = cp; 671 setDEL(); 672 CP(cursor, wcursor); 673 if (state != HARDOPEN) { 674 /* place cursor at beginning of changing text */ 675 vgotoCL(lcolumn(cp)); 676 doomed = i - cindent(); 677 } else { 678 /* 679 sethard(); 680 wcursor = cursor; 681 cursor = linebuf; 682 vgoto(outline, value(vi_NUMBER) << 3); 683 vmove(); 684 */ 685 doomed = 0; 686 } 687 prepapp(); 688 vappend('c', 1, 0); 689 return (0); 690 } 691 692 /* 693 * Open new lines. 694 */ 695 void 696 voOpen(int c, int cnt) 697 { 698 int ind = 0, i; 699 short oldhold = hold; 700 701 vsave(); 702 setLAST(); 703 if (value(vi_AUTOINDENT)) 704 ind = whitecnt(linebuf); 705 if (c == 'O') { 706 vcline--; 707 dot--; 708 if (dot > zero) 709 getDOT(); 710 } 711 if (value(vi_AUTOINDENT)) { 712 if (value(vi_LISP)) 713 ind = lindent(dot + 1); 714 } 715 killU(); 716 prepapp(); 717 if (FIXUNDO) 718 vundkind = VMANY; 719 if (state != VISUAL) 720 c = WBOT + 1; 721 else { 722 c = vcline < 0 ? WTOP - cnt : LINE(vcline) + DEPTH(vcline); 723 if (c < ZERO) 724 c = ZERO; 725 i = LINE(vcline + 1) - c; 726 if (i < cnt && c <= WBOT && (!insert_line || !delete_line)) 727 vinslin(c, cnt - i, vcline); 728 } 729 *genindent(ind) = 0; 730 vdoappend(genbuf); 731 vcline++; 732 oldhold = hold; 733 hold |= HOLDROL; 734 vopen(dot, c); 735 hold = oldhold; 736 if (value(vi_SLOWOPEN)) 737 /* 738 * Oh, so lazy! 739 */ 740 vscrap(); 741 else 742 vsync1(LINE(vcline)); 743 cursor = linebuf; 744 linebuf[0] = 0; 745 vappend('o', cnt, ind); 746 } 747 748 /* 749 * > < and = shift operators. 750 * 751 * Note that =, which aligns lisp, is just a ragged sort of shift, 752 * since it never distributes text between lines. 753 */ 754 unsigned char vshnam[2] = { 'x', 0 }; 755 756 int 757 vshftop(void) 758 { 759 line *addr; 760 int cnt; 761 762 if ((cnt = xdw()) < 0) 763 return (0); 764 addr = dot; 765 vremote(cnt, vshift, 0); 766 vshnam[0] = op; 767 notenam = vshnam; 768 dot = addr; 769 vreplace(vcline, cnt, cnt); 770 if (state == HARDOPEN) 771 vcnt = 0; 772 vrepaint(NOSTR); 773 return (0); 774 } 775 776 /* 777 * !. 778 * 779 * Filter portions of the buffer through unix commands. 780 */ 781 int 782 vfilter(void) 783 { 784 line *addr; 785 int cnt; 786 unsigned char *oglobp; 787 short d; 788 789 if ((cnt = xdw()) < 0) 790 return (0); 791 if (vglobp) 792 vglobp = (unsigned char *)uxb; 793 if (readecho('!')) 794 return (0); 795 oglobp = globp; globp = genbuf + 1; 796 d = peekc; ungetchar(0); 797 CATCH 798 fixech(); 799 unix0(0, 0); 800 ONERR 801 splitw = 0; 802 ungetchar(d); 803 vrepaint(cursor); 804 globp = oglobp; 805 return (0); 806 ENDCATCH 807 ungetchar(d); globp = oglobp; 808 addr = dot; 809 CATCH 810 vgoto(WECHO, 0); flusho(); 811 vremote(cnt, vi_filter, 2); 812 ONERR 813 vdirty(0, lines); 814 ENDCATCH 815 if (dot == zero && dol > zero) 816 dot = one; 817 splitw = 0; 818 notenam = (unsigned char *)""; 819 /* 820 * BUG: we shouldn't be depending on what undap2 and undap1 are, 821 * since we may be inside a macro. What's really wanted is the 822 * number of lines we read from the filter. However, the mistake 823 * will be an overestimate so it only results in extra work, 824 * it shouldn't cause any real mess-ups. 825 */ 826 vreplace(vcline, cnt, undap2 - undap1); 827 dot = addr; 828 if (dot > dol) { 829 dot--; 830 vcline--; 831 } 832 vrepaint(NOSTR); 833 return (0); 834 } 835 836 /* 837 * Xdw exchanges dot and wdot if appropriate and also checks 838 * that wdot is reasonable. Its name comes from 839 * xchange dotand wdot 840 */ 841 int 842 xdw(void) 843 { 844 unsigned char *cp; 845 int cnt; 846 /* 847 register int notp = 0; 848 */ 849 850 if (wdot == NOLINE || wdot < one || wdot > dol) { 851 (void) beep(); 852 return (-1); 853 } 854 vsave(); 855 setLAST(); 856 if (dot > wdot || (dot == wdot && wcursor != 0 && cursor > wcursor)) { 857 line *addr; 858 859 vcline -= dot - wdot; 860 addr = dot; dot = wdot; wdot = addr; 861 cp = cursor; cursor = wcursor; wcursor = cp; 862 } 863 /* 864 * If a region is specified but wcursor is at the beginning 865 * of the last line, then we move it to be the end of the 866 * previous line (actually off the end). 867 */ 868 if (cursor && wcursor == linebuf && wdot > dot) { 869 wdot--; 870 getDOT(); 871 if (vpastwh(linebuf) >= cursor) 872 wcursor = 0; 873 else { 874 getline(*wdot); 875 wcursor = strend(linebuf); 876 getDOT(); 877 } 878 /* 879 * Should prepare in caller for possible dot == wdot. 880 */ 881 } 882 cnt = wdot - dot + 1; 883 if (vreg) { 884 vremote(cnt, YANKreg, vreg); 885 /* 886 if (notp) 887 notpart(vreg); 888 */ 889 } 890 891 /* 892 * Kill buffer code. If delete operator is c or d, then save 893 * the region in numbered buffers. 894 * 895 * BUG: This may be somewhat inefficient due 896 * to the way named buffer are implemented, 897 * necessitating some optimization. 898 */ 899 vreg = 0; 900 if (any(op, "cd")) { 901 vremote(cnt, YANKreg, '1'); 902 /* 903 if (notp) 904 notpart('1'); 905 */ 906 } 907 return (cnt); 908 } 909 910 /* 911 * Routine for vremote to call to implement shifts. 912 */ 913 int 914 vshift(void) 915 { 916 917 shift(op, 1); 918 return (0); 919 } 920 921 /* 922 * Replace a single character with the next input character. 923 * A funny kind of insert. 924 */ 925 void 926 vrep(int cnt) 927 { 928 int i, c; 929 unsigned char *endcurs; 930 endcurs = cursor; 931 for(i = 1; i <= cnt; i++) { 932 if(!*endcurs) { 933 (void) beep(); 934 return; 935 } 936 endcurs = nextchr(endcurs); 937 } 938 i = lcolumn(endcurs); 939 vcursat(cursor); 940 doomed = i - cindent(); 941 /* 942 * TRANSLATION_NOTE 943 * "r" is a terse mode message that corresponds to 944 * "REPLACE 1 CHAR". 945 * Translated message of "r" must be 1 character (not byte). 946 * Or, just leave it. 947 */ 948 if(value(vi_TERSE)) 949 vshowmode(gettext("r")); 950 else 951 vshowmode(gettext("REPLACE 1 CHAR")); 952 if (!vglobp) { 953 c = getesc(); 954 if (c == 0) { 955 vshowmode(""); 956 vfixcurs(); 957 return; 958 } 959 ungetkey(c); 960 } 961 CP(vutmp, linebuf); 962 if (FIXUNDO) 963 vundkind = VCHNG; 964 wcursor = endcurs; 965 vUD1 = cursor; vUD2 = wcursor; 966 CP(cursor, wcursor); 967 prepapp(); 968 vappend('r', cnt, 0); 969 *lastcp++ = INS[0]; 970 setLAST(); 971 } 972 973 /* 974 * Yank. 975 * 976 * Yanking to string registers occurs for free (essentially) 977 * in the routine xdw(). 978 */ 979 int 980 vyankit(void) 981 { 982 int cnt; 983 984 if (wdot) { 985 if ((cnt = xdw()) < 0) 986 return (0); 987 vremote(cnt, yank, 0); 988 setpk(); 989 notenam = (unsigned char *)"yank"; 990 if (FIXUNDO) 991 vundkind = VNONE; 992 DEL[0] = 0; 993 wdot = NOLINE; 994 if (notecnt <= vcnt - vcline && notecnt < value(vi_REPORT)) 995 notecnt = 0; 996 vrepaint(cursor); 997 return (0); 998 } else { 999 /* 1000 * For one line y<motion> commands, eg. 2yw, save the 1001 * command for a subsequent [count]. 1002 */ 1003 setLAST(); 1004 } 1005 takeout(DEL); 1006 return (0); 1007 1008 } 1009 1010 /* 1011 * Set pkill variables so a put can 1012 * know how to put back partial text. 1013 * This is necessary because undo needs the complete 1014 * line images to be saved, while a put wants to trim 1015 * the first and last lines. The compromise 1016 * is for put to be more clever. 1017 */ 1018 void 1019 setpk(void) 1020 { 1021 1022 if (wcursor) { 1023 pkill[0] = cursor; 1024 pkill[1] = wcursor; 1025 } 1026 } 1027