X-Git-Url: https://pd.if.org/git/?p=pd_readline;a=blobdiff_plain;f=mg%2Fdisplay.c;fp=mg%2Fdisplay.c;h=0000000000000000000000000000000000000000;hp=ba7c580e9c5b75cdbcfff5c90914d163e1ce4e8a;hb=4bb27266f935c9aafad6870ffc8847fc65c8120f;hpb=3f771e17236364ded86e96ee64f99344337991f8 diff --git a/mg/display.c b/mg/display.c deleted file mode 100644 index ba7c580..0000000 --- a/mg/display.c +++ /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 - -/* - * 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 -#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]); -}