xref: /original-bsd/usr.bin/ex/ex_vops.c (revision a0a7d8f4)
1 /* Copyright (c) 1981 Regents of the University of California */
2 static char *sccsid = "@(#)ex_vops.c	7.4	03/27/85";
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 	int oldmask;
630 
631 	if (value(SLOWOPEN) || value(REDRAW) && AL && DL)
632 		cnt = 1;
633 	oldmask = sigblock(sigmask(SIGWINCH));
634 	vsave();
635 	setLAST();
636 	if (value(AUTOINDENT))
637 		ind = whitecnt(linebuf);
638 	if (c == 'O') {
639 		vcline--;
640 		dot--;
641 		if (dot > zero)
642 			getDOT();
643 	}
644 	if (value(AUTOINDENT)) {
645 #ifdef LISPCODE
646 		if (value(LISP))
647 			ind = lindent(dot + 1);
648 #endif
649 	}
650 	killU();
651 	prepapp();
652 	if (FIXUNDO)
653 		vundkind = VMANY;
654 	if (state != VISUAL)
655 		c = WBOT + 1;
656 	else {
657 		c = vcline < 0 ? WTOP - cnt : LINE(vcline) + DEPTH(vcline);
658 		if (c < ZERO)
659 			c = ZERO;
660 		i = LINE(vcline + 1) - c;
661 		if (i < cnt && c <= WBOT && (!AL || !DL))
662 			vinslin(c, cnt - i, vcline);
663 	}
664 	*genindent(ind) = 0;
665 	vdoappend(genbuf);
666 	vcline++;
667 	oldhold = hold;
668 	hold |= HOLDROL;
669 	vopen(dot, c);
670 	hold = oldhold;
671 	if (value(SLOWOPEN))
672 		/*
673 		 * Oh, so lazy!
674 		 */
675 		vscrap();
676 	else
677 		vsync1(LINE(vcline));
678 	cursor = linebuf;
679 	linebuf[0] = 0;
680 	vappend('o', 1, ind);
681 	(void)sigsetmask(oldmask);
682 }
683 
684 /*
685  * > < and = shift operators.
686  *
687  * Note that =, which aligns lisp, is just a ragged sort of shift,
688  * since it never distributes text between lines.
689  */
690 char	vshnam[2] = { 'x', 0 };
691 
692 vshftop()
693 {
694 	register line *addr;
695 	register int cnt;
696 
697 	if ((cnt = xdw()) < 0)
698 		return;
699 	addr = dot;
700 	vremote(cnt, vshift, 0);
701 	vshnam[0] = op;
702 	notenam = vshnam;
703 	dot = addr;
704 	vreplace(vcline, cnt, cnt);
705 	if (state == HARDOPEN)
706 		vcnt = 0;
707 	vrepaint(NOSTR);
708 }
709 
710 /*
711  * !.
712  *
713  * Filter portions of the buffer through unix commands.
714  */
715 vfilter()
716 {
717 	register line *addr;
718 	register int cnt;
719 	char *oglobp;
720 	short d;
721 
722 	if ((cnt = xdw()) < 0)
723 		return;
724 	if (vglobp)
725 		vglobp = uxb;
726 	if (readecho('!'))
727 		return;
728 	oglobp = globp; globp = genbuf + 1;
729 	d = peekc; ungetchar(0);
730 	CATCH
731 		fixech();
732 		unix0(0);
733 	ONERR
734 		splitw = 0;
735 		ungetchar(d);
736 		vrepaint(cursor);
737 		globp = oglobp;
738 		return;
739 	ENDCATCH
740 	ungetchar(d); globp = oglobp;
741 	addr = dot;
742 	CATCH
743 		vgoto(WECHO, 0); flusho();
744 		vremote(cnt, filter, 2);
745 	ONERR
746 		vdirty(0, LINES);
747 	ENDCATCH
748 	if (dot == zero && dol > zero)
749 		dot = one;
750 	splitw = 0;
751 	notenam = "";
752 	/*
753 	 * BUG: we shouldn't be depending on what undap2 and undap1 are,
754 	 * since we may be inside a macro.  What's really wanted is the
755 	 * number of lines we read from the filter.  However, the mistake
756 	 * will be an overestimate so it only results in extra work,
757 	 * it shouldn't cause any real screwups.
758 	 */
759 	vreplace(vcline, cnt, undap2 - undap1);
760 	dot = addr;
761 	if (dot > dol) {
762 		dot--;
763 		vcline--;
764 	}
765 	vrepaint(NOSTR);
766 }
767 
768 /*
769  * Xdw exchanges dot and wdot if appropriate and also checks
770  * that wdot is reasonable.  Its name comes from
771  *	xchange dotand wdot
772  */
773 xdw()
774 {
775 	register char *cp;
776 	register int cnt;
777 /*
778 	register int notp = 0;
779  */
780 
781 	if (wdot == NOLINE || wdot < one || wdot > dol) {
782 		beep();
783 		return (-1);
784 	}
785 	vsave();
786 	setLAST();
787 	if (dot > wdot || (dot == wdot && wcursor != 0 && cursor > wcursor)) {
788 		register line *addr;
789 
790 		vcline -= dot - wdot;
791 		addr = dot; dot = wdot; wdot = addr;
792 		cp = cursor; cursor = wcursor; wcursor = cp;
793 	}
794 	/*
795 	 * If a region is specified but wcursor is at the begining
796 	 * of the last line, then we move it to be the end of the
797 	 * previous line (actually off the end).
798 	 */
799 	if (cursor && wcursor == linebuf && wdot > dot) {
800 		wdot--;
801 		getDOT();
802 		if (vpastwh(linebuf) >= cursor)
803 			wcursor = 0;
804 		else {
805 			getline(*wdot);
806 			wcursor = strend(linebuf);
807 			getDOT();
808 		}
809 		/*
810 		 * Should prepare in caller for possible dot == wdot.
811 		 */
812 	}
813 	cnt = wdot - dot + 1;
814 	if (vreg) {
815 		vremote(cnt, YANKreg, vreg);
816 /*
817 		if (notp)
818 			notpart(vreg);
819  */
820 	}
821 
822 	/*
823 	 * Kill buffer code.  If delete operator is c or d, then save
824 	 * the region in numbered buffers.
825 	 *
826 	 * BUG:			This may be somewhat inefficient due
827 	 *			to the way named buffer are implemented,
828 	 *			necessitating some optimization.
829 	 */
830 	vreg = 0;
831 	if (any(op, "cd")) {
832 		vremote(cnt, YANKreg, '1');
833 /*
834 		if (notp)
835 			notpart('1');
836  */
837 	}
838 	return (cnt);
839 }
840 
841 /*
842  * Routine for vremote to call to implement shifts.
843  */
844 vshift()
845 {
846 
847 	shift(op, 1);
848 }
849 
850 /*
851  * Replace a single character with the next input character.
852  * A funny kind of insert.
853  */
854 vrep(cnt)
855 	register int cnt;
856 {
857 	register int i, c;
858 
859 	if (cnt > strlen(cursor)) {
860 		beep();
861 		return;
862 	}
863 	i = column(cursor + cnt - 1);
864 	vcursat(cursor);
865 	doomed = i - cindent();
866 	if (!vglobp) {
867 		c = getesc();
868 		if (c == 0) {
869 			vfixcurs();
870 			return;
871 		}
872 		ungetkey(c);
873 	}
874 	CP(vutmp, linebuf);
875 	if (FIXUNDO)
876 		vundkind = VCHNG;
877 	wcursor = cursor + cnt;
878 	vUD1 = cursor; vUD2 = wcursor;
879 	CP(cursor, wcursor);
880 	prepapp();
881 	vappend('r', cnt, 0);
882 	*lastcp++ = INS[0];
883 	setLAST();
884 }
885 
886 /*
887  * Yank.
888  *
889  * Yanking to string registers occurs for free (essentially)
890  * in the routine xdw().
891  */
892 vyankit()
893 {
894 	register int cnt;
895 
896 	if (wdot) {
897 		if ((cnt = xdw()) < 0)
898 			return;
899 		vremote(cnt, yank, 0);
900 		setpk();
901 		notenam = "yank";
902 		if (FIXUNDO)
903 			vundkind = VNONE;
904 		DEL[0] = 0;
905 		wdot = NOLINE;
906 		if (notecnt <= vcnt - vcline && notecnt < value(REPORT))
907 			notecnt = 0;
908 		vrepaint(cursor);
909 		return;
910 	}
911 	takeout(DEL);
912 }
913 
914 /*
915  * Set pkill variables so a put can
916  * know how to put back partial text.
917  * This is necessary because undo needs the complete
918  * line images to be saved, while a put wants to trim
919  * the first and last lines.  The compromise
920  * is for put to be more clever.
921  */
922 setpk()
923 {
924 
925 	if (wcursor) {
926 		pkill[0] = cursor;
927 		pkill[1] = wcursor;
928 	}
929 }
930