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