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