xref: /titanic_50/usr/src/cmd/vi/port/ex_vadj.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2000 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 /* Copyright (c) 1981 Regents of the University of California */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 #include "ex.h"
36 #include "ex_tune.h"
37 #include "ex_tty.h"
38 #include "ex_vis.h"
39 
40 /*
41  * Routines to deal with management of logical versus physical
42  * display, opening and redisplaying lines on the screen, and
43  * use of intelligent terminal operations.  Routines to deal with
44  * screen cleanup after a change.
45  */
46 
47 /*
48  * Display a new line at physical line p, returning
49  * the depth of the newly displayed line.  We may decide
50  * to expand the window on an intelligent terminal if it is
51  * less than a full screen by deleting a line above the top of the
52  * window before doing an insert line to keep all the good text
53  * on the screen in which case the line may actually end up
54  * somewhere other than line p.
55  */
56 vopen(tp, p)
57 	line *tp;
58 	int p;
59 {
60 	register int cnt;
61 	register struct vlinfo *vp, *vpc;
62 
63 #ifdef ADEBUG
64 	if (trace != NULL)
65 		tfixnl(), fprintf(trace, "vopen(%d, %d)\n", lineno(tp), p);
66 #endif
67 	if (state != VISUAL) {
68 		if (vcnt)
69 			if (hold & HOLDROL)
70 				vup1();
71 			else
72 				vclean();
73 
74 		/*
75 		 * Forget all that we once knew.
76 		 */
77 		vcnt = vcline = 0;
78 		p = WBOT; LASTLINE = WBOT + 1;
79 		state = bastate;
80 		WTOP = basWTOP;
81 		WLINES = basWLINES;
82 	}
83 	vpc = &vlinfo[vcline];
84 	for (vp = &vlinfo[vcnt]; vp >= vpc; vp--)
85 		vlcopy(vp[1], vp[0]);
86 	vcnt++;
87 	if (Pline == numbline)
88 		/*
89 		 * Dirtying all the lines is rather inefficient
90 		 * internally, but number mode is used rarely
91 		 * and so it's not worth optimizing.
92 		 */
93 		vdirty(vcline+1, WECHO);
94 	getline(*tp);
95 
96 	/*
97 	 * If we are opening at the top of the window, can try a window
98 	 * expansion at the top.
99 	 */
100 	if (state == VISUAL && vcline == 0 && vcnt > 1 && p > ZERO) {
101 		cnt = p + vdepth() - LINE(1);
102 		if (cnt > 0) {
103 			p -= cnt;
104 			if (p < ZERO)
105 				p = ZERO;
106 			WTOP = p;
107 			WLINES = WBOT - WTOP + 1;
108 		}
109 	}
110 	vpc->vliny = p, vpc->vdepth = 0, vpc->vflags = 0;
111 	cnt = vreopen(p, lineno(tp), vcline);
112 	if (vcline + 1 == vcnt)
113 		LINE(vcnt) = LINE(vcline) + cnt;
114 }
115 
116 /*
117  * Redisplay logical line l at physical line p with line number lineno.
118  */
119 vreopen(p, lineno, l)
120 	int p, lineno, l;
121 {
122 	register int d;
123 	register struct vlinfo *vp = &vlinfo[l];
124 
125 	d = vp->vdepth;
126 	if (d == 0 || (vp->vflags & VDIRT))
127 		vp->vdepth = d = vdepth();
128 	vp->vliny = p, vp->vflags &= ~VDIRT;
129 
130 	/*
131 	 * Try to win by making the screen larger rather than inserting
132 	 * a line and driving text off the bottom.
133 	 */
134 	p = vglitchup(l, 0);
135 
136 	/*
137 	 * BUG:	Should consider using clr_eol here to clear to end of line.
138 	 *	As it stands we always strike over the current text.
139 	 *	Since often the current text is the same as what
140 	 *	we are overstriking with, it tends not to show.
141 	 *	On the other hand if it is different and we end up
142 	 *	spacing out a lot of text, we could have won with
143 	 *	a clr_eol.  This is probably worthwhile at low speed
144 	 *	only however, since clearly computation will be
145 	 *	necessary to determine which way to go.
146 	 */
147 	vigoto(p, 0);
148 	pline(lineno);
149 
150 	if (state == VISUAL && l == vcline && vp->vliny < 0) {
151 		vp->vliny = 0;
152 		vscrap();
153 		return d;
154 	}
155 
156 	/*
157 	 * When we are typing part of a line for hardcopy open, don't
158 	 * want to type the '$' marking an end of line if in list mode.
159 	 */
160 	if (hold & HOLDDOL)
161 		return (d);
162 	if (Putchar == listchar)
163 		putchar('$');
164 
165 	/*
166 	 * Optimization of cursor motion may prevent screen rollup if the
167 	 * line has blanks/tabs at the end unless we force the cursor to appear
168 	 * on the last line segment.
169 	 */
170 	if (vp->vliny + d - 1 > WBOT)
171 		vcsync();
172 
173 	/*
174 	 * Switch into hardcopy open mode if we are in one line (adm3)
175 	 * open mode and this line is now too long.  If in hardcopy
176 	 * open mode, then call sethard to move onto the next line
177 	 * with appropriate positioning.
178 	 */
179 	if (state == ONEOPEN) {
180 		WCOLS = OCOLUMNS;
181 		if (vdepth() > 1) {
182 			WCOLS = TUBECOLS;
183 			sethard();
184 		} else
185 			WCOLS = TUBECOLS;
186 	} else if (state == HARDOPEN)
187 		sethard();
188 
189 	/*
190 	 * Unless we filled (completely) the last line we typed on,
191 	 * we have to clear to the end of the line
192 	 * in case stuff is left from before.
193 	 */
194 	if (vp->vliny + d > destline) {
195 		if (insert_null_glitch && destcol == WCOLS)
196 			vigoto(vp->vliny + d - 1, 0);
197 		vclreol();
198 	}
199 	return (d);
200 }
201 
202 /*
203  * Real work for winning growing of window at top
204  * when inserting in the middle of a partially full
205  * screen on an intelligent terminal.  We have as argument
206  * the logical line number to be inserted after, and the offset
207  * from that line where the insert will go.
208  * We look at the picture of depths and positions, and if we can
209  * delete some (blank) lines from the top of the screen so that
210  * later inserts will not push stuff off the bottom.
211  */
212 vglitchup(l, o)
213 	int l, o;
214 {
215 	register struct vlinfo *vp = &vlinfo[l];
216 	register int need;
217 	register int p = vp->vliny;
218 	short oldhold, oldheldech;
219 	bool glitched = 0;
220 
221  	if (l < vcnt - 1) {
222 		need = p + vp->vdepth - (vp+1)->vliny;
223 		if (need > 0) {
224 			if (state == VISUAL && WTOP - ZERO >= need && insert_line && delete_line) {
225 				glitched++;
226 				WTOP -= need;
227 				WLINES = WBOT - WTOP + 1;
228 				p -= need;
229 				if (p + o == WTOP) {
230 					vp->vliny = WTOP;
231 					return (WTOP + o);
232 				}
233 				vdellin(WTOP, need, -1);
234 				oldheldech = heldech;
235 				oldhold = hold;
236 				hold |= HOLDECH;
237 			}
238 			vinslin((vp+1)->vliny, need, l);
239 			if (glitched) {
240 				hold = oldhold;
241 				heldech = oldheldech;
242 			}
243 		}
244 	} else
245 		vp[1].vliny = vp[0].vliny + vp->vdepth;
246 	return (p + o);
247 }
248 
249 /*
250  * Insert cnt blank lines before line p,
251  * logically and (if supported) physically.
252  */
253 vinslin(p, cnt, l)
254 	register int p, cnt;
255 	int l;
256 {
257 	register int i;
258 	bool could = 1;
259 
260 #ifdef ADEBUG
261 	if (trace)
262 		tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l);
263 #endif
264 	if (p + cnt > WBOT && clr_eos) {
265 		/*
266 		 * Really quick -- clear to end of screen.
267 		 */
268 		cnt = WECHO + 1 - p;
269 		vgoto(p, 0), vputp(clr_eos, cnt);
270 		vclrech(1);
271 		vadjAL(p, cnt);
272 	} else if (scroll_reverse && p == WTOP && costSR < costAL) {
273 		/*
274 		 * Use reverse scroll mode of the terminal, at
275 		 * the top of the window.  Reverse linefeed works
276 		 * too, since we only use it from line WTOP.
277 		 */
278 		for (i = cnt; i > 0; i--) {
279 			vgoto(p, 0), vputp(scroll_reverse, 0);
280 			if (i > 1 && (hold & HOLDAT) == 0)
281 				putchar('@');
282 			/*
283 			 * If we are at the top of the screen, and the
284 			 * terminal retains display above, then we
285 			 * should try to clear to end of line.
286 			 * Have to use clr_eol since we don't remember what is
287 			 * actually on the line.
288 			 */
289 			if (clr_eol && (memory_above || p != 0))
290 				vputp(clr_eol, 1);
291 		}
292 		vadjAL(p, cnt);
293 	} else if (insert_line) {
294 		/*
295 		 * Use insert line.
296 		 */
297 		vgoto(p, 0);
298 		if (parm_insert_line && (cnt>1 || *insert_line==0)) {
299 			/* insert cnt lines.  Should do @'s too. */
300 			vputp(tparm(parm_insert_line, cnt, p), WECHO+1-p);
301 		}
302 		else if (change_scroll_region && *insert_line==0) {
303 			/* vt100 change scrolling region to fake insert_line */
304 			vputp(save_cursor, 1);
305 			vputp(tparm(change_scroll_region, p, lines-1), 1);
306 			vputp(restore_cursor, 1);	/* change_scroll_region homes stupid cursor */
307 			for (i=cnt; i>0; i--)
308 				vputp(scroll_reverse, 1);	/* should do @'s */
309 			vputp(tparm(change_scroll_region, 0, lines-1), 1);
310 			vputp(restore_cursor, 1);	/* Once again put it back */
311 		}
312 		else {
313 			vputp(insert_line, WECHO + 1 - p);
314 			for (i = cnt - 1; i > 0; i--) {
315 				vgoto(outline+1, 0);
316 				vputp(insert_line, WECHO + 1 - outline);
317 				if ((hold & HOLDAT) == 0)
318 					putchar('@');
319 			}
320 		}
321 		vadjAL(p, cnt);
322 	} else
323 		could = 0;
324 	vopenup(cnt, could, l);
325 }
326 
327 /*
328  * Logically open up after line l, cnt of them.
329  * We need to know if it was done ``physically'' since in this
330  * case we accept what the hardware gives us.  If we have to do
331  * it ourselves (brute force) we will squish out @ lines in the process
332  * if this will save us work.
333  */
334 vopenup(cnt, could, l)
335 	int cnt;
336 	bool could;
337 {
338 	register struct vlinfo *vc = &vlinfo[l + 1];
339 	register struct vlinfo *ve = &vlinfo[vcnt];
340 
341 #ifdef ADEBUG
342 	if (trace)
343 		tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l);
344 #endif
345 	if (could)
346 		/*
347 		 * This will push @ lines down the screen,
348 		 * just as the hardware did.  Since the default
349 		 * for intelligent terminals is to never have @
350 		 * lines on the screen, this should never happen,
351 		 * and the code makes no special effort to be nice in this
352 		 * case, e.g. squishing out the @ lines by delete lines
353 		 * before doing append lines.
354 		 */
355 		for (; vc <= ve; vc++)
356 			vc->vliny += cnt;
357 	else {
358 		/*
359 		 * Will have to clean up brute force eventually,
360 		 * so push the line data around as little as possible.
361 		 */
362 		vc->vliny += cnt, vc->vflags |= VDIRT;
363 		while (vc < ve) {
364 			register int i = vc->vliny + vc->vdepth;
365 
366 			vc++;
367 			if (i <= vc->vliny)
368 				break;
369 			vc->vliny = i, vc->vflags |= VDIRT;
370 		}
371 	}
372 	vscrap();
373 }
374 
375 /*
376  * Adjust data structure internally to account for insertion of
377  * blank lines on the screen.
378  */
379 vadjAL(p, cnt)
380 	int p, cnt;
381 {
382 	wchar_t *tlines[TUBELINES];
383 	register int from, to;
384 
385 #ifdef ADEBUG
386 	if (trace)
387 		tfixnl(), fprintf(trace, "vadjal(%d, %d)\n", p, cnt);
388 #endif
389 	copy(tlines, vtube, sizeof vtube);	/*SASSIGN*/
390 	for (from = p, to = p + cnt; to <= WECHO; from++, to++)
391 		vtube[to] = tlines[from];
392 	for (to = p; from <= WECHO; from++, to++) {
393 		vtube[to] = tlines[from];
394 		vclrbyte(vtube[to], WCOLS);
395 	}
396 	/*
397 	 * Have to clear the echo area since its contents aren't
398 	 * necessarily consistent with the rest of the display.
399 	 */
400 	vclrech(0);
401 }
402 
403 /*
404  * Roll the screen up logically and physically
405  * so that line dl is the bottom line on the screen.
406  */
407 vrollup(dl)
408 	int dl;
409 {
410 	register int cnt;
411 	register int dc = destcol;
412 
413 #ifdef ADEBUG
414 	if (trace)
415 		tfixnl(), fprintf(trace, "vrollup(%d)\n", dl);
416 #endif
417 	cnt = dl - (splitw ? WECHO : WBOT);
418 	if (splitw && (state == VISUAL || state == CRTOPEN))
419 		holdupd = 1;
420 	vmoveitup(cnt, 1);
421 	vscroll(cnt);
422 	destline = dl - cnt, destcol = dc;
423 }
424 
425 vup1()
426 {
427 
428 	vrollup(WBOT + 1);
429 }
430 
431 /*
432  * Scroll the screen up cnt lines physically.
433  * If doclr is true, do a clear eol if the terminal
434  * has standout (to prevent it from scrolling up)
435  */
436 vmoveitup(cnt, doclr)
437 	register int cnt;
438 	bool doclr;
439 {
440 
441 	if (cnt == 0)
442 		return;
443 #ifdef ADEBUG
444 	if (trace)
445 		tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt);
446 #endif
447 	if (doclr)
448 		vclrech(0);
449 	if (scroll_forward) {
450 		destline = WECHO;
451 		destcol = (NONL ? 0 : outcol % WCOLS);
452 		fgoto();
453 		while (cnt > 0)
454 			vputp(scroll_forward, 0), cnt--;
455 	}
456 	else {
457 		destline = WECHO + cnt;
458 		destcol = (NONL ? 0 : outcol % WCOLS);
459 		fgoto();
460 		if (state == ONEOPEN || state == HARDOPEN) {
461 			outline = destline = 0;
462 			vclrbyte(vtube[0], WCOLS);
463 		}
464 	}
465 	/* Get rid of line we just rolled up */
466 	if (doclr && memory_below && clr_eol)
467 		vclrech(0);
468 }
469 
470 /*
471  * Scroll the screen up cnt lines logically.
472  */
473 vscroll(cnt)
474 	register int cnt;
475 {
476 	register int from, to;
477 	wchar_t *tlines[TUBELINES];
478 
479 #ifdef ADEBUG
480 	if (trace)
481 		fprintf(trace, "vscroll(%d)\n", cnt);
482 #endif
483 	if (cnt < 0 || cnt > TUBELINES)
484 		error(gettext("Internal error: vscroll"));
485 	if (cnt == 0)
486 		return;
487 	copy(tlines, vtube, sizeof vtube);
488 	for (to = ZERO, from = ZERO + cnt; to <= WECHO - cnt; to++, from++)
489 		vtube[to] = tlines[from];
490 	for (from = ZERO; to <= WECHO; to++, from++) {
491 		vtube[to] = tlines[from];
492 		vclrbyte(vtube[to], WCOLS);
493 	}
494 	for (from = 0; from <= vcnt; from++)
495 		LINE(from) -= cnt;
496 }
497 
498 /*
499  * Discard logical lines due to physical wandering off the screen.
500  */
501 vscrap()
502 {
503 	register int i, j;
504 
505 #ifdef ADEBUG
506 	if (trace)
507 		tfixnl(), fprintf(trace, "vscrap\n"), tvliny();
508 #endif
509 	if (splitw)
510 		return;
511 	if (vcnt && WBOT != WECHO && LINE(0) < WTOP && LINE(0) >= ZERO) {
512 		WTOP = LINE(0);
513 		WLINES = WBOT - WTOP + 1;
514 	}
515 	for (j = 0; j < vcnt; j++)
516 		if (LINE(j) >= WTOP) {
517 			if (j == 0)
518 				break;
519 			/*
520 			 * Discard the first j physical lines off the top.
521 			 */
522 			vcnt -= j, vcline -= j;
523 			for (i = 0; i <= vcnt; i++)
524 				vlcopy(vlinfo[i], vlinfo[i + j]);
525 			break;
526 		}
527 	/*
528 	 * Discard lines off the bottom.
529 	 */
530 	if (vcnt) {
531 		for (j = 0; j <= vcnt; j++)
532 			if (LINE(j) > WBOT || LINE(j) + DEPTH(j) - 1 > WBOT) {
533 				vcnt = j;
534 				break;
535 			}
536 		if (vcnt == 0)
537 			LASTLINE = 0;
538 		else
539 			LASTLINE = LINE(vcnt-1) + DEPTH(vcnt-1);
540 	}
541 #ifdef ADEBUG
542 	if (trace)
543 		tvliny();
544 #endif
545 	/*
546 	 * May have no lines!
547 	 */
548 }
549 
550 /*
551  * Repaint the screen, with cursor at curs, aftern an arbitrary change.
552  * Handle notification on large changes.
553  */
554 vrepaint(curs)
555 	unsigned char *curs;
556 {
557 
558 	wdot = NOLINE;
559 	/*
560 	 * In open want to notify first.
561 	 */
562 	noteit(0);
563 	vscrap();
564 
565 	/*
566 	 * Deal with a totally useless display.
567 	 */
568 	if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) {
569 		register line *odol = dol;
570 
571 		vcnt = 0;
572 		if (holdupd)
573 			if (state == VISUAL)
574 				(void)peekkey();
575 			else
576 				vup1();
577 		holdupd = 0;
578 		if (odol == zero)
579 			fixzero();
580 		vcontext(dot, '.');
581 		noteit(1);
582 		if (noteit(1) == 0 && odol == zero) {
583 			CATCH
584 				error(gettext("No lines in buffer"));
585 			ENDCATCH
586 			linebuf[0] = 0;
587 			splitw = 0;
588 		}
589 		vnline(curs);
590 		return;
591 	}
592 
593 	/*
594 	 * Have some useful displayed text; refresh it.
595 	 */
596 	getDOT();
597 
598 	/*
599 	 * This is for boundary conditions in open mode.
600 	 */
601 	if (FLAGS(0) & VDIRT)
602 		vsync(WTOP);
603 
604 	/*
605 	 * If the current line is after the last displayed line
606 	 * or the bottom of the screen, then special effort is needed
607 	 * to get it on the screen.  We first try a redraw at the
608 	 * last line on the screen, hoping it will fill in where @
609 	 * lines are now.  If this doesn't work, then roll it onto
610 	 * the screen.
611 	 */
612 	if (vcline >= vcnt || LINE(vcline) > WBOT) {
613 		short oldhold = hold;
614 		hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold;
615 		if (vcline >= vcnt) {
616 			register int i = vcline - vcnt + 1;
617 
618 			dot -= i;
619 			vcline -= i;
620 			vroll(i);
621 		} else
622 			vsyncCL();
623 	} else
624 		vsync(vcline > 0 ? LINE(vcline - 1) : WTOP);
625 
626 	/*
627 	 * Notification on large change for visual
628 	 * has to be done last or we may lose
629 	 * the echo area with redisplay.
630 	 */
631 	noteit(1);
632 
633 	/*
634 	 * Finally.  Move the cursor onto the current line.
635 	 */
636 	vnline(curs);
637 }
638 
639 /*
640  * Fully cleanup the screen, leaving no @ lines except at end when
641  * line after last won't completely fit.  The routine vsync is
642  * more conservative and much less work on dumb terminals.
643  */
644 vredraw(p)
645 	register int p;
646 {
647 	register int l;
648 	register line *tp;
649 	unsigned char temp[LBSIZE];
650 	bool anydl = 0;
651 	short oldhold = hold;
652 
653 #ifdef ADEBUG
654 	if (trace)
655 		tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny();
656 #endif
657 	if (holdupd) {
658 		holdupd = 3;
659 		return;
660 	}
661 	if (state == HARDOPEN || splitw)
662 		return;
663 	if (p < 0 /* || p > WECHO */)
664 		error(gettext("Internal error: vredraw"));
665 
666 	/*
667 	 * Trim the ragged edges (lines which are off the screen but
668 	 * not yet logically discarded), save the current line, and
669 	 * search for first logical line affected by the redraw.
670 	 */
671 	vscrap();
672 	CP(temp, linebuf);
673 	l = 0;
674 	tp = dot - vcline;
675 	if (vcnt == 0)
676 		LINE(0) = WTOP;
677 	while (l < vcnt && LINE(l) < p)
678 		l++, tp++;
679 
680 	/*
681 	 * We hold off echo area clearing during the redraw in deference
682 	 * to a final clear of the echo area at the end if appropriate.
683 	 */
684 	heldech = 0;
685 	hold |= HOLDECH;
686 	for (; l < vcnt && Peekkey != ATTN; l++) {
687 		if (l == vcline)
688 			strcLIN(temp);
689 		else
690 			getline(*tp);
691 
692 		/*
693 		 * Delete junk between displayed lines.
694 		 */
695 		if (LINE(l) != LINE(l + 1) && LINE(l) != p) {
696 			if (anydl == 0 && memory_below && clr_eos) {
697 				hold = oldhold;
698 				vclrech(0);
699 				anydl = 1;
700 				hold |= HOLDECH;
701 				heldech = 0;
702 			}
703 			vdellin(p, LINE(l) - p, l);
704 		}
705 
706 		/*
707 		 * If line image is not know to be up to date, then
708 		 * redisplay it;  else just skip onward.
709 		 */
710 		LINE(l) = p;
711 		if (FLAGS(l) & VDIRT) {
712 			DEPTH(l) = vdepth();
713 			if (l != vcline && p + DEPTH(l) - 1 > WBOT) {
714 				vscrap();
715 				break;
716 			}
717 			FLAGS(l) &= ~VDIRT;
718 			vreopen(p, lineno(tp), l);
719 			p = LINE(l) + DEPTH(l);
720 		} else
721 			p += DEPTH(l);
722 		tp++;
723 	}
724 
725 	/*
726 	 * That takes care of lines which were already partially displayed.
727 	 * Now try to fill the rest of the screen with text.
728 	 */
729 	if (state == VISUAL && p <= WBOT) {
730 		int ovcline = vcline;
731 
732 		vcline = l;
733 		for (; tp <= dol && Peekkey != ATTN; tp++) {
734 			getline(*tp);
735 			if (p + vdepth() - 1 > WBOT)
736 				break;
737 			vopen(tp, p);
738 			p += DEPTH(vcline);
739 			vcline++;
740 		}
741 		vcline = ovcline;
742 	}
743 
744 	/*
745 	 * That's all the text we can get on.
746 	 * Now rest of lines (if any) get either a ~ if they
747 	 * are past end of file, or an @ if the next line won't fit.
748 	 */
749 	for (; p <= WBOT && Peekkey != ATTN; p++)
750 		vclrlin(p, tp);
751 	strcLIN(temp);
752 	hold = oldhold;
753 	if (heldech)
754 		vclrech(0);
755 #ifdef ADEBUG
756 	if (trace)
757 		tvliny();
758 #endif
759 }
760 
761 /*
762  * Do the real work in deleting cnt lines starting at line p from
763  * the display.  First affected line is line l.
764  */
765 vdellin(p, cnt, l)
766 	int p, cnt, l;
767 {
768 	register int i;
769 
770 	if (cnt == 0)
771 		return;
772 	if (delete_line == NOSTR || cnt < 0) {
773 		/*
774 		 * Can't do it; just remember that line l is munged.
775 		 */
776 		FLAGS(l) |= VDIRT;
777 		return;
778 	}
779 #ifdef ADEBUG
780 	if (trace)
781 		tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l);
782 #endif
783 	/*
784 	 * Send the deletes to the screen and then adjust logical
785 	 * and physical internal data structures.
786 	 */
787 	vgoto(p, 0);
788 	if (parm_delete_line && (cnt>1 || *delete_line==0)) {
789 		vputp(tparm(parm_delete_line, cnt, p), WECHO-p);
790 	}
791 	else if (change_scroll_region && *delete_line==0) {
792 		/* vt100: fake delete_line by changing scrolling region */
793 		vputp(save_cursor, 1);	/* Save since change_scroll_region homes stupid cursor */
794 		vputp(tparm(change_scroll_region, p, lines-1), 1);
795 		vputp(tparm(cursor_address, lines-1, 0), 1);/* Go to lower left corner */
796 		for (i=0; i<cnt; i++)		/* .. and scroll cnt times */
797 			putch('\n');		/* should check NL too */
798 		vputp(tparm(change_scroll_region, 0, lines-1), 1);/* restore scrolling region */
799 		vputp(restore_cursor, 1);			/* put cursor back */
800 	}
801 	else {
802 		for (i = 0; i < cnt; i++)
803 			vputp(delete_line, WECHO - p);
804 	}
805 	vadjDL(p, cnt);
806 	vcloseup(l, cnt);
807 }
808 /*
809  * Adjust internal physical screen image to account for deleted lines.
810  */
811 vadjDL(p, cnt)
812 	int p, cnt;
813 {
814 	wchar_t *tlines[TUBELINES];
815 	register int from, to;
816 
817 #ifdef ADEBUG
818 	if (trace)
819 		tfixnl(), fprintf(trace, "vadjDL(%d, %d)\n", p, cnt);
820 #endif
821 	/*
822 	 * Would like to use structured assignment but early
823 	 * v7 compiler (released with phototypesetter for v6)
824 	 * can't hack it.
825 	 */
826 	copy(tlines, vtube, sizeof vtube);	/*SASSIGN*/
827 	for (from = p + cnt, to = p; from <= WECHO; from++, to++)
828 		vtube[to] = tlines[from];
829 	for (from = p; to <= WECHO; from++, to++) {
830 		vtube[to] = tlines[from];
831 		vclrbyte(vtube[to], WCOLS);
832 	}
833 }
834 /*
835  * Sync the screen, like redraw but more lazy and willing to leave
836  * @ lines on the screen.  VsyncCL syncs starting at the current line.
837  * In any case, if the redraw option is set then all syncs map to redraws
838  * as if vsync didn't exist.
839  */
840 vsyncCL()
841 {
842 
843 	vsync(LINE(vcline));
844 }
845 
846 vsync(p)
847 	register int p;
848 {
849 
850 	if (value(vi_REDRAW))
851 		vredraw(p);
852 	else
853 		vsync1(p);
854 }
855 
856 /*
857  * The guts of a sync.  Similar to redraw but
858  * just less ambitious.
859  */
860 vsync1(p)
861 	register int p;
862 {
863 	register int l;
864 	unsigned char temp[LBSIZE];
865 	register struct vlinfo *vp = &vlinfo[0];
866 	short oldhold = hold;
867 
868 #ifdef ADEBUG
869 	if (trace)
870 		tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny();
871 #endif
872 	if (holdupd) {
873 		if (holdupd < 3)
874 			holdupd = 2;
875 		return;
876 	}
877 	if (state == HARDOPEN || splitw)
878 		return;
879 	vscrap();
880 	CP(temp, linebuf);
881 	if (vcnt == 0)
882 		LINE(0) = WTOP;
883 	l = 0;
884 	while (l < vcnt && vp->vliny < p)
885 		l++, vp++;
886 	heldech = 0;
887 	hold |= HOLDECH;
888 	while (p <= WBOT && Peekkey != ATTN) {
889 		/*
890 		 * Want to put a line here if not in visual and first line
891 		 * or if there are lies left and this line starts before
892 		 * the current line, or if this line is piled under the
893 		 * next line (vreplace does this and we undo it).
894 		 */
895 		if (l == 0 && state != VISUAL ||
896 		    (l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) {
897 			if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) {
898 				if (l == vcline)
899 					strcLIN(temp);
900 				else
901 					getline(dot[l - vcline]);
902 				/*
903 				 * Be careful that a long line doesn't cause the
904 				 * screen to shoot up.
905 				 */
906 				if (l != vcline && (vp->vflags & VDIRT)) {
907 					vp->vdepth = vdepth();
908 					vp->vflags &= ~VDIRT;
909 					if (p + vp->vdepth - 1 > WBOT)
910 						break;
911 				}
912 				vreopen(p, lineDOT() + (l - vcline), l);
913 			}
914 			p = vp->vliny + vp->vdepth;
915 			vp++;
916 			l++;
917 		} else
918 			/*
919 			 * A physical line between logical lines,
920 			 * so we settle for an @ at the beginning.
921 			 */
922 			vclrlin(p, dot + (l - vcline)), p++;
923 	}
924 	strcLIN(temp);
925 	hold = oldhold;
926 	if (heldech)
927 		vclrech(0);
928 }
929 
930 /*
931  * Subtract (logically) cnt physical lines from the
932  * displayed position of lines starting with line l.
933  */
934 vcloseup(l, cnt)
935 	int l;
936 	register int cnt;
937 {
938 	register int i;
939 
940 #ifdef ADEBUG
941 	if (trace)
942 		tfixnl(), fprintf(trace, "vcloseup(%d, %d)\n", l, cnt);
943 #endif
944 	for (i = l + 1; i <= vcnt; i++)
945 		LINE(i) -= cnt;
946 }
947 
948 /*
949  * Workhorse for rearranging line descriptors on changes.
950  * The idea here is that, starting with line l, cnt lines
951  * have been replaced with newcnt lines.  All of these may
952  * be ridiculous, i.e. l may be -1000, cnt 50 and newcnt 0,
953  * since we may be called from an undo after the screen has
954  * moved a lot.  Thus we have to be careful.
955  *
956  * Many boundary conditions here.
957  */
958 vreplace(l, cnt, newcnt)
959 	int l, cnt, newcnt;
960 {
961 	register int from, to, i;
962 	bool savenote = 0;
963 
964 #ifdef ADEBUG
965 	if (trace) {
966 		tfixnl(), fprintf(trace, "vreplace(%d, %d, %d)\n", l, cnt, newcnt);
967 		tvliny();
968 	}
969 #endif
970 	if (l >= vcnt)
971 		return;
972 	if (l < 0) {
973 		if (l + cnt < 0) {
974 			/*
975 			 * Nothing on the screen is relevant.
976 			 * Settle for redrawing from scratch (later).
977 			 */
978 			vcnt = 0;
979 			return;
980 		}
981 		/*
982 		 * Normalize l to top of screen; the add is
983 		 * really a subtract from cnt since l is negative.
984 		 */
985 		cnt += l;
986 		l = 0;
987 
988 		/*
989 		 * Unseen lines were affected so notify (later).
990 		 */
991 		savenote++;
992 	}
993 
994 	/*
995 	 * These shouldn't happen
996 	 * but would cause great havoc.
997 	 */
998 	if (cnt < 0)
999 		cnt = 0;
1000 	if (newcnt < 0)
1001 		newcnt = 0;
1002 
1003 	/*
1004 	 * Surely worthy of note if more than report
1005 	 * lines were changed.
1006 	 */
1007 	if (cnt > value(vi_REPORT) || newcnt > value(vi_REPORT))
1008 		savenote++;
1009 
1010 	/*
1011 	 * Same number of lines affected as on screen, and we
1012 	 * can insert and delete lines.  Thus we just type
1013 	 * over them, since otherwise we will push them
1014 	 * slowly off the screen, a clear lose.
1015 	 */
1016 	if (cnt == newcnt || vcnt - l == newcnt && insert_line && delete_line) {
1017 		if (cnt > 1 && l + cnt > vcnt)
1018 			savenote++;
1019 		vdirty(l, newcnt);
1020 	} else {
1021 		/*
1022 		 * Lines are going away, squish them out.
1023 		 */
1024 		if (cnt > 0) {
1025 			/*
1026 			 * If non-displayed lines went away,
1027 			 * always notify.
1028 			 */
1029 			if (cnt > 1 && l + cnt > vcnt)
1030 				savenote++;
1031 			if (l + cnt >= vcnt)
1032 				cnt = vcnt - l;
1033 			else
1034 				for (from = l + cnt, to = l; from <= vcnt; to++, from++)
1035 					vlcopy(vlinfo[to], vlinfo[from]);
1036 			vcnt -= cnt;
1037 		}
1038 		/*
1039 		 * Open up space for new lines appearing.
1040 		 * All new lines are piled in the same place,
1041 		 * and will be unpiled by vredraw/vsync, which
1042 		 * inserts lines in front as it unpiles.
1043 		 */
1044 		if (newcnt > 0) {
1045 			/*
1046 			 * Newlines are appearing which may not show,
1047 			 * so notify (this is only approximately correct
1048 			 * when long lines are present).
1049 			 */
1050 			if (newcnt > 1 && l + newcnt > vcnt + 1)
1051 				savenote++;
1052 
1053 			/*
1054 			 * If there will be more lines than fit, then
1055 			 * just throw way the rest of the stuff on the screen.
1056 			 */
1057 			if (l + newcnt > WBOT && insert_line && delete_line) {
1058 				vcnt = l;
1059 				goto skip;
1060 			}
1061 			from = vcnt, to = vcnt + newcnt;
1062 			i = TUBELINES - to;
1063 			if (i < 0)
1064 				from += i, to += i;
1065 			vcnt = to;
1066 			for (; from >= l; from--, to--)
1067 				vlcopy(vlinfo[to], vlinfo[from]);
1068 			for (from = to + 1, to = l; to < l + newcnt && to <= WBOT + 1; to++) {
1069 				LINE(to) = LINE(from);
1070 				DEPTH(to) = 0;
1071 				FLAGS(to) = VDIRT;
1072 			}
1073 		}
1074 	}
1075 skip:
1076 	if (Pline == numbline && cnt != newcnt)
1077 		/*
1078 		 * When lines positions are shifted, the numbers
1079 		 * will be wrong.
1080 		 */
1081 		vdirty(l, WECHO);
1082 	if (!savenote)
1083 		notecnt = 0;
1084 #ifdef ADEBUG
1085 	if (trace)
1086 		tvliny();
1087 #endif
1088 }
1089 
1090 /*
1091  * Start harcopy open.
1092  * Print an image of the line to the left of the cursor
1093  * under the full print of the line and position the cursor.
1094  * If we are in a scroll ^D within hardcopy open then all this
1095  * is suppressed.
1096  */
1097 sethard()
1098 {
1099 
1100 	if (state == VISUAL)
1101 		return;
1102 	rubble = 0;
1103 	state = HARDOPEN;
1104 	if (hold & HOLDROL)
1105 		return;
1106 	vup1();
1107 	LINE(0) = WBOT;
1108 	if (Pline == numbline)
1109 		vgoto(WBOT, 0), printf("%6d  ", lineDOT());
1110 }
1111 
1112 /*
1113  * Mark the lines starting at base for i lines
1114  * as dirty so that they will be checked for correct
1115  * display at next sync/redraw.
1116  */
1117 vdirty(base, i)
1118 	register int base, i;
1119 {
1120 	register int l;
1121 
1122 	for (l = base; l < vcnt; l++) {
1123 		if (--i < 0)
1124 			return;
1125 		FLAGS(l) |= VDIRT;
1126 	}
1127 }
1128