home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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. Two conditional
- * compilation flags; the GOSLING flag enables dynamic programming redisplay,
- * using the algorithm published by Jim Gosling in SIGOA. The MEMMAP changes
- * things around for memory mapped video. With both off, the terminal is a
- * VT52.
- */
- #include "nondynvid.h"
- #include "nrow.h"
- #include "ncol.h"
- #include "notab.h"
-
- #include "def.h"
- #include "line.h"
- #include "kbd.h"
- #include "buffer.h"
- #include "window.h"
-
- #ifdef ANSI
- #include <string.h>
- #endif
-
- VOID
- updext(), modeline();
-
-
- #ifdef STANDOUT_GLITCH
- extern int SG; /* number of standout glitches */
- #endif
-
- /*
- * These two things are normally found in sysdef.h. They are currently
- * defined to get the smallest code. They can be changed on a
- * system-by-system basis to get better code generation if that happens on
- * your system. For instance, VAXen prefer them both to both to be ints.
- */
- #ifndef XCHAR
- #define XCHAR char
- #endif
-
- #ifndef XSHORT
- #define XSHORT short int
- #endif
-
- /*
- * A video structure always holds an array of characters whose length is
- * equal to the longest line possible. Only some of this is used if "ncol"
- * isn't the same as "NCOL".
- */
- 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[NCOL]; /* 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 score 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. */
- };
-
- int sgarbf = TRUE; /* TRUE if screen is garbage. */
- int vtrow = 0; /* Virtual cursor row. */
- int vtcol = 0; /* 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[NROW - 1]; /* Edge vector, virtual. */
- struct video *pscreen[NROW - 1]; /* Edge vector, physical. */
- struct video vid[2 * (NROW - 1)]; /* Actual screen data */
- struct video blanks; /* Blank line image. */
-
- /*
- * Some prototypes
- */
- static VOID ucopy
- PROTO((struct video * vvp, struct video * pvp));
- static VOID uline
- PROTO((int row, struct video * vvp, struct video * pvp));
- static VOID hash
- PROTO((struct video * vp));
- VOID setscores
- PROTO((int offs, int size));
- VOID traceback
- PROTO((int offs, int size, int i, int j));
-
-
- #ifndef NONDYNVID
- /*
- * 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 dscore[NROW * NROW];
- #endif
-
- /*
- * 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()
- {
- register struct video *vp;
- register int i;
-
- ttopen();
- ttinit();
- vp = &vid[0];
- for (i = 0; i < NROW - 1; ++i) {
- vscreen[i] = vp;
- ++vp;
- pscreen[i] = vp;
- ++vp;
- }
- 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()
- {
- 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(row, 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(c)
- register int c;
- {
- register struct video *vp;
-
- 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
- vp->v_text[vtcol++] = c;
- }
-
- /*
- * 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(c)
- int c;
- {
- register struct video *vp;
-
- 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()
- {
- register 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()
- {
- register struct line *lp;
- register struct window *wp;
- register struct video *vp1;
- struct video *vp2;
- register int i;
- register int j;
- register int c;
- register int hflag;
- register int currow;
- register int curcol;
- #ifndef NONDYNVID
- register int offs;
- register int size;
- #endif
- VOID traceback();
-
- if (typeahead())
- return;
- if (sgarbf) { /* must update everything */
- wp = wheadp;
- while (wp != NULL) {
- wp->w_flag |= WFMODE | WFHARD;
- wp = wp->w_wndp;
- }
- }
- hflag = FALSE; /* Not hard. */
- wp = wheadp;
- while (wp != NULL) {
- if (wp->w_flag != 0) { /* Need update. */
- if ((wp->w_flag & WFFORCE) == 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_linep)
- break;
- lp = lforw(lp);
- }
- }
- i = wp->w_force; /* Reframe this one. */
- 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;
- lp = wp->w_dotp;
- while (i != 0 && lback(lp) != wp->w_bufp->b_linep) {
- --i;
- lp = lback(lp);
- }
- wp->w_linep = lp;
- wp->w_flag |= WFHARD; /* Force full. */
- out:
- lp = wp->w_linep; /* Try reduced update. */
- i = wp->w_toprow;
- if ((wp->w_flag & ~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_flag & (WFEDIT | WFHARD)) != 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_linep) {
- for (j = 0; j < llength(lp); ++j)
- vtputc(lgetc(lp, j));
- lp = lforw(lp);
- }
- vteeol();
- ++i;
- }
- }
- if ((wp->w_flag & WFMODE) != 0)
- modeline(wp);
- wp->w_flag = 0;
- wp->w_force = 0;
- }
- wp = wp->w_wndp;
- }
- 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;
- else if (ISCTRL(c) != FALSE)
- ++curcol;
- ++curcol;
- }
- 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;
- }
- #ifndef NONDYNVID
- 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;
- }
- #endif
- 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.
- */
- static VOID
- ucopy(vvp, pvp)
- register struct video *vvp;
- register 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(currow, curcol)
- int currow, curcol;
- {
- register struct line *lp; /* pointer to current line */
- register int j; /* index into line */
-
- /* 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.
- */
- static VOID
- uline(row, vvp, pvp)
- struct video *vvp;
- struct video *pvp;
- {
- #ifdef MEMMAP
- putline(row + 1, 1, &vvp->v_text[0]);
- #else
- register char *cp1;
- register char *cp2;
- register char *cp3;
- char *cp4;
- char *cp5;
- register 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 && SG >= 0)
- tteeol();
- #endif
- ttcolor(vvp->v_color);
- #ifdef STANDOUT_GLITCH
- cp1 = &vvp->v_text[SG > 0 ? SG : 0];
- /*
- * the odd code for SG==0 is to avoid putting the invisable
- * glitch character on the next line. (Hazeltine executive 80
- * model 30)
- */
- cp2 = &vvp->v_text[ncol - (SG >= 0 ? (SG != 0 ? SG : 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 && SG > 0) {
- if (cp1 < &vvp->v_text[SG])
- cp1 = &vvp->v_text[SG];
- if (cp5 > &vvp->v_text[ncol - SG])
- cp5 = &vvp->v_text[ncol - SG];
- } else if (SG < 0)
- #endif
- ttcolor(vvp->v_color);
- while (cp1 != cp5) {
- ttputc(*cp1++);
- ++ttcol;
- }
- if (cp5 != cp3) /* Do erase. */
- tteeol();
- #endif
- }
-
- /*
- * Redisplay the mode line for the window pointed to by the "wp". This is the
- * only routine that has any idea of how the modeline 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 SG characters may never be seen.
- */
- VOID
- modeline(wp)
- register struct window *wp;
- {
- register int n;
- register struct buffer *bp;
- int mode;
-
- 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 & 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 (mode = 0;;) {
- n += vtputs(bp->b_modes[mode]->p_name);
- if (++mode > bp->b_nmodes)
- break;
- vtputc('-');
- ++n;
- }
- vtputc(')');
- ++n;
- while (n < ncol) { /* Pad out. */
- vtputc('-');
- ++n;
- }
- }
- /*
- * output a string to the mode line, report how long it was.
- */
- vtputs(s)
- register char *s;
- {
- register int n = 0;
-
- while (*s != '\0') {
- vtputc(*s++);
- ++n;
- }
- return n;
- }
- #ifndef NONDYNVID
- /*
- * 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.
- */
- static VOID
- hash(vp)
- register struct video *vp;
- {
- register int i;
- register int n;
- register 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(offs, size)
- {
- register struct score *sp;
- struct score *sp1;
- register int tempcost;
- register int bestcost;
- register int j;
- register int i;
- register struct video **vp;
- struct video **pp, **vbase, **pbase;
-
- vbase = &vscreen[offs - 1]; /* By hand CSE's. */
- pbase = &pscreen[offs - 1];
- dscore[0].s_itrace = 0; /* [0, 0] */
- dscore[0].s_jtrace = 0;
- dscore[0].s_cost = 0;
- sp = &dscore[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 = &dscore[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 = &dscore[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(offs, size, i, j)
- {
- register int itrace;
- register int jtrace;
- register int k;
- register int ninsl;
- register int ndraw;
- register int ndell;
-
- if (i == 0 && j == 0) /* End of update. */
- return;
- itrace = dscore[(NROW * i) + j].s_itrace;
- jtrace = dscore[(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 (dscore[(NROW * itrace) + jtrace].s_itrace != itrace)
- break;
- jtrace = dscore[(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 (dscore[(NROW * itrace) + jtrace].s_jtrace != jtrace)
- break;
- itrace = dscore[(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]);
- }
- #endif
-