]> pd.if.org Git - pd_readline/blobdiff - mg/display.c
Getting close to a basic working readline now.
[pd_readline] / mg / display.c
diff --git a/mg/display.c b/mg/display.c
deleted file mode 100644 (file)
index ba7c580..0000000
+++ /dev/null
@@ -1,1064 +0,0 @@
-/*     $OpenBSD: display.c,v 1.37 2009/06/04 02:23:37 kjell Exp $      */
-
-/* This file is in the public domain. */
-
-/*
- * The functions in this file handle redisplay. The
- * redisplay system knows almost nothing about the editing
- * process; the editing functions do, however, set some
- * hints to eliminate a lot of the grinding. There is more
- * that can be done; the "vtputc" interface is a real
- * pig.
- */
-#include "def.h"
-#include "kbd.h"
-
-#include <ctype.h>
-
-/*
- * You can change these back to the types
- * implied by the name if you get tight for space. If you
- * make both of them "int" you get better code on the VAX.
- * They do nothing if this is not Gosling redisplay, except
- * for change the size of a structure that isn't used.
- * A bit of a cheat.
- */
-#define        XCHAR   int
-#define        XSHORT  int
-
-#ifdef STANDOUT_GLITCH
-#include <term.h>
-#endif
-
-/*
- * A video structure always holds
- * an array of characters whose length is equal to
- * the longest line possible. v_text is allocated
- * dynamically to fit the screen width.
- */
-struct video {
-       short   v_hash;         /* Hash code, for compares.      */
-       short   v_flag;         /* Flag word.                    */
-       short   v_color;        /* Color of the line.            */
-       XSHORT  v_cost;         /* Cost of display.              */
-       char    *v_text;        /* The actual characters.        */
-};
-
-#define VFCHG  0x0001                  /* Changed.                      */
-#define VFHBAD 0x0002                  /* Hash and cost are bad.        */
-#define VFEXT  0x0004                  /* extended line (beond ncol)    */
-
-/*
- * SCORE structures hold the optimal
- * trace trajectory, and the cost of redisplay, when
- * the dynamic programming redisplay code is used.
- * If no fancy redisplay, this isn't used. The trace index
- * fields can be "char", and the cost a "short", but
- * this makes the code worse on the VAX.
- */
-struct score {
-       XCHAR   s_itrace;       /* "i" index for track back.     */
-       XCHAR   s_jtrace;       /* "j" index for trace back.     */
-       XSHORT  s_cost;         /* Display cost.                 */
-};
-
-void   vtmove(int, int);
-void   vtputc(int);
-void   vtpute(int);
-int    vtputs(const char *);
-void   vteeol(void);
-void   updext(int, int);
-void   modeline(struct mgwin *);
-void   setscores(int, int);
-void   traceback(int, int, int, int);
-void   ucopy(struct video *, struct video *);
-void   uline(int, struct video *, struct video *);
-void   hash(struct video *);
-
-
-int    sgarbf = TRUE;          /* TRUE if screen is garbage.    */
-int    vtrow = HUGE;           /* Virtual cursor row.           */
-int    vtcol = HUGE;           /* Virtual cursor column.        */
-int    tthue = CNONE;          /* Current color.                */
-int    ttrow = HUGE;           /* Physical cursor row.          */
-int    ttcol = HUGE;           /* Physical cursor column.       */
-int    tttop = HUGE;           /* Top of scroll region.         */
-int    ttbot = HUGE;           /* Bottom of scroll region.      */
-int    lbound = 0;             /* leftmost bound of the current */
-                               /* line being displayed          */
-
-struct video   **vscreen;              /* Edge vector, virtual.         */
-struct video   **pscreen;              /* Edge vector, physical.        */
-struct video    *video;                /* Actual screen data.           */
-struct video     blanks;               /* Blank line image.             */
-
-/*
- * This matrix is written as an array because
- * we do funny things in the "setscores" routine, which
- * is very compute intensive, to make the subscripts go away.
- * It would be "SCORE  score[NROW][NROW]" in old speak.
- * Look at "setscores" to understand what is up.
- */
-struct score *score;                   /* [NROW * NROW] */
-
-#ifndef LINENOMODE
-#define LINENOMODE TRUE
-#endif /* !LINENOMODE */
-static int      linenos = LINENOMODE;
-
-/* Is macro recording enabled? */
-extern int macrodef;
-/* Is working directory global? */
-extern int globalwd;
-
-/*
- * Since we don't have variables (we probably should) these are command
- * processors for changing the values of mode flags.
- */
-/* ARGSUSED */
-int
-linenotoggle(int f, int n)
-{
-       if (f & FFARG)
-               linenos = n > 0;
-       else
-               linenos = !linenos;
-
-       sgarbf = TRUE;
-
-       return (TRUE);
-}
-
-/*
- * Reinit the display data structures, this is called when the terminal
- * size changes.
- */
-int
-vtresize(int force, int newrow, int newcol)
-{
-       int      i;
-       int      rowchanged, colchanged;
-       static   int first_run = 1;
-       struct video    *vp;
-
-       if (newrow < 1 || newcol < 1)
-               return (FALSE);
-
-       rowchanged = (newrow != nrow);
-       colchanged = (newcol != ncol);
-
-#define TRYREALLOC(a, n) do {                                  \
-               void *tmp;                                      \
-               if ((tmp = realloc((a), (n))) == NULL) {        \
-                       panic("out of memory in display code"); \
-               }                                               \
-               (a) = tmp;                                      \
-       } while (0)
-
-       /* No update needed */
-       if (!first_run && !force && !rowchanged && !colchanged)
-               return (TRUE);
-
-       if (first_run)
-               memset(&blanks, 0, sizeof(blanks));
-
-       if (rowchanged || first_run) {
-               int vidstart;
-
-               /*
-                * This is not pretty.
-                */
-               if (nrow == 0)
-                       vidstart = 0;
-               else
-                       vidstart = 2 * (nrow - 1);
-
-               /*
-                * We're shrinking, free some internal data.
-                */
-               if (newrow < nrow) {
-                       for (i = 2 * (newrow - 1); i < 2 * (nrow - 1); i++) {
-                               free(video[i].v_text);
-                               video[i].v_text = NULL;
-                       }
-               }
-
-               TRYREALLOC(score, newrow * newrow * sizeof(struct score));
-               TRYREALLOC(vscreen, (newrow - 1) * sizeof(struct video *));
-               TRYREALLOC(pscreen, (newrow - 1) * sizeof(struct video *));
-               TRYREALLOC(video, (2 * (newrow - 1)) * sizeof(struct video));
-
-               /*
-                * Zero-out the entries we just allocated.
-                */
-               for (i = vidstart; i < 2 * (newrow - 1); i++)
-                       memset(&video[i], 0, sizeof(struct video));
-
-               /*
-                * Reinitialize vscreen and pscreen arrays completely.
-                */
-               vp = &video[0];
-               for (i = 0; i < newrow - 1; ++i) {
-                       vscreen[i] = vp;
-                       ++vp;
-                       pscreen[i] = vp;
-                       ++vp;
-               }
-       }
-       if (rowchanged || colchanged || first_run) {
-               for (i = 0; i < 2 * (newrow - 1); i++)
-                       TRYREALLOC(video[i].v_text, newcol * sizeof(char));
-               TRYREALLOC(blanks.v_text, newcol * sizeof(char));
-       }
-
-       nrow = newrow;
-       ncol = newcol;
-
-       if (ttrow > nrow)
-               ttrow = nrow;
-       if (ttcol > ncol)
-               ttcol = ncol;
-
-       first_run = 0;
-       return (TRUE);
-}
-
-#undef TRYREALLOC
-
-/*
- * Initialize the data structures used
- * by the display code. The edge vectors used
- * to access the screens are set up. The operating
- * system's terminal I/O channel is set up. Fill the
- * "blanks" array with ASCII blanks. The rest is done
- * at compile time. The original window is marked
- * as needing full update, and the physical screen
- * is marked as garbage, so all the right stuff happens
- * on the first call to redisplay.
- */
-void
-vtinit(void)
-{
-       int     i;
-
-       ttopen();
-       ttinit();
-
-       /*
-        * ttinit called ttresize(), which called vtresize(), so our data
-        * structures are setup correctly.
-        */
-
-       blanks.v_color = CTEXT;
-       for (i = 0; i < ncol; ++i)
-               blanks.v_text[i] = ' ';
-}
-
-/*
- * Tidy up the virtual display system
- * in anticipation of a return back to the host
- * operating system. Right now all we do is position
- * the cursor to the last line, erase the line, and
- * close the terminal channel.
- */
-void
-vttidy(void)
-{
-       ttcolor(CTEXT);
-       ttnowindow();           /* No scroll window.     */
-       ttmove(nrow - 1, 0);    /* Echo line.            */
-       tteeol();
-       tttidy();
-       ttflush();
-       ttclose();
-}
-
-/*
- * Move the virtual cursor to an origin
- * 0 spot on the virtual display screen. I could
- * store the column as a character pointer to the spot
- * on the line, which would make "vtputc" a little bit
- * more efficient. No checking for errors.
- */
-void
-vtmove(int row, int col)
-{
-       vtrow = row;
-       vtcol = col;
-}
-
-/*
- * Write a character to the virtual display,
- * dealing with long lines and the display of unprintable
- * things like control characters. Also expand tabs every 8
- * columns. This code only puts printing characters into
- * the virtual display image. Special care must be taken when
- * expanding tabs. On a screen whose width is not a multiple
- * of 8, it is possible for the virtual cursor to hit the
- * right margin before the next tab stop is reached. This
- * makes the tab code loop if you are not careful.
- * Three guesses how we found this.
- */
-void
-vtputc(int c)
-{
-       struct video    *vp;
-
-       c &= 0xff;
-
-       vp = vscreen[vtrow];
-       if (vtcol >= ncol)
-               vp->v_text[ncol - 1] = '$';
-       else if (c == '\t'
-#ifdef NOTAB
-           && !(curbp->b_flag & BFNOTAB)
-#endif
-           ) {
-               do {
-                       vtputc(' ');
-               } while (vtcol < ncol && (vtcol & 0x07) != 0);
-       } else if (ISCTRL(c)) {
-               vtputc('^');
-               vtputc(CCHR(c));
-       } else if (isprint(c))
-               vp->v_text[vtcol++] = c;
-       else {
-               char bf[5];
-
-               snprintf(bf, sizeof(bf), "\\%o", c);
-               vtputs(bf);
-       }
-}
-
-/*
- * Put a character to the virtual screen in an extended line.  If we are not
- * yet on left edge, don't print it yet.  Check for overflow on the right
- * margin.
- */
-void
-vtpute(int c)
-{
-       struct video *vp;
-
-       c &= 0xff;
-
-       vp = vscreen[vtrow];
-       if (vtcol >= ncol)
-               vp->v_text[ncol - 1] = '$';
-       else if (c == '\t'
-#ifdef NOTAB
-           && !(curbp->b_flag & BFNOTAB)
-#endif
-           ) {
-               do {
-                       vtpute(' ');
-               } while (((vtcol + lbound) & 0x07) != 0 && vtcol < ncol);
-       } else if (ISCTRL(c) != FALSE) {
-               vtpute('^');
-               vtpute(CCHR(c));
-       } else {
-               if (vtcol >= 0)
-                       vp->v_text[vtcol] = c;
-               ++vtcol;
-       }
-}
-
-/*
- * Erase from the end of the software cursor to the end of the line on which
- * the software cursor is located. The display routines will decide if a
- * hardware erase to end of line command should be used to display this.
- */
-void
-vteeol(void)
-{
-       struct video *vp;
-
-       vp = vscreen[vtrow];
-       while (vtcol < ncol)
-               vp->v_text[vtcol++] = ' ';
-}
-
-/*
- * Make sure that the display is
- * right. This is a three part process. First,
- * scan through all of the windows looking for dirty
- * ones. Check the framing, and refresh the screen.
- * Second, make sure that "currow" and "curcol" are
- * correct for the current window. Third, make the
- * virtual and physical screens the same.
- */
-void
-update(void)
-{
-       struct line     *lp;
-       struct mgwin    *wp;
-       struct video    *vp1;
-       struct video    *vp2;
-       int      c, i, j;
-       int      hflag;
-       int      currow, curcol;
-       int      offs, size;
-
-       if (charswaiting())
-               return;
-       if (sgarbf) {           /* must update everything */
-               wp = wheadp;
-               while (wp != NULL) {
-                       wp->w_rflag |= WFMODE | WFFULL;
-                       wp = wp->w_wndp;
-               }
-       }
-       if (linenos) {
-               wp = wheadp;
-               while (wp != NULL) {
-                       wp->w_rflag |= WFMODE;
-                       wp = wp->w_wndp;
-               }
-       }
-       hflag = FALSE;                  /* Not hard. */
-       for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
-               /*
-                * Nothing to be done.
-                */
-               if (wp->w_rflag == 0)
-                       continue;
-
-               if ((wp->w_rflag & WFFRAME) == 0) {
-                       lp = wp->w_linep;
-                       for (i = 0; i < wp->w_ntrows; ++i) {
-                               if (lp == wp->w_dotp)
-                                       goto out;
-                               if (lp == wp->w_bufp->b_headp)
-                                       break;
-                               lp = lforw(lp);
-                       }
-               }
-               /*
-                * Put the middle-line in place.
-                */
-               i = wp->w_frame;
-               if (i > 0) {
-                       --i;
-                       if (i >= wp->w_ntrows)
-                               i = wp->w_ntrows - 1;
-               } else if (i < 0) {
-                       i += wp->w_ntrows;
-                       if (i < 0)
-                               i = 0;
-               } else
-                       i = wp->w_ntrows / 2; /* current center, no change */
-
-               /*
-                * Find the line.
-                */
-               lp = wp->w_dotp;
-               while (i != 0 && lback(lp) != wp->w_bufp->b_headp) {
-                       --i;
-                       lp = lback(lp);
-               }
-               wp->w_linep = lp;
-               wp->w_rflag |= WFFULL;  /* Force full.           */
-       out:
-               lp = wp->w_linep;       /* Try reduced update.   */
-               i = wp->w_toprow;
-               if ((wp->w_rflag & ~WFMODE) == WFEDIT) {
-                       while (lp != wp->w_dotp) {
-                               ++i;
-                               lp = lforw(lp);
-                       }
-                       vscreen[i]->v_color = CTEXT;
-                       vscreen[i]->v_flag |= (VFCHG | VFHBAD);
-                       vtmove(i, 0);
-                       for (j = 0; j < llength(lp); ++j)
-                               vtputc(lgetc(lp, j));
-                       vteeol();
-               } else if ((wp->w_rflag & (WFEDIT | WFFULL)) != 0) {
-                       hflag = TRUE;
-                       while (i < wp->w_toprow + wp->w_ntrows) {
-                               vscreen[i]->v_color = CTEXT;
-                               vscreen[i]->v_flag |= (VFCHG | VFHBAD);
-                               vtmove(i, 0);
-                               if (lp != wp->w_bufp->b_headp) {
-                                       for (j = 0; j < llength(lp); ++j)
-                                               vtputc(lgetc(lp, j));
-                                       lp = lforw(lp);
-                               }
-                               vteeol();
-                               ++i;
-                       }
-               }
-               if ((wp->w_rflag & WFMODE) != 0)
-                       modeline(wp);
-               wp->w_rflag = 0;
-               wp->w_frame = 0;
-       }
-       lp = curwp->w_linep;    /* Cursor location. */
-       currow = curwp->w_toprow;
-       while (lp != curwp->w_dotp) {
-               ++currow;
-               lp = lforw(lp);
-       }
-       curcol = 0;
-       i = 0;
-       while (i < curwp->w_doto) {
-               c = lgetc(lp, i++);
-               if (c == '\t'
-#ifdef NOTAB
-                   && !(curbp->b_flag & BFNOTAB)
-#endif
-                       ) {
-                       curcol |= 0x07;
-                       curcol++;
-               } else if (ISCTRL(c) != FALSE)
-                       curcol += 2;
-               else if (isprint(c))
-                       curcol++;
-               else {
-                       char bf[5];
-
-                       snprintf(bf, sizeof(bf), "\\%o", c);
-                       curcol += strlen(bf);
-               }
-       }
-       if (curcol >= ncol - 1) {       /* extended line. */
-               /* flag we are extended and changed */
-               vscreen[currow]->v_flag |= VFEXT | VFCHG;
-               updext(currow, curcol); /* and output extended line */
-       } else
-               lbound = 0;     /* not extended line */
-
-       /*
-        * Make sure no lines need to be de-extended because the cursor is no
-        * longer on them.
-        */
-       wp = wheadp;
-       while (wp != NULL) {
-               lp = wp->w_linep;
-               i = wp->w_toprow;
-               while (i < wp->w_toprow + wp->w_ntrows) {
-                       if (vscreen[i]->v_flag & VFEXT) {
-                               /* always flag extended lines as changed */
-                               vscreen[i]->v_flag |= VFCHG;
-                               if ((wp != curwp) || (lp != wp->w_dotp) ||
-                                   (curcol < ncol - 1)) {
-                                       vtmove(i, 0);
-                                       for (j = 0; j < llength(lp); ++j)
-                                               vtputc(lgetc(lp, j));
-                                       vteeol();
-                                       /* this line no longer is extended */
-                                       vscreen[i]->v_flag &= ~VFEXT;
-                               }
-                       }
-                       lp = lforw(lp);
-                       ++i;
-               }
-               /* if garbaged then fix up mode lines */
-               if (sgarbf != FALSE)
-                       vscreen[i]->v_flag |= VFCHG;
-               /* and onward to the next window */
-               wp = wp->w_wndp;
-       }
-
-       if (sgarbf != FALSE) {  /* Screen is garbage.    */
-               sgarbf = FALSE; /* Erase-page clears.    */
-               epresf = FALSE; /* The message area.     */
-               tttop = HUGE;   /* Forget where you set. */
-               ttbot = HUGE;   /* scroll region.        */
-               tthue = CNONE;  /* Color unknown.        */
-               ttmove(0, 0);
-               tteeop();
-               for (i = 0; i < nrow - 1; ++i) {
-                       uline(i, vscreen[i], &blanks);
-                       ucopy(vscreen[i], pscreen[i]);
-               }
-               ttmove(currow, curcol - lbound);
-               ttflush();
-               return;
-       }
-       if (hflag != FALSE) {                   /* Hard update?         */
-               for (i = 0; i < nrow - 1; ++i) {/* Compute hash data.   */
-                       hash(vscreen[i]);
-                       hash(pscreen[i]);
-               }
-               offs = 0;                       /* Get top match.       */
-               while (offs != nrow - 1) {
-                       vp1 = vscreen[offs];
-                       vp2 = pscreen[offs];
-                       if (vp1->v_color != vp2->v_color
-                           || vp1->v_hash != vp2->v_hash)
-                               break;
-                       uline(offs, vp1, vp2);
-                       ucopy(vp1, vp2);
-                       ++offs;
-               }
-               if (offs == nrow - 1) {         /* Might get it all.    */
-                       ttmove(currow, curcol - lbound);
-                       ttflush();
-                       return;
-               }
-               size = nrow - 1;                /* Get bottom match.    */
-               while (size != offs) {
-                       vp1 = vscreen[size - 1];
-                       vp2 = pscreen[size - 1];
-                       if (vp1->v_color != vp2->v_color
-                           || vp1->v_hash != vp2->v_hash)
-                               break;
-                       uline(size - 1, vp1, vp2);
-                       ucopy(vp1, vp2);
-                       --size;
-               }
-               if ((size -= offs) == 0)        /* Get screen size.     */
-                       panic("Illegal screen size in update");
-               setscores(offs, size);          /* Do hard update.      */
-               traceback(offs, size, size, size);
-               for (i = 0; i < size; ++i)
-                       ucopy(vscreen[offs + i], pscreen[offs + i]);
-               ttmove(currow, curcol - lbound);
-               ttflush();
-               return;
-       }
-       for (i = 0; i < nrow - 1; ++i) {        /* Easy update.         */
-               vp1 = vscreen[i];
-               vp2 = pscreen[i];
-               if ((vp1->v_flag & VFCHG) != 0) {
-                       uline(i, vp1, vp2);
-                       ucopy(vp1, vp2);
-               }
-       }
-       ttmove(currow, curcol - lbound);
-       ttflush();
-}
-
-/*
- * Update a saved copy of a line,
- * kept in a video structure. The "vvp" is
- * the one in the "vscreen". The "pvp" is the one
- * in the "pscreen". This is called to make the
- * virtual and physical screens the same when
- * display has done an update.
- */
-void
-ucopy(struct video *vvp, struct video *pvp)
-{
-       vvp->v_flag &= ~VFCHG;          /* Changes done.         */
-       pvp->v_flag = vvp->v_flag;      /* Update model.         */
-       pvp->v_hash = vvp->v_hash;
-       pvp->v_cost = vvp->v_cost;
-       pvp->v_color = vvp->v_color;
-       bcopy(vvp->v_text, pvp->v_text, ncol);
-}
-
-/*
- * updext: update the extended line which the cursor is currently on at a
- * column greater than the terminal width. The line will be scrolled right or
- * left to let the user see where the cursor is.
- */
-void
-updext(int currow, int curcol)
-{
-       struct line     *lp;                    /* pointer to current line */
-       int      j;                     /* index into line */
-
-       if (ncol < 2)
-               return;
-
-       /*
-        * calculate what column the left bound should be
-        * (force cursor into middle half of screen)
-        */
-       lbound = curcol - (curcol % (ncol >> 1)) - (ncol >> 2);
-
-       /*
-        * scan through the line outputing characters to the virtual screen
-        * once we reach the left edge
-        */
-       vtmove(currow, -lbound);                /* start scanning offscreen */
-       lp = curwp->w_dotp;                     /* line to output */
-       for (j = 0; j < llength(lp); ++j)       /* until the end-of-line */
-               vtpute(lgetc(lp, j));
-       vteeol();                               /* truncate the virtual line */
-       vscreen[currow]->v_text[0] = '$';       /* and put a '$' in column 1 */
-}
-
-/*
- * Update a single line. This routine only
- * uses basic functionality (no insert and delete character,
- * but erase to end of line). The "vvp" points at the video
- * structure for the line on the virtual screen, and the "pvp"
- * is the same for the physical screen. Avoid erase to end of
- * line when updating CMODE color lines, because of the way that
- * reverse video works on most terminals.
- */
-void
-uline(int row, struct video *vvp, struct video *pvp)
-{
-       char  *cp1;
-       char  *cp2;
-       char  *cp3;
-       char  *cp4;
-       char  *cp5;
-       int    nbflag;
-
-       if (vvp->v_color != pvp->v_color) {     /* Wrong color, do a     */
-               ttmove(row, 0);                 /* full redraw.          */
-#ifdef STANDOUT_GLITCH
-               if (pvp->v_color != CTEXT && magic_cookie_glitch >= 0)
-                       tteeol();
-#endif
-               ttcolor(vvp->v_color);
-#ifdef STANDOUT_GLITCH
-               cp1 = &vvp->v_text[magic_cookie_glitch > 0 ? magic_cookie_glitch : 0];
-               /*
-                * The odd code for magic_cookie_glitch==0 is to avoid
-                * putting the invisible glitch character on the next line.
-                * (Hazeltine executive 80 model 30)
-                */
-               cp2 = &vvp->v_text[ncol - (magic_cookie_glitch >= 0 ?
-                   (magic_cookie_glitch != 0 ? magic_cookie_glitch : 1) : 0)];
-#else
-               cp1 = &vvp->v_text[0];
-               cp2 = &vvp->v_text[ncol];
-#endif
-               while (cp1 != cp2) {
-                       ttputc(*cp1++);
-                       ++ttcol;
-               }
-#ifndef MOVE_STANDOUT
-               ttcolor(CTEXT);
-#endif
-               return;
-       }
-       cp1 = &vvp->v_text[0];          /* Compute left match.   */
-       cp2 = &pvp->v_text[0];
-       while (cp1 != &vvp->v_text[ncol] && cp1[0] == cp2[0]) {
-               ++cp1;
-               ++cp2;
-       }
-       if (cp1 == &vvp->v_text[ncol])  /* All equal.            */
-               return;
-       nbflag = FALSE;
-       cp3 = &vvp->v_text[ncol];       /* Compute right match.  */
-       cp4 = &pvp->v_text[ncol];
-       while (cp3[-1] == cp4[-1]) {
-               --cp3;
-               --cp4;
-               if (cp3[0] != ' ')      /* Note non-blanks in    */
-                       nbflag = TRUE;  /* the right match.      */
-       }
-       cp5 = cp3;                      /* Is erase good?        */
-       if (nbflag == FALSE && vvp->v_color == CTEXT) {
-               while (cp5 != cp1 && cp5[-1] == ' ')
-                       --cp5;
-               /* Alcyon hack */
-               if ((int) (cp3 - cp5) <= tceeol)
-                       cp5 = cp3;
-       }
-       /* Alcyon hack */
-       ttmove(row, (int) (cp1 - &vvp->v_text[0]));
-#ifdef STANDOUT_GLITCH
-       if (vvp->v_color != CTEXT && magic_cookie_glitch > 0) {
-               if (cp1 < &vvp->v_text[magic_cookie_glitch])
-                       cp1 = &vvp->v_text[magic_cookie_glitch];
-               if (cp5 > &vvp->v_text[ncol - magic_cookie_glitch])
-                       cp5 = &vvp->v_text[ncol - magic_cookie_glitch];
-       } else if (magic_cookie_glitch < 0)
-#endif
-               ttcolor(vvp->v_color);
-       while (cp1 != cp5) {
-               ttputc(*cp1++);
-               ++ttcol;
-       }
-       if (cp5 != cp3)                 /* Do erase.             */
-               tteeol();
-}
-
-/*
- * Redisplay the mode line for the window pointed to by the "wp".
- * This is the only routine that has any idea of how the mode line is
- * formatted. You can change the modeline format by hacking at this
- * routine. Called by "update" any time there is a dirty window.  Note
- * that if STANDOUT_GLITCH is defined, first and last magic_cookie_glitch
- * characters may never be seen.
- */
-void
-modeline(struct mgwin *wp)
-{
-       int     n, md;
-       struct buffer *bp;
-       char sl[21];            /* Overkill. Space for 2^64 in base 10. */
-       int len;
-
-       n = wp->w_toprow + wp->w_ntrows;        /* Location.             */
-       vscreen[n]->v_color = CMODE;            /* Mode line color.      */
-       vscreen[n]->v_flag |= (VFCHG | VFHBAD); /* Recompute, display.   */
-       vtmove(n, 0);                           /* Seek to right line.   */
-       bp = wp->w_bufp;
-       vtputc('-');
-       vtputc('-');
-       if ((bp->b_flag & BFREADONLY) != 0) {
-               vtputc('%');
-               if ((bp->b_flag & BFCHG) != 0)
-                       vtputc('*');
-               else
-                       vtputc('%');
-       } else if ((bp->b_flag & BFCHG) != 0) { /* "*" if changed.       */
-               vtputc('*');
-               vtputc('*');
-       } else {
-               vtputc('-');
-               vtputc('-');
-       }
-       vtputc('-');
-       n = 5;
-       n += vtputs("Mg: ");
-       if (bp->b_bname[0] != '\0')
-               n += vtputs(&(bp->b_bname[0]));
-       while (n < 42) {                        /* Pad out with blanks.  */
-               vtputc(' ');
-               ++n;
-       }
-       vtputc('(');
-       ++n;
-       for (md = 0; ; ) {
-               n += vtputs(bp->b_modes[md]->p_name);
-               if (++md > bp->b_nmodes)
-                       break;
-               vtputc('-');
-               ++n;
-       }
-       /* XXX These should eventually move to a real mode */
-       if (macrodef == TRUE)
-               n += vtputs("-def");
-       if (globalwd == TRUE)
-               n += vtputs("-gwd");
-       vtputc(')');
-       ++n;
-
-       if (linenos) {
-               len = snprintf(sl, sizeof(sl), "--L%d--C%d", wp->w_dotline,
-                   getcolpos());
-               if (len < sizeof(sl) && len != -1)
-                       n += vtputs(sl);
-       }
-
-       while (n < ncol) {                      /* Pad out.              */
-               vtputc('-');
-               ++n;
-       }
-}
-
-/*
- * Output a string to the mode line, report how long it was.
- */
-int
-vtputs(const char *s)
-{
-       int n = 0;
-
-       while (*s != '\0') {
-               vtputc(*s++);
-               ++n;
-       }
-       return (n);
-}
-
-/*
- * Compute the hash code for the line pointed to by the "vp".
- * Recompute it if necessary. Also set the approximate redisplay
- * cost. The validity of the hash code is marked by a flag bit.
- * The cost understand the advantages of erase to end of line.
- * Tuned for the VAX by Bob McNamara; better than it used to be on
- * just about any machine.
- */
-void
-hash(struct video *vp)
-{
-       int     i, n;
-       char   *s;
-
-       if ((vp->v_flag & VFHBAD) != 0) {       /* Hash bad.             */
-               s = &vp->v_text[ncol - 1];
-               for (i = ncol; i != 0; --i, --s)
-                       if (*s != ' ')
-                               break;
-               n = ncol - i;                   /* Erase cheaper?        */
-               if (n > tceeol)
-                       n = tceeol;
-               vp->v_cost = i + n;             /* Bytes + blanks.       */
-               for (n = 0; i != 0; --i, --s)
-                       n = (n << 5) + n + *s;
-               vp->v_hash = n;                 /* Hash code.            */
-               vp->v_flag &= ~VFHBAD;          /* Flag as all done.     */
-       }
-}
-
-/*
- * Compute the Insert-Delete
- * cost matrix. The dynamic programming algorithm
- * described by James Gosling is used. This code assumes
- * that the line above the echo line is the last line involved
- * in the scroll region. This is easy to arrange on the VT100
- * because of the scrolling region. The "offs" is the origin 0
- * offset of the first row in the virtual/physical screen that
- * is being updated; the "size" is the length of the chunk of
- * screen being updated. For a full screen update, use offs=0
- * and size=nrow-1.
- *
- * Older versions of this code implemented the score matrix by
- * a two dimensional array of SCORE nodes. This put all kinds of
- * multiply instructions in the code! This version is written to
- * use a linear array and pointers, and contains no multiplication
- * at all. The code has been carefully looked at on the VAX, with
- * only marginal checking on other machines for efficiency. In
- * fact, this has been tuned twice! Bob McNamara tuned it even
- * more for the VAX, which is a big issue for him because of
- * the 66 line X displays.
- *
- * On some machines, replacing the "for (i=1; i<=size; ++i)" with
- * i = 1; do { } while (++i <=size)" will make the code quite a
- * bit better; but it looks ugly.
- */
-void
-setscores(int offs, int size)
-{
-       struct score     *sp;
-       struct score     *sp1;
-       struct video    **vp, **pp;
-       struct video    **vbase, **pbase;
-       int       tempcost;
-       int       bestcost;
-       int       j, i;
-
-       vbase = &vscreen[offs - 1];     /* By hand CSE's.        */
-       pbase = &pscreen[offs - 1];
-       score[0].s_itrace = 0;          /* [0, 0]                */
-       score[0].s_jtrace = 0;
-       score[0].s_cost = 0;
-       sp = &score[1];                 /* Row 0, inserts.       */
-       tempcost = 0;
-       vp = &vbase[1];
-       for (j = 1; j <= size; ++j) {
-               sp->s_itrace = 0;
-               sp->s_jtrace = j - 1;
-               tempcost += tcinsl;
-               tempcost += (*vp)->v_cost;
-               sp->s_cost = tempcost;
-               ++vp;
-               ++sp;
-       }
-       sp = &score[nrow];              /* Column 0, deletes.    */
-       tempcost = 0;
-       for (i = 1; i <= size; ++i) {
-               sp->s_itrace = i - 1;
-               sp->s_jtrace = 0;
-               tempcost += tcdell;
-               sp->s_cost = tempcost;
-               sp += nrow;
-       }
-       sp1 = &score[nrow + 1];         /* [1, 1].               */
-       pp = &pbase[1];
-       for (i = 1; i <= size; ++i) {
-               sp = sp1;
-               vp = &vbase[1];
-               for (j = 1; j <= size; ++j) {
-                       sp->s_itrace = i - 1;
-                       sp->s_jtrace = j;
-                       bestcost = (sp - nrow)->s_cost;
-                       if (j != size)  /* Cd(A[i])=0 @ Dis.     */
-                               bestcost += tcdell;
-                       tempcost = (sp - 1)->s_cost;
-                       tempcost += (*vp)->v_cost;
-                       if (i != size)  /* Ci(B[j])=0 @ Dsj.     */
-                               tempcost += tcinsl;
-                       if (tempcost < bestcost) {
-                               sp->s_itrace = i;
-                               sp->s_jtrace = j - 1;
-                               bestcost = tempcost;
-                       }
-                       tempcost = (sp - nrow - 1)->s_cost;
-                       if ((*pp)->v_color != (*vp)->v_color
-                           || (*pp)->v_hash != (*vp)->v_hash)
-                               tempcost += (*vp)->v_cost;
-                       if (tempcost < bestcost) {
-                               sp->s_itrace = i - 1;
-                               sp->s_jtrace = j - 1;
-                               bestcost = tempcost;
-                       }
-                       sp->s_cost = bestcost;
-                       ++sp;           /* Next column.          */
-                       ++vp;
-               }
-               ++pp;
-               sp1 += nrow;            /* Next row.             */
-       }
-}
-
-/*
- * Trace back through the dynamic programming cost
- * matrix, and update the screen using an optimal sequence
- * of redraws, insert lines, and delete lines. The "offs" is
- * the origin 0 offset of the chunk of the screen we are about to
- * update. The "i" and "j" are always started in the lower right
- * corner of the matrix, and imply the size of the screen.
- * A full screen traceback is called with offs=0 and i=j=nrow-1.
- * There is some do-it-yourself double subscripting here,
- * which is acceptable because this routine is much less compute
- * intensive then the code that builds the score matrix!
- */
-void
-traceback(int offs, int size, int i, int j)
-{
-       int     itrace, jtrace;
-       int     k;
-       int     ninsl, ndraw, ndell;
-
-       if (i == 0 && j == 0)   /* End of update.        */
-               return;
-       itrace = score[(nrow * i) + j].s_itrace;
-       jtrace = score[(nrow * i) + j].s_jtrace;
-       if (itrace == i) {      /* [i, j-1]              */
-               ninsl = 0;      /* Collect inserts.      */
-               if (i != size)
-                       ninsl = 1;
-               ndraw = 1;
-               while (itrace != 0 || jtrace != 0) {
-                       if (score[(nrow * itrace) + jtrace].s_itrace != itrace)
-                               break;
-                       jtrace = score[(nrow * itrace) + jtrace].s_jtrace;
-                       if (i != size)
-                               ++ninsl;
-                       ++ndraw;
-               }
-               traceback(offs, size, itrace, jtrace);
-               if (ninsl != 0) {
-                       ttcolor(CTEXT);
-                       ttinsl(offs + j - ninsl, offs + size - 1, ninsl);
-               }
-               do {            /* B[j], A[j] blank.     */
-                       k = offs + j - ndraw;
-                       uline(k, vscreen[k], &blanks);
-               } while (--ndraw);
-               return;
-       }
-       if (jtrace == j) {      /* [i-1, j]              */
-               ndell = 0;      /* Collect deletes.      */
-               if (j != size)
-                       ndell = 1;
-               while (itrace != 0 || jtrace != 0) {
-                       if (score[(nrow * itrace) + jtrace].s_jtrace != jtrace)
-                               break;
-                       itrace = score[(nrow * itrace) + jtrace].s_itrace;
-                       if (j != size)
-                               ++ndell;
-               }
-               if (ndell != 0) {
-                       ttcolor(CTEXT);
-                       ttdell(offs + i - ndell, offs + size - 1, ndell);
-               }
-               traceback(offs, size, itrace, jtrace);
-               return;
-       }
-       traceback(offs, size, itrace, jtrace);
-       k = offs + j - 1;
-       uline(k, vscreen[k], pscreen[offs + i - 1]);
-}