summaryrefslogtreecommitdiff
path: root/ex_vadj.c
diff options
context:
space:
mode:
Diffstat (limited to 'ex_vadj.c')
-rw-r--r--ex_vadj.c1162
1 files changed, 1162 insertions, 0 deletions
diff --git a/ex_vadj.c b/ex_vadj.c
new file mode 100644
index 0000000..0bb62c7
--- /dev/null
+++ b/ex_vadj.c
@@ -0,0 +1,1162 @@
+/*
+ * This code contains changes by
+ * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
+ *
+ * Conditions 1, 2, and 4 and the no-warranty notice below apply
+ * to these changes.
+ *
+ *
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * Redistributions of source code and documentation must retain the
+ * above copyright notice, this list of conditions and the following
+ * disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of
+ * other contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
+ * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+#ifdef DOSCCS
+static char sccsid[] = "@(#)ex_vadj.c 1.11 (gritter) 3/4/05";
+#endif
+#endif
+
+/* from ex_vadj.c 7.9 (Berkeley) 6/7/85 */
+
+#include "ex.h"
+#include "ex_tty.h"
+#include "ex_vis.h"
+
+/*
+ * Routines to deal with management of logical versus physical
+ * display, opening and redisplaying lines on the screen, and
+ * use of intelligent terminal operations. Routines to deal with
+ * screen cleanup after a change.
+ */
+
+/*
+ * Display a new line at physical line p, returning
+ * the depth of the newly displayed line. We may decide
+ * to expand the window on an intelligent terminal if it is
+ * less than a full screen by deleting a line above the top of the
+ * window before doing an insert line to keep all the good text
+ * on the screen in which case the line may actually end up
+ * somewhere other than line p.
+ */
+void
+vopen(line *tp, int p)
+{
+ register int cnt;
+ register struct vlinfo *vp, *vpc;
+
+#ifdef ADEBUG
+ if (trace != NULL)
+ tfixnl(), fprintf(trace, "vopen(%d, %d)\n", lineno(tp), p);
+#endif
+ if (state != VISUAL) {
+ if (vcnt)
+ if (hold & HOLDROL)
+ vup1();
+ else
+ vclean();
+
+ /*
+ * Forget all that we once knew.
+ */
+ vcnt = vcline = 0;
+ p = WBOT; LASTLINE = WBOT + 1;
+ state = bastate;
+ WTOP = basWTOP;
+ WLINES = basWLINES;
+ }
+ vpc = &vlinfo[vcline];
+ for (vp = &vlinfo[vcnt]; vp >= vpc; vp--)
+ vlcopy(vp[1], vp[0]);
+ vcnt++;
+ if (Pline == numbline)
+ /*
+ * Dirtying all the lines is rather inefficient
+ * internally, but number mode is used rarely
+ * and so its not worth optimizing.
+ */
+ vdirty(vcline+1, WECHO);
+ getline(*tp);
+
+ /*
+ * If we are opening at the top of the window, can try a window
+ * expansion at the top.
+ */
+ if (state == VISUAL && vcline == 0 && vcnt > 1 && p > ZERO) {
+ cnt = p + vdepth() - LINE(1);
+ if (cnt > 0) {
+ p -= cnt;
+ if (p < ZERO)
+ p = ZERO;
+ WTOP = p;
+ WLINES = WBOT - WTOP + 1;
+ }
+ }
+ vpc->vliny = p, vpc->vdepth = 0, vpc->vflags = 0;
+ cnt = vreopen(p, lineno(tp), vcline);
+ if (vcline + 1 == vcnt)
+ LINE(vcnt) = LINE(vcline) + cnt;
+}
+
+/*
+ * Redisplay logical line l at physical line p with line number lineno.
+ */
+int
+vreopen(int p, int lineno, int l)
+{
+ register int d;
+ register struct vlinfo *vp = &vlinfo[l];
+
+ if (p < 0)
+ error("Line too long to fit on screen");
+ d = vp->vdepth;
+ if (d == 0 || (vp->vflags & VDIRT))
+ vp->vdepth = d = vdepth();
+ vp->vliny = p, vp->vflags &= ~VDIRT;
+
+ /*
+ * Try to win by making the screen larger rather than inserting
+ * a line and driving text off the bottom.
+ */
+ p = vglitchup(l, 0);
+
+ /*
+ * BUG: Should consider using CE here to clear to end of line.
+ * As it stands we always strike over the current text.
+ * Since often the current text is the same as what
+ * we are overstriking with, it tends not to show.
+ * On the other hand if it is different and we end up
+ * spacing out a lot of text, we could have won with
+ * a CE. This is probably worthwhile at low speed
+ * only however, since clearly computation will be
+ * necessary to determine which way to go.
+ */
+ vigoto(p, 0);
+ pline(lineno);
+
+ /*
+ * When we are typing part of a line for hardcopy open, don't
+ * want to type the '$' marking an end of line if in list mode.
+ */
+ if (hold & HOLDDOL)
+ return (d);
+ if (Putchar == listchar)
+ putchar('$');
+
+ /*
+ * Optimization of cursor motion may prevent screen rollup if the
+ * line has blanks/tabs at the end unless we force the cursor to appear
+ * on the last line segment.
+ */
+ if (vp->vliny + d - 1 > WBOT)
+ vcsync();
+
+ /*
+ * Switch into hardcopy open mode if we are in one line (adm3)
+ * open mode and this line is now too long. If in hardcopy
+ * open mode, then call sethard to move onto the next line
+ * with appropriate positioning.
+ */
+ if (state == ONEOPEN) {
+ WCOLS = OCOLUMNS;
+ if (vdepth() > 1) {
+ WCOLS = TUBECOLS;
+ sethard();
+ } else
+ WCOLS = TUBECOLS;
+ } else if (state == HARDOPEN)
+ sethard();
+
+ /*
+ * Unless we filled (completely) the last line we typed on,
+ * we have to clear to the end of the line
+ * in case stuff is left from before.
+ */
+ if (vp->vliny + d > destline) {
+ if (IN && destcol == WCOLS)
+ vigoto(vp->vliny + d - 1, 0);
+ vclreol();
+ }
+ return (d);
+}
+
+/*
+ * Real work for winning growing of window at top
+ * when inserting in the middle of a partially full
+ * screen on an intelligent terminal. We have as argument
+ * the logical line number to be inserted after, and the offset
+ * from that line where the insert will go.
+ * We look at the picture of depths and positions, and if we can
+ * delete some (blank) lines from the top of the screen so that
+ * later inserts will not push stuff off the bottom.
+ */
+int
+vglitchup(int l, int o)
+{
+ register struct vlinfo *vp = &vlinfo[l];
+ register int need;
+ register int p = vp->vliny;
+ short oldhold = 0, oldheldech = 0;
+ bool glitched = 0;
+
+ if (l < vcnt - 1) {
+ need = p + vp->vdepth - (vp+1)->vliny;
+ if (need > 0) {
+ if (state == VISUAL && WTOP - ZERO >= need && AL && DL) {
+ glitched++;
+ WTOP -= need;
+ WLINES = WBOT - WTOP + 1;
+ p -= need;
+ if (p + o == WTOP) {
+ vp->vliny = WTOP;
+ return (WTOP + o);
+ }
+ vdellin(WTOP, need, -1);
+ oldheldech = heldech;
+ oldhold = hold;
+ hold |= HOLDECH;
+ }
+ vinslin((vp+1)->vliny, need, l);
+ if (glitched) {
+ hold = oldhold;
+ heldech = oldheldech;
+ }
+ }
+ } else
+ vp[1].vliny = vp[0].vliny + vp->vdepth;
+ return (p + o);
+}
+
+/*
+ * Insert cnt blank lines before line p,
+ * logically and (if supported) physically.
+ */
+void
+vinslin(register int p, register int cnt, int l)
+{
+ register int i;
+ bool could = 1;
+
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l);
+#endif
+ if (p + cnt > WBOT && CD) {
+ /*
+ * Really quick -- clear to end of screen.
+ */
+ cnt = WECHO + 1 - p;
+ vgoto(p, 0), vputp(CD, cnt);
+ vclrech(1);
+ vadjAL(p, cnt);
+ } else if (SR && p == WTOP && costSR < costAL) {
+ /*
+ * Use reverse scroll mode of the terminal, at
+ * the top of the window. Reverse linefeed works
+ * too, since we only use it from line WTOP.
+ */
+ for (i = cnt; i > 0; i--) {
+ vgoto(p, 0), vputp(SR, 0);
+ if (i > 1 && (hold & HOLDAT) == 0)
+ putchar('@');
+ /*
+ * If we are at the top of the screen, and the
+ * terminal retains display above, then we
+ * should try to clear to end of line.
+ * Have to use CE since we don't remember what is
+ * actually on the line.
+ */
+ if (CE && (DA || p != 0))
+ vputp(CE, 1);
+ }
+ vadjAL(p, cnt);
+ } else if (AL) {
+ /*
+ * Use insert line.
+ */
+ vgoto(p, 0);
+ if (AL_PARM && (cnt>1 || *AL==0)) {
+ /* insert cnt lines. Should do @'s too. */
+ vputp(tgoto(AL_PARM, p, cnt), WECHO+1-p);
+ }
+ else if (xCS && *AL==0) {
+ /* vt100 change scrolling region to fake AL */
+ vputp(SC, 1);
+ vputp(tgoto(xCS, TLINES-1,p), 1);
+ vputp(RC, 1); /* xCS homes stupid cursor */
+ for (i=cnt; i>0; i--)
+ vputp(SR, 1); /* should do @'s */
+ vputp(tgoto(xCS, TLINES-1,0), 1);
+ vputp(RC, 1); /* Once again put it back */
+ }
+ else {
+ vputp(AL, WECHO + 1 - p);
+ for (i = cnt - 1; i > 0; i--) {
+ vgoto(outline+1, 0);
+ vputp(AL, WECHO + 1 - outline);
+ if ((hold & HOLDAT) == 0)
+ putchar('@');
+ }
+ }
+ vadjAL(p, cnt);
+ } else
+ could = 0;
+ vopenup(cnt, could, l);
+}
+
+/*
+ * Logically open up after line l, cnt of them.
+ * We need to know if it was done ``physically'' since in this
+ * case we accept what the hardware gives us. If we have to do
+ * it ourselves (brute force) we will squish out @ lines in the process
+ * if this will save us work.
+ */
+void
+vopenup(int cnt, int could, int l)
+{
+ register struct vlinfo *vc = &vlinfo[l + 1];
+ register struct vlinfo *ve = &vlinfo[vcnt];
+
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l);
+#endif
+ if (could)
+ /*
+ * This will push @ lines down the screen,
+ * just as the hardware did. Since the default
+ * for intelligent terminals is to never have @
+ * lines on the screen, this should never happen,
+ * and the code makes no special effort to be nice in this
+ * case, e.g. squishing out the @ lines by delete lines
+ * before doing append lines.
+ */
+ for (; vc <= ve; vc++)
+ vc->vliny += cnt;
+ else {
+ /*
+ * Will have to clean up brute force eventually,
+ * so push the line data around as little as possible.
+ */
+ vc->vliny += cnt, vc->vflags |= VDIRT;
+ while (vc < ve) {
+ register int i = vc->vliny + vc->vdepth;
+
+ vc++;
+ if (i <= vc->vliny)
+ break;
+ vc->vliny = i, vc->vflags |= VDIRT;
+ }
+ }
+ vscrap();
+}
+
+/*
+ * Adjust data structure internally to account for insertion of
+ * blank lines on the screen.
+ */
+void
+vadjAL(int p, int cnt)
+{
+ cell *tlines[TUBELINES];
+ register int from, to;
+
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vadjal(%d, %d)\n", p, cnt);
+#endif
+ copy(tlines, vtube, sizeof vtube); /*SASSIGN*/
+ for (from = p, to = p + cnt; to <= WECHO; from++, to++)
+ vtube[to] = tlines[from];
+ for (to = p; from <= WECHO; from++, to++) {
+ vtube[to] = tlines[from];
+ vclrcell(vtube[to], WCOLS);
+ }
+ /*
+ * Have to clear the echo area since its contents aren't
+ * necessarily consistent with the rest of the display.
+ */
+ vclrech(0);
+}
+
+/*
+ * Roll the screen up logically and physically
+ * so that line dl is the bottom line on the screen.
+ */
+void
+vrollup(int dl)
+{
+ register int cnt;
+ register int dc = destcol;
+
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vrollup(%d)\n", dl);
+#endif
+ cnt = dl - (splitw ? WECHO : WBOT);
+ if (splitw && (state == VISUAL || state == CRTOPEN))
+ holdupd = 1;
+ vmoveitup(cnt, 1);
+ vscroll(cnt);
+ destline = dl - cnt, destcol = dc;
+}
+
+void
+vup1(void)
+{
+
+ vrollup(WBOT + 1);
+}
+
+/*
+ * Scroll the screen up cnt lines physically.
+ * If doclr is true, do a clear eol if the terminal
+ * has standout (to prevent it from scrolling up)
+ */
+void
+vmoveitup(register int cnt, int doclr)
+{
+
+ if (cnt == 0)
+ return;
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt);
+#endif
+ if (doclr && (SO || SE))
+ vclrech(0);
+ if (SF) {
+ destline = WECHO;
+ destcol = (NONL ? 0 : outcol % WCOLS);
+ fgoto();
+ while (cnt > 0)
+ vputp(SF, 0), cnt--;
+ return;
+ }
+ destline = WECHO + cnt;
+ destcol = (NONL ? 0 : outcol % WCOLS);
+ fgoto();
+ if (state == ONEOPEN || state == HARDOPEN) {
+ outline = destline = 0;
+ vclrcell(vtube[0], WCOLS);
+ }
+}
+
+/*
+ * Scroll the screen up cnt lines logically.
+ */
+void
+vscroll(register int cnt)
+{
+ register int from, to;
+ cell *tlines[TUBELINES];
+
+#ifdef ADEBUG
+ if (trace)
+ fprintf(trace, "vscroll(%d)\n", cnt);
+#endif
+ if (cnt < 0 || cnt > TUBELINES)
+ error(catgets(catd, 1, 219, "Internal error: vscroll"));
+ if (cnt == 0)
+ return;
+ copy(tlines, vtube, sizeof vtube);
+ for (to = ZERO, from = ZERO + cnt; to <= WECHO - cnt; to++, from++)
+ vtube[to] = tlines[from];
+ for (from = ZERO; to <= WECHO; to++, from++) {
+ vtube[to] = tlines[from];
+ vclrcell(vtube[to], WCOLS);
+ }
+ for (from = 0; from <= vcnt; from++)
+ LINE(from) -= cnt;
+}
+
+/*
+ * Discard logical lines due to physical wandering off the screen.
+ */
+void
+vscrap(void)
+{
+ register int i, j;
+
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vscrap\n"), tvliny();
+#endif
+ if (splitw)
+ return;
+ if (vcnt && WBOT != WECHO && LINE(0) < WTOP && LINE(0) >= ZERO) {
+ WTOP = LINE(0);
+ WLINES = WBOT - WTOP + 1;
+ }
+ for (j = 0; j < vcnt; j++)
+ if (LINE(j) >= WTOP) {
+ if (j == 0)
+ break;
+ /*
+ * Discard the first j physical lines off the top.
+ */
+ vcnt -= j, vcline -= j;
+ for (i = 0; i <= vcnt; i++)
+ vlcopy(vlinfo[i], vlinfo[i + j]);
+ break;
+ }
+ /*
+ * Discard lines off the bottom.
+ */
+ if (vcnt) {
+ for (j = 0; j <= vcnt; j++)
+ if (LINE(j) > WBOT || LINE(j) + DEPTH(j) - 1 > WBOT) {
+ vcnt = j;
+ break;
+ }
+ LASTLINE = LINE(vcnt-1) + DEPTH(vcnt-1);
+ }
+#ifdef ADEBUG
+ if (trace)
+ tvliny();
+#endif
+ /*
+ * May have no lines!
+ */
+}
+
+/*
+ * Repaint the screen, with cursor at curs, aftern an arbitrary change.
+ * Handle notification on large changes.
+ */
+void
+vrepaint(char *curs)
+{
+
+ wdot = NOLINE;
+ /*
+ * In open want to notify first.
+ */
+ noteit(0);
+ vscrap();
+
+ /*
+ * Deal with a totally useless display.
+ */
+ if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) {
+ register line *odol = dol;
+
+ vcnt = 0;
+ if (holdupd)
+ if (state == VISUAL)
+ ignore(peekkey());
+ else
+ vup1();
+ holdupd = 0;
+ if (odol == zero)
+ fixzero();
+ vcontext(dot, '.');
+ noteit(1);
+ if (noteit(1) == 0 && odol == zero) {
+ CATCH
+ error(catgets(catd, 1, 220,
+ "No lines in buffer"));
+ ENDCATCH
+ linebuf[0] = 0;
+ splitw = 0;
+ }
+ vnline(curs);
+ return;
+ }
+
+ /*
+ * Have some useful displayed text; refresh it.
+ */
+ getDOT();
+
+ /*
+ * This is for boundary conditions in open mode.
+ */
+ if (FLAGS(0) & VDIRT)
+ vsync(WTOP);
+
+ /*
+ * If the current line is after the last displayed line
+ * or the bottom of the screen, then special effort is needed
+ * to get it on the screen. We first try a redraw at the
+ * last line on the screen, hoping it will fill in where @
+ * lines are now. If this doesn't work, then roll it onto
+ * the screen.
+ */
+ if (vcline >= vcnt || LINE(vcline) > WBOT) {
+ short oldhold = hold;
+ hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold;
+ if (vcline >= vcnt) {
+ register int i = vcline - vcnt + 1;
+
+ dot -= i;
+ vcline -= i;
+ vroll(i);
+ } else
+ vsyncCL();
+ } else
+ vsync(vcline > 0 ? LINE(vcline - 1) : WTOP);
+
+ /*
+ * Notification on large change for visual
+ * has to be done last or we may lose
+ * the echo area with redisplay.
+ */
+ noteit(1);
+
+ /*
+ * Finally. Move the cursor onto the current line.
+ */
+ vnline(curs);
+}
+
+/*
+ * Fully cleanup the screen, leaving no @ lines except at end when
+ * line after last won't completely fit. The routine vsync is
+ * more conservative and much less work on dumb terminals.
+ */
+void
+vredraw(register int p)
+{
+ register int l;
+ register line *tp;
+ char temp[LBSIZE];
+ bool anydl = 0;
+ short oldhold = hold;
+
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny();
+#endif
+ if (holdupd) {
+ holdupd = 3;
+ return;
+ }
+ if (state == HARDOPEN || splitw)
+ return;
+ if (p < 0 /* || p > WECHO */)
+ error(catgets(catd, 1, 221, "Internal error: vredraw"));
+
+ /*
+ * Trim the ragged edges (lines which are off the screen but
+ * not yet logically discarded), save the current line, and
+ * search for first logical line affected by the redraw.
+ */
+ vscrap();
+ CP(temp, linebuf);
+ l = 0;
+ tp = dot - vcline;
+ if (vcnt == 0)
+ LINE(0) = WTOP;
+ while (l < vcnt && LINE(l) < p)
+ l++, tp++;
+
+ /*
+ * We hold off echo area clearing during the redraw in deference
+ * to a final clear of the echo area at the end if appropriate.
+ */
+ heldech = 0;
+ hold |= HOLDECH;
+ for (; l < vcnt && Peekkey != ATTN; l++) {
+ if (l == vcline)
+ strcLIN(temp);
+ else
+ getline(*tp);
+
+ /*
+ * Delete junk between displayed lines.
+ */
+ if (LINE(l) != LINE(l + 1) && LINE(l) != p) {
+ if (anydl == 0 && DB && CD) {
+ hold = oldhold;
+ vclrech(0);
+ anydl = 1;
+ hold |= HOLDECH;
+ heldech = 0;
+ }
+ vdellin(p, LINE(l) - p, l);
+ }
+
+ /*
+ * If line image is not know to be up to date, then
+ * redisplay it; else just skip onward.
+ */
+ LINE(l) = p;
+ if (FLAGS(l) & VDIRT) {
+ DEPTH(l) = vdepth();
+ if (l != vcline && p + DEPTH(l) - 1 > WBOT) {
+ vscrap();
+ break;
+ }
+ FLAGS(l) &= ~VDIRT;
+ vreopen(p, lineno(tp), l);
+ p = LINE(l) + DEPTH(l);
+ } else
+ p += DEPTH(l);
+ tp++;
+ }
+
+ /*
+ * That takes care of lines which were already partially displayed.
+ * Now try to fill the rest of the screen with text.
+ */
+ if (state == VISUAL && p <= WBOT) {
+ int ovcline = vcline;
+
+ vcline = l;
+ for (; tp <= dol && Peekkey != ATTN; tp++) {
+ getline(*tp);
+ if (p + vdepth() - 1 > WBOT)
+ break;
+ vopen(tp, p);
+ p += DEPTH(vcline);
+ vcline++;
+ }
+ vcline = ovcline;
+ }
+
+ /*
+ * Thats all the text we can get on.
+ * Now rest of lines (if any) get either a ~ if they
+ * are past end of file, or an @ if the next line won't fit.
+ */
+ for (; p <= WBOT && Peekkey != ATTN; p++)
+ vclrlin(p, tp);
+ strcLIN(temp);
+ hold = oldhold;
+ if (heldech)
+ vclrech(0);
+#ifdef ADEBUG
+ if (trace)
+ tvliny();
+#endif
+}
+
+/*
+ * Do the real work in deleting cnt lines starting at line p from
+ * the display. First affected line is line l.
+ */
+void
+vdellin(int p, int cnt, int l)
+{
+ register int i;
+
+ if (cnt == 0)
+ return;
+ if (DL == NOSTR || cnt < 0) {
+ /*
+ * Can't do it; just remember that line l is munged.
+ */
+ FLAGS(l) |= VDIRT;
+ return;
+ }
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l);
+#endif
+ /*
+ * Send the deletes to the screen and then adjust logical
+ * and physical internal data structures.
+ */
+ vgoto(p, 0);
+ if (DL_PARM && (cnt>1 || *DL==0)) {
+ vputp(tgoto(DL_PARM, p, cnt), WECHO-p);
+ }
+ else if (xCS && *DL==0) {
+ /* vt100: fake DL by changing scrolling region */
+ vputp(SC, 1); /* Save since xCS homes stupid cursor */
+ vputp(tgoto(xCS, TLINES-1, p), 1);
+ vputp(tgoto(CM, 0, TLINES-1), 1);/* Go to lower left corner */
+ for (i=0; i<cnt; i++) /* .. and scroll cnt times */
+ putch('\n'); /* should check NL too */
+ vputp(tgoto(xCS, TLINES-1, 0), 1);/* restore scrolling region */
+ vputp(RC, 1); /* put cursor back */
+ }
+ else {
+ for (i = 0; i < cnt; i++)
+ vputp(DL, WECHO - p);
+ }
+ vadjDL(p, cnt);
+ vcloseup(l, cnt);
+}
+/*
+ * Adjust internal physical screen image to account for deleted lines.
+ */
+void
+vadjDL(int p, int cnt)
+{
+ cell *tlines[TUBELINES];
+ register int from, to;
+
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vadjDL(%d, %d)\n", p, cnt);
+#endif
+ /*
+ * Would like to use structured assignment but early
+ * v7 compiler (released with phototypesetter for v6)
+ * can't hack it.
+ */
+ copy(tlines, vtube, sizeof vtube); /*SASSIGN*/
+ for (from = p + cnt, to = p; from <= WECHO; from++, to++)
+ vtube[to] = tlines[from];
+ for (from = p; to <= WECHO; from++, to++) {
+ vtube[to] = tlines[from];
+ vclrcell(vtube[to], WCOLS);
+ }
+}
+/*
+ * Sync the screen, like redraw but more lazy and willing to leave
+ * @ lines on the screen. VsyncCL syncs starting at the current line.
+ * In any case, if the redraw option is set then all syncs map to redraws
+ * as if vsync didn't exist.
+ */
+void
+vsyncCL(void)
+{
+
+ vsync(LINE(vcline));
+}
+
+void
+vsync(register int p)
+{
+
+ if (value(REDRAW))
+ vredraw(p);
+ else
+ vsync1(p);
+}
+
+/*
+ * The guts of a sync. Similar to redraw but
+ * just less ambitous.
+ */
+void
+vsync1(register int p)
+{
+ register int l;
+ char temp[LBSIZE];
+ register struct vlinfo *vp = &vlinfo[0];
+ short oldhold = hold;
+
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny();
+#endif
+ if (holdupd) {
+ if (holdupd < 3)
+ holdupd = 2;
+ return;
+ }
+ if (state == HARDOPEN || splitw)
+ return;
+ vscrap();
+ CP(temp, linebuf);
+ if (vcnt == 0)
+ LINE(0) = WTOP;
+ l = 0;
+ while (l < vcnt && vp->vliny < p)
+ l++, vp++;
+ heldech = 0;
+ hold |= HOLDECH;
+ while (p <= WBOT && Peekkey != ATTN) {
+ /*
+ * Want to put a line here if not in visual and first line
+ * or if there are lies left and this line starts before
+ * the current line, or if this line is piled under the
+ * next line (vreplace does this and we undo it).
+ */
+ if (l == 0 && state != VISUAL ||
+ (l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) {
+ if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) {
+ if (l == vcline)
+ strcLIN(temp);
+ else
+ getline(dot[l - vcline]);
+ /*
+ * Be careful that a long line doesn't cause the
+ * screen to shoot up.
+ */
+ if (l != vcline && (vp->vflags & VDIRT)) {
+ vp->vdepth = vdepth();
+ vp->vflags &= ~VDIRT;
+ if (p + vp->vdepth - 1 > WBOT)
+ break;
+ }
+ vreopen(p, lineDOT() + (l - vcline), l);
+ }
+ p = vp->vliny + vp->vdepth;
+ vp++;
+ l++;
+ } else
+ /*
+ * A physical line between logical lines,
+ * so we settle for an @ at the beginning.
+ */
+ vclrlin(p, dot + (l - vcline)), p++;
+ }
+ strcLIN(temp);
+ hold = oldhold;
+ if (heldech)
+ vclrech(0);
+}
+
+/*
+ * Subtract (logically) cnt physical lines from the
+ * displayed position of lines starting with line l.
+ */
+void
+vcloseup(int l, register int cnt)
+{
+ register int i;
+
+#ifdef ADEBUG
+ if (trace)
+ tfixnl(), fprintf(trace, "vcloseup(%d, %d)\n", l, cnt);
+#endif
+ for (i = l + 1; i <= vcnt; i++)
+ LINE(i) -= cnt;
+}
+
+/*
+ * Workhorse for rearranging line descriptors on changes.
+ * The idea here is that, starting with line l, cnt lines
+ * have been replaced with newcnt lines. All of these may
+ * be ridiculous, i.e. l may be -1000, cnt 50 and newcnt 0,
+ * since we may be called from an undo after the screen has
+ * moved a lot. Thus we have to be careful.
+ *
+ * Many boundary conditions here.
+ */
+void
+vreplace(int l, int cnt, int newcnt)
+{
+ register int from, to, i;
+ bool savenote = 0;
+
+#ifdef ADEBUG
+ if (trace) {
+ tfixnl(), fprintf(trace, "vreplace(%d, %d, %d)\n", l, cnt, newcnt);
+ tvliny();
+ }
+#endif
+ if (l >= vcnt)
+ return;
+ if (l < 0) {
+ if (l + cnt < 0) {
+ /*
+ * Nothing on the screen is relevant.
+ * Settle for redrawing from scratch (later).
+ */
+ vcnt = 0;
+ return;
+ }
+ /*
+ * Normalize l to top of screen; the add is
+ * really a subtract from cnt since l is negative.
+ */
+ cnt += l;
+ l = 0;
+
+ /*
+ * Unseen lines were affect so notify (later).
+ */
+ savenote++;
+ }
+
+ /*
+ * These shouldn't happen
+ * but would cause great havoc.
+ */
+ if (cnt < 0)
+ cnt = 0;
+ if (newcnt < 0)
+ newcnt = 0;
+
+ /*
+ * Surely worthy of note if more than report
+ * lines were changed.
+ */
+ if (cnt > value(REPORT) || newcnt > value(REPORT))
+ savenote++;
+
+ /*
+ * Same number of lines affeted as on screen, and we
+ * can insert and delete lines. Thus we just type
+ * over them, since otherwise we will push them
+ * slowly off the screen, a clear lose.
+ */
+ if (cnt == newcnt || vcnt - l == newcnt && AL && DL) {
+ if (cnt > 1 && l + cnt > vcnt)
+ savenote++;
+ vdirty(l, newcnt);
+ } else {
+ /*
+ * Lines are going away, squish them out.
+ */
+ if (cnt > 0) {
+ /*
+ * If non-displayed lines went away,
+ * always notify.
+ */
+ if (cnt > 1 && l + cnt > vcnt)
+ savenote++;
+ if (l + cnt >= vcnt)
+ cnt = vcnt - l;
+ else
+ for (from = l + cnt, to = l; from <= vcnt; to++, from++)
+ vlcopy(vlinfo[to], vlinfo[from]);
+ vcnt -= cnt;
+ }
+ /*
+ * Open up space for new lines appearing.
+ * All new lines are piled in the same place,
+ * and will be unpiled by vredraw/vsync, which
+ * inserts lines in front as it unpiles.
+ */
+ if (newcnt > 0) {
+ /*
+ * Newlines are appearing which may not show,
+ * so notify (this is only approximately correct
+ * when long lines are present).
+ */
+ if (newcnt > 1 && l + newcnt > vcnt + 1)
+ savenote++;
+
+ /*
+ * If there will be more lines than fit, then
+ * just throw way the rest of the stuff on the screen.
+ */
+ if (l + newcnt > WBOT && AL && DL) {
+ vcnt = l;
+ goto skip;
+ }
+ from = vcnt, to = vcnt + newcnt;
+ i = TUBELINES - to;
+ if (i < 0)
+ from += i, to += i;
+ vcnt = to;
+ for (; from >= l; from--, to--)
+ vlcopy(vlinfo[to], vlinfo[from]);
+ for (from = to + 1, to = l; to < l + newcnt && to <= WBOT + 1; to++) {
+ LINE(to) = LINE(from);
+ DEPTH(to) = 0;
+ FLAGS(to) = VDIRT;
+ }
+ }
+ }
+skip:
+ if (Pline == numbline && cnt != newcnt)
+ /*
+ * When lines positions are shifted, the numbers
+ * will be wrong.
+ */
+ vdirty(l, WECHO);
+ if (!savenote)
+ notecnt = 0;
+#ifdef ADEBUG
+ if (trace)
+ tvliny();
+#endif
+}
+
+/*
+ * Start harcopy open.
+ * Print an image of the line to the left of the cursor
+ * under the full print of the line and position the cursor.
+ * If we are in a scroll ^D within hardcopy open then all this
+ * is suppressed.
+ */
+void
+sethard(void)
+{
+
+ if (state == VISUAL)
+ return;
+ rubble = 0;
+ state = HARDOPEN;
+ if (hold & HOLDROL)
+ return;
+ vup1();
+ LINE(0) = WBOT;
+ if (Pline == numbline)
+ vgoto(WBOT, 0), printf("%6d ", lineDOT());
+}
+
+/*
+ * Mark the lines starting at base for i lines
+ * as dirty so that they will be checked for correct
+ * display at next sync/redraw.
+ */
+void
+vdirty(register int base, register int i)
+{
+ register int l;
+
+ for (l = base; l < vcnt; l++) {
+ if (--i < 0)
+ return;
+ FLAGS(l) |= VDIRT;
+ }
+}