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