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