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 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 * Tricky thing here is slowopen. This causes display updating 696 * to be held off so that 300 baud dumb terminals don't lose badly. 697 * This also suppressed counts, which otherwise say how many blank 698 * space to open up. Counts are also suppressed on intelligent terminals. 699 * Actually counts are obsoleted, since if your terminal is slow 700 * you are better off with slowopen. 701 */ 702 void 703 voOpen(int c, int cnt) 704 { 705 int ind = 0, i; 706 short oldhold = hold; 707 708 if (value(vi_SLOWOPEN) || value(vi_REDRAW) && insert_line && delete_line) 709 cnt = 1; 710 vsave(); 711 setLAST(); 712 if (value(vi_AUTOINDENT)) 713 ind = whitecnt(linebuf); 714 if (c == 'O') { 715 vcline--; 716 dot--; 717 if (dot > zero) 718 getDOT(); 719 } 720 if (value(vi_AUTOINDENT)) { 721 if (value(vi_LISP)) 722 ind = lindent(dot + 1); 723 } 724 killU(); 725 prepapp(); 726 if (FIXUNDO) 727 vundkind = VMANY; 728 if (state != VISUAL) 729 c = WBOT + 1; 730 else { 731 c = vcline < 0 ? WTOP - cnt : LINE(vcline) + DEPTH(vcline); 732 if (c < ZERO) 733 c = ZERO; 734 i = LINE(vcline + 1) - c; 735 if (i < cnt && c <= WBOT && (!insert_line || !delete_line)) 736 vinslin(c, cnt - i, vcline); 737 } 738 *genindent(ind) = 0; 739 vdoappend(genbuf); 740 vcline++; 741 oldhold = hold; 742 hold |= HOLDROL; 743 vopen(dot, c); 744 hold = oldhold; 745 if (value(vi_SLOWOPEN)) 746 /* 747 * Oh, so lazy! 748 */ 749 vscrap(); 750 else 751 vsync1(LINE(vcline)); 752 cursor = linebuf; 753 linebuf[0] = 0; 754 vappend('o', 1, ind); 755 } 756 757 /* 758 * > < and = shift operators. 759 * 760 * Note that =, which aligns lisp, is just a ragged sort of shift, 761 * since it never distributes text between lines. 762 */ 763 unsigned char vshnam[2] = { 'x', 0 }; 764 765 int 766 vshftop(void) 767 { 768 line *addr; 769 int cnt; 770 771 if ((cnt = xdw()) < 0) 772 return (0); 773 addr = dot; 774 vremote(cnt, vshift, 0); 775 vshnam[0] = op; 776 notenam = vshnam; 777 dot = addr; 778 vreplace(vcline, cnt, cnt); 779 if (state == HARDOPEN) 780 vcnt = 0; 781 vrepaint(NOSTR); 782 return (0); 783 } 784 785 /* 786 * !. 787 * 788 * Filter portions of the buffer through unix commands. 789 */ 790 int 791 vfilter(void) 792 { 793 line *addr; 794 int cnt; 795 unsigned char *oglobp; 796 short d; 797 798 if ((cnt = xdw()) < 0) 799 return (0); 800 if (vglobp) 801 vglobp = (unsigned char *)uxb; 802 if (readecho('!')) 803 return (0); 804 oglobp = globp; globp = genbuf + 1; 805 d = peekc; ungetchar(0); 806 CATCH 807 fixech(); 808 unix0(0, 0); 809 ONERR 810 splitw = 0; 811 ungetchar(d); 812 vrepaint(cursor); 813 globp = oglobp; 814 return (0); 815 ENDCATCH 816 ungetchar(d); globp = oglobp; 817 addr = dot; 818 CATCH 819 vgoto(WECHO, 0); flusho(); 820 vremote(cnt, vi_filter, 2); 821 ONERR 822 vdirty(0, lines); 823 ENDCATCH 824 if (dot == zero && dol > zero) 825 dot = one; 826 splitw = 0; 827 notenam = (unsigned char *)""; 828 /* 829 * BUG: we shouldn't be depending on what undap2 and undap1 are, 830 * since we may be inside a macro. What's really wanted is the 831 * number of lines we read from the filter. However, the mistake 832 * will be an overestimate so it only results in extra work, 833 * it shouldn't cause any real mess-ups. 834 */ 835 vreplace(vcline, cnt, undap2 - undap1); 836 dot = addr; 837 if (dot > dol) { 838 dot--; 839 vcline--; 840 } 841 vrepaint(NOSTR); 842 return (0); 843 } 844 845 /* 846 * Xdw exchanges dot and wdot if appropriate and also checks 847 * that wdot is reasonable. Its name comes from 848 * xchange dotand wdot 849 */ 850 int 851 xdw(void) 852 { 853 unsigned char *cp; 854 int cnt; 855 /* 856 register int notp = 0; 857 */ 858 859 if (wdot == NOLINE || wdot < one || wdot > dol) { 860 (void) beep(); 861 return (-1); 862 } 863 vsave(); 864 setLAST(); 865 if (dot > wdot || (dot == wdot && wcursor != 0 && cursor > wcursor)) { 866 line *addr; 867 868 vcline -= dot - wdot; 869 addr = dot; dot = wdot; wdot = addr; 870 cp = cursor; cursor = wcursor; wcursor = cp; 871 } 872 /* 873 * If a region is specified but wcursor is at the beginning 874 * of the last line, then we move it to be the end of the 875 * previous line (actually off the end). 876 */ 877 if (cursor && wcursor == linebuf && wdot > dot) { 878 wdot--; 879 getDOT(); 880 if (vpastwh(linebuf) >= cursor) 881 wcursor = 0; 882 else { 883 getline(*wdot); 884 wcursor = strend(linebuf); 885 getDOT(); 886 } 887 /* 888 * Should prepare in caller for possible dot == wdot. 889 */ 890 } 891 cnt = wdot - dot + 1; 892 if (vreg) { 893 vremote(cnt, YANKreg, vreg); 894 /* 895 if (notp) 896 notpart(vreg); 897 */ 898 } 899 900 /* 901 * Kill buffer code. If delete operator is c or d, then save 902 * the region in numbered buffers. 903 * 904 * BUG: This may be somewhat inefficient due 905 * to the way named buffer are implemented, 906 * necessitating some optimization. 907 */ 908 vreg = 0; 909 if (any(op, "cd")) { 910 vremote(cnt, YANKreg, '1'); 911 /* 912 if (notp) 913 notpart('1'); 914 */ 915 } 916 return (cnt); 917 } 918 919 /* 920 * Routine for vremote to call to implement shifts. 921 */ 922 int 923 vshift(void) 924 { 925 926 shift(op, 1); 927 return (0); 928 } 929 930 /* 931 * Replace a single character with the next input character. 932 * A funny kind of insert. 933 */ 934 void 935 vrep(int cnt) 936 { 937 int i, c; 938 unsigned char *endcurs; 939 endcurs = cursor; 940 for(i = 1; i <= cnt; i++) { 941 if(!*endcurs) { 942 (void) beep(); 943 return; 944 } 945 endcurs = nextchr(endcurs); 946 } 947 i = lcolumn(endcurs); 948 vcursat(cursor); 949 doomed = i - cindent(); 950 /* 951 * TRANSLATION_NOTE 952 * "r" is a terse mode message that corresponds to 953 * "REPLACE 1 CHAR". 954 * Translated message of "r" must be 1 character (not byte). 955 * Or, just leave it. 956 */ 957 if(value(vi_TERSE)) 958 vshowmode(gettext("r")); 959 else 960 vshowmode(gettext("REPLACE 1 CHAR")); 961 if (!vglobp) { 962 c = getesc(); 963 if (c == 0) { 964 vshowmode(""); 965 vfixcurs(); 966 return; 967 } 968 ungetkey(c); 969 } 970 CP(vutmp, linebuf); 971 if (FIXUNDO) 972 vundkind = VCHNG; 973 wcursor = endcurs; 974 vUD1 = cursor; vUD2 = wcursor; 975 CP(cursor, wcursor); 976 prepapp(); 977 vappend('r', cnt, 0); 978 *lastcp++ = INS[0]; 979 setLAST(); 980 } 981 982 /* 983 * Yank. 984 * 985 * Yanking to string registers occurs for free (essentially) 986 * in the routine xdw(). 987 */ 988 int 989 vyankit(void) 990 { 991 int cnt; 992 993 if (wdot) { 994 if ((cnt = xdw()) < 0) 995 return (0); 996 vremote(cnt, yank, 0); 997 setpk(); 998 notenam = (unsigned char *)"yank"; 999 if (FIXUNDO) 1000 vundkind = VNONE; 1001 DEL[0] = 0; 1002 wdot = NOLINE; 1003 if (notecnt <= vcnt - vcline && notecnt < value(vi_REPORT)) 1004 notecnt = 0; 1005 vrepaint(cursor); 1006 return (0); 1007 } 1008 takeout(DEL); 1009 return (0); 1010 1011 } 1012 1013 /* 1014 * Set pkill variables so a put can 1015 * know how to put back partial text. 1016 * This is necessary because undo needs the complete 1017 * line images to be saved, while a put wants to trim 1018 * the first and last lines. The compromise 1019 * is for put to be more clever. 1020 */ 1021 void 1022 setpk(void) 1023 { 1024 1025 if (wcursor) { 1026 pkill[0] = cursor; 1027 pkill[1] = wcursor; 1028 } 1029 } 1030