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