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