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