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