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