[BACK]Return to display.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/display.c, Revision 1.3

1.1       deraadt     1: /*
                      2:  * The functions in this file handle redisplay. The
                      3:  * redisplay system knows almost nothing about the editing
                      4:  * process; the editing functions do, however, set some
                      5:  * hints to eliminate a lot of the grinding. There is more
                      6:  * that can be done; the "vtputc" interface is a real
                      7:  * pig. Two conditional compilation flags; the GOSLING
                      8:  * flag enables dynamic programming redisplay, using the
                      9:  * algorithm published by Jim Gosling in SIGOA. The MEMMAP
                     10:  * changes things around for memory mapped video. With
                     11:  * both off, the terminal is a VT52.
                     12:  */
                     13: #include       "def.h"
                     14: #include       "kbd.h"
                     15:
                     16: /*
                     17:  * You can change these back to the types
                     18:  * implied by the name if you get tight for space. If you
                     19:  * make both of them "int" you get better code on the VAX.
                     20:  * They do nothing if this is not Gosling redisplay, except
                     21:  * for change the size of a structure that isn't used.
                     22:  * A bit of a cheat.
                     23:  */
                     24: /* These defines really belong in sysdef.h */
                     25: #ifndef XCHAR
1.3     ! millert    26: #define        XCHAR   int
        !            27: #define        XSHORT  int
1.1       deraadt    28: #endif
                     29:
                     30: #ifdef STANDOUT_GLITCH
1.2       millert    31: #include <term.h>
1.1       deraadt    32: #endif
                     33:
                     34: /*
                     35:  * A video structure always holds
                     36:  * an array of characters whose length is equal to
                     37:  * the longest line possible. Only some of this is
                     38:  * used if "ncol" isn't the same as "NCOL".
                     39:  */
1.3     ! millert    40: typedef struct {
        !            41:        short           v_hash;         /* Hash code, for compares.      */
        !            42:        short           v_flag;         /* Flag word.                    */
        !            43:        short           v_color;        /* Color of the line.            */
        !            44:        XSHORT          v_cost;         /* Cost of display.              */
        !            45:        char            v_text[NCOL];   /* The actual characters.        */
        !            46: } VIDEO;
        !            47:
        !            48: #define VFCHG  0x0001                  /* Changed.                      */
        !            49: #define VFHBAD 0x0002                  /* Hash and cost are bad.        */
        !            50: #define VFEXT  0x0004                  /* extended line (beond ncol)    */
1.1       deraadt    51:
                     52: /*
                     53:  * SCORE structures hold the optimal
                     54:  * trace trajectory, and the cost of redisplay, when
                     55:  * the dynamic programming redisplay code is used.
                     56:  * If no fancy redisplay, this isn't used. The trace index
                     57:  * fields can be "char", and the score a "short", but
                     58:  * this makes the code worse on the VAX.
                     59:  */
1.3     ! millert    60: typedef struct {
        !            61:        XCHAR           s_itrace;       /* "i" index for track back.     */
        !            62:        XCHAR           s_jtrace;       /* "j" index for trace back.     */
        !            63:        XSHORT          s_cost;         /* Display cost.                 */
        !            64: } SCORE;
        !            65:
        !            66:
        !            67: VOID     vtmove         __P((int, int));
        !            68: VOID     vtputc         __P((int));
        !            69: VOID     vtpute         __P((int));
        !            70: int      vtputs         __P((char *));
        !            71: VOID     vteeol         __P((void));
        !            72: VOID     updext         __P((int, int));
        !            73: VOID     modeline       __P((MGWIN *));
        !            74: VOID     setscores      __P((int, int));
        !            75: VOID     traceback      __P((int, int, int, int));
        !            76: VOID     ucopy          __P((VIDEO *, VIDEO *));
        !            77: VOID     uline          __P((int, VIDEO *, VIDEO *));
        !            78: VOID     hash           __P((VIDEO *));
        !            79:
        !            80:
        !            81: int             sgarbf = TRUE;         /* TRUE if screen is garbage.    */
        !            82: int             vtrow = 0;             /* Virtual cursor row.           */
        !            83: int             vtcol = 0;             /* Virtual cursor column.        */
        !            84: int             tthue = CNONE;         /* Current color.                */
        !            85: int             ttrow = HUGE;          /* Physical cursor row.          */
        !            86: int             ttcol = HUGE;          /* Physical cursor column.       */
        !            87: int             tttop = HUGE;          /* Top of scroll region.         */
        !            88: int             ttbot = HUGE;          /* Bottom of scroll region.      */
        !            89: int             lbound = 0;            /* leftmost bound of the current line */
        !            90:                                        /* being displayed               */
        !            91:
        !            92: VIDEO          *vscreen[NROW - 1];     /* Edge vector, virtual.         */
        !            93: VIDEO          *pscreen[NROW - 1];     /* Edge vector, physical.        */
        !            94: VIDEO           video[2 * (NROW - 1)]; /* Actual screen data.           */
        !            95: VIDEO           blanks;                        /* Blank line image.             */
1.1       deraadt    96:
                     97: #ifdef GOSLING
                     98: /*
                     99:  * This matrix is written as an array because
                    100:  * we do funny things in the "setscores" routine, which
                    101:  * is very compute intensive, to make the subscripts go away.
                    102:  * It would be "SCORE  score[NROW][NROW]" in old speak.
                    103:  * Look at "setscores" to understand what is up.
                    104:  */
1.3     ! millert   105: SCORE score[NROW * NROW];
1.1       deraadt   106: #endif
                    107:
                    108: /*
                    109:  * Initialize the data structures used
                    110:  * by the display code. The edge vectors used
                    111:  * to access the screens are set up. The operating
                    112:  * system's terminal I/O channel is set up. Fill the
                    113:  * "blanks" array with ASCII blanks. The rest is done
                    114:  * at compile time. The original window is marked
                    115:  * as needing full update, and the physical screen
                    116:  * is marked as garbage, so all the right stuff happens
                    117:  * on the first call to redisplay.
                    118:  */
                    119: VOID
1.3     ! millert   120: vtinit()
        !           121: {
        !           122:        VIDEO *vp;
        !           123:        int    i;
1.1       deraadt   124:
                    125:        ttopen();
                    126:        ttinit();
                    127:        vp = &video[0];
1.3     ! millert   128:        for (i = 0; i < NROW - 1; ++i) {
1.1       deraadt   129:                vscreen[i] = vp;
                    130:                ++vp;
                    131:                pscreen[i] = vp;
                    132:                ++vp;
                    133:        }
                    134:        blanks.v_color = CTEXT;
1.3     ! millert   135:        for (i = 0; i < NCOL; ++i)
1.1       deraadt   136:                blanks.v_text[i] = ' ';
                    137: }
                    138:
                    139: /*
                    140:  * Tidy up the virtual display system
                    141:  * in anticipation of a return back to the host
                    142:  * operating system. Right now all we do is position
                    143:  * the cursor to the last line, erase the line, and
                    144:  * close the terminal channel.
                    145:  */
                    146: VOID
1.3     ! millert   147: vttidy()
        !           148: {
        !           149:
1.1       deraadt   150:        ttcolor(CTEXT);
1.3     ! millert   151:        ttnowindow();           /* No scroll window.     */
        !           152:        ttmove(nrow - 1, 0);    /* Echo line.            */
1.1       deraadt   153:        tteeol();
                    154:        tttidy();
                    155:        ttflush();
                    156:        ttclose();
                    157: }
                    158:
                    159: /*
                    160:  * Move the virtual cursor to an origin
                    161:  * 0 spot on the virtual display screen. I could
                    162:  * store the column as a character pointer to the spot
                    163:  * on the line, which would make "vtputc" a little bit
                    164:  * more efficient. No checking for errors.
                    165:  */
                    166: VOID
1.3     ! millert   167: vtmove(row, col)
        !           168:        int row, col;
        !           169: {
        !           170:
1.1       deraadt   171:        vtrow = row;
                    172:        vtcol = col;
                    173: }
                    174:
                    175: /*
                    176:  * Write a character to the virtual display,
                    177:  * dealing with long lines and the display of unprintable
                    178:  * things like control characters. Also expand tabs every 8
                    179:  * columns. This code only puts printing characters into
                    180:  * the virtual display image. Special care must be taken when
                    181:  * expanding tabs. On a screen whose width is not a multiple
                    182:  * of 8, it is possible for the virtual cursor to hit the
                    183:  * right margin before the next tab stop is reached. This
                    184:  * makes the tab code loop if you are not careful.
                    185:  * Three guesses how we found this.
                    186:  */
                    187: VOID
1.3     ! millert   188: vtputc(c)
        !           189:        int    c;
        !           190: {
        !           191:        VIDEO *vp;
1.1       deraadt   192:
                    193:        vp = vscreen[vtrow];
                    194:        if (vtcol >= ncol)
1.3     ! millert   195:                vp->v_text[ncol - 1] = '$';
1.1       deraadt   196:        else if (c == '\t'
                    197: #ifdef NOTAB
1.3     ! millert   198:                 && !(curbp->b_flag & BFNOTAB)
1.1       deraadt   199: #endif
1.3     ! millert   200:                ) {
1.1       deraadt   201:                do {
                    202:                        vtputc(' ');
1.3     ! millert   203:                } while (vtcol < ncol && (vtcol & 0x07) != 0);
1.1       deraadt   204:        } else if (ISCTRL(c)) {
                    205:                vtputc('^');
                    206:                vtputc(CCHR(c));
                    207:        } else
                    208:                vp->v_text[vtcol++] = c;
                    209: }
                    210:
1.3     ! millert   211: /*
        !           212:  * Put a character to the virtual screen in an extended line.  If we are not
        !           213:  * yet on left edge, don't print it yet.  Check for overflow on the right
        !           214:  * margin.
1.1       deraadt   215:  */
                    216: VOID
                    217: vtpute(c)
1.3     ! millert   218:        int    c;
1.1       deraadt   219: {
1.3     ! millert   220:        VIDEO *vp;
1.1       deraadt   221:
1.3     ! millert   222:        vp = vscreen[vtrow];
1.1       deraadt   223:
1.3     ! millert   224:        if (vtcol >= ncol)
        !           225:                vp->v_text[ncol - 1] = '$';
        !           226:        else if (c == '\t'
1.1       deraadt   227: #ifdef NOTAB
1.3     ! millert   228:                 && !(curbp->b_flag & BFNOTAB)
1.1       deraadt   229: #endif
1.3     ! millert   230:                ) {
        !           231:                do {
        !           232:                        vtpute(' ');
        !           233:                }
        !           234:                while (((vtcol + lbound) & 0x07) != 0 && vtcol < ncol);
        !           235:        } else if (ISCTRL(c) != FALSE) {
        !           236:                vtpute('^');
        !           237:                vtpute(CCHR(c));
        !           238:        } else {
        !           239:                if (vtcol >= 0)
        !           240:                        vp->v_text[vtcol] = c;
        !           241:                ++vtcol;
        !           242:        }
        !           243: }
        !           244:
        !           245: /*
        !           246:  * Erase from the end of the software cursor to the end of the line on which
        !           247:  * the software cursor is located. The display routines will decide if a
        !           248:  * hardware erase to end of line command should be used to display this.
1.1       deraadt   249:  */
                    250: VOID
1.3     ! millert   251: vteeol()
        !           252: {
        !           253:        VIDEO *vp;
1.1       deraadt   254:
                    255:        vp = vscreen[vtrow];
                    256:        while (vtcol < ncol)
                    257:                vp->v_text[vtcol++] = ' ';
                    258: }
                    259:
                    260: /*
                    261:  * Make sure that the display is
                    262:  * right. This is a three part process. First,
                    263:  * scan through all of the windows looking for dirty
                    264:  * ones. Check the framing, and refresh the screen.
                    265:  * Second, make sure that "currow" and "curcol" are
                    266:  * correct for the current window. Third, make the
                    267:  * virtual and physical screens the same.
                    268:  */
                    269: VOID
1.3     ! millert   270: update()
        !           271: {
        !           272:        LINE  *lp;
        !           273:        MGWIN *wp;
        !           274:        VIDEO *vp1;
        !           275:        VIDEO *vp2;
        !           276:        int    i;
        !           277:        int    j;
        !           278:        int    c;
        !           279:        int    hflag;
        !           280:        int    currow;
        !           281:        int    curcol;
        !           282:        int    offs;
        !           283:        int    size;
1.1       deraadt   284:
1.3     ! millert   285:        if (typeahead())
        !           286:                return;
        !           287:        if (sgarbf) {           /* must update everything */
1.1       deraadt   288:                wp = wheadp;
1.3     ! millert   289:                while (wp != NULL) {
1.1       deraadt   290:                        wp->w_flag |= WFMODE | WFHARD;
                    291:                        wp = wp->w_wndp;
                    292:                }
                    293:        }
1.3     ! millert   294:        hflag = FALSE;                  /* Not hard.             */
1.1       deraadt   295:        wp = wheadp;
                    296:        while (wp != NULL) {
1.3     ! millert   297:                if (wp->w_flag != 0) {  /* Need update.          */
        !           298:                        if ((wp->w_flag & WFFORCE) == 0) {
1.1       deraadt   299:                                lp = wp->w_linep;
1.3     ! millert   300:                                for (i = 0; i < wp->w_ntrows; ++i) {
1.1       deraadt   301:                                        if (lp == wp->w_dotp)
                    302:                                                goto out;
                    303:                                        if (lp == wp->w_bufp->b_linep)
                    304:                                                break;
                    305:                                        lp = lforw(lp);
                    306:                                }
                    307:                        }
1.3     ! millert   308:                        i = wp->w_force;        /* Reframe this one.     */
1.1       deraadt   309:                        if (i > 0) {
                    310:                                --i;
                    311:                                if (i >= wp->w_ntrows)
1.3     ! millert   312:                                        i = wp->w_ntrows - 1;
1.1       deraadt   313:                        } else if (i < 0) {
                    314:                                i += wp->w_ntrows;
                    315:                                if (i < 0)
                    316:                                        i = 0;
                    317:                        } else
1.3     ! millert   318:                                i = wp->w_ntrows / 2;
1.1       deraadt   319:                        lp = wp->w_dotp;
1.3     ! millert   320:                        while (i != 0 && lback(lp) != wp->w_bufp->b_linep) {
1.1       deraadt   321:                                --i;
                    322:                                lp = lback(lp);
                    323:                        }
                    324:                        wp->w_linep = lp;
1.3     ! millert   325:                        wp->w_flag |= WFHARD;   /* Force full.           */
        !           326:        out:
        !           327:                        lp = wp->w_linep;       /* Try reduced update.   */
        !           328:                        i = wp->w_toprow;
        !           329:                        if ((wp->w_flag & ~WFMODE) == WFEDIT) {
1.1       deraadt   330:                                while (lp != wp->w_dotp) {
                    331:                                        ++i;
                    332:                                        lp = lforw(lp);
                    333:                                }
                    334:                                vscreen[i]->v_color = CTEXT;
1.3     ! millert   335:                                vscreen[i]->v_flag |= (VFCHG | VFHBAD);
1.1       deraadt   336:                                vtmove(i, 0);
1.3     ! millert   337:                                for (j = 0; j < llength(lp); ++j)
1.1       deraadt   338:                                        vtputc(lgetc(lp, j));
                    339:                                vteeol();
1.3     ! millert   340:                        } else if ((wp->w_flag & (WFEDIT | WFHARD)) != 0) {
1.1       deraadt   341:                                hflag = TRUE;
1.3     ! millert   342:                                while (i < wp->w_toprow + wp->w_ntrows) {
1.1       deraadt   343:                                        vscreen[i]->v_color = CTEXT;
1.3     ! millert   344:                                        vscreen[i]->v_flag |= (VFCHG | VFHBAD);
1.1       deraadt   345:                                        vtmove(i, 0);
                    346:                                        if (lp != wp->w_bufp->b_linep) {
1.3     ! millert   347:                                                for (j = 0; j < llength(lp); ++j)
1.1       deraadt   348:                                                        vtputc(lgetc(lp, j));
                    349:                                                lp = lforw(lp);
                    350:                                        }
                    351:                                        vteeol();
                    352:                                        ++i;
                    353:                                }
                    354:                        }
1.3     ! millert   355:                        if ((wp->w_flag & WFMODE) != 0)
1.1       deraadt   356:                                modeline(wp);
1.3     ! millert   357:                        wp->w_flag = 0;
1.1       deraadt   358:                        wp->w_force = 0;
                    359:                }
                    360:                wp = wp->w_wndp;
                    361:        }
1.3     ! millert   362:        lp = curwp->w_linep;    /* Cursor location.      */
1.1       deraadt   363:        currow = curwp->w_toprow;
                    364:        while (lp != curwp->w_dotp) {
                    365:                ++currow;
                    366:                lp = lforw(lp);
                    367:        }
                    368:        curcol = 0;
                    369:        i = 0;
                    370:        while (i < curwp->w_doto) {
                    371:                c = lgetc(lp, i++);
                    372:                if (c == '\t'
                    373: #ifdef NOTAB
1.3     ! millert   374:                    && !(curbp->b_flag & BFNOTAB)
1.1       deraadt   375: #endif
1.3     ! millert   376:                        )
        !           377:                        curcol |= 0x07;
1.1       deraadt   378:                else if (ISCTRL(c) != FALSE)
                    379:                        ++curcol;
                    380:                ++curcol;
                    381:        }
1.3     ! millert   382:        if (curcol >= ncol - 1) {       /* extended line. */
        !           383:                /* flag we are extended and changed */
1.1       deraadt   384:                vscreen[currow]->v_flag |= VFEXT | VFCHG;
1.3     ! millert   385:                updext(currow, curcol); /* and output extended line */
        !           386:        } else
        !           387:                lbound = 0;     /* not extended line */
1.1       deraadt   388:
1.3     ! millert   389:        /*
        !           390:         * make sure no lines need to be de-extended because the cursor is no
        !           391:         * longer on them
        !           392:         */
1.1       deraadt   393:        wp = wheadp;
                    394:        while (wp != NULL) {
1.3     ! millert   395:                lp = wp->w_linep;
        !           396:                i = wp->w_toprow;
        !           397:                while (i < wp->w_toprow + wp->w_ntrows) {
        !           398:                        if (vscreen[i]->v_flag & VFEXT) {
        !           399:                                /* always flag extended lines as changed */
        !           400:                                vscreen[i]->v_flag |= VFCHG;
        !           401:                                if ((wp != curwp) || (lp != wp->w_dotp) ||
        !           402:                                    (curcol < ncol - 1)) {
        !           403:                                        vtmove(i, 0);
        !           404:                                        for (j = 0; j < llength(lp); ++j)
        !           405:                                                vtputc(lgetc(lp, j));
        !           406:                                        vteeol();
        !           407:                                        /* this line no longer is extended */
        !           408:                                        vscreen[i]->v_flag &= ~VFEXT;
        !           409:                                }
        !           410:                        }
        !           411:                        lp = lforw(lp);
        !           412:                        ++i;
1.1       deraadt   413:                }
1.3     ! millert   414:                /* if garbaged then fix up mode lines */
        !           415:                if (sgarbf != FALSE)
        !           416:                        vscreen[i]->v_flag |= VFCHG;
        !           417:                /* and onward to the next window */
        !           418:                wp = wp->w_wndp;
1.1       deraadt   419:        }
                    420:
1.3     ! millert   421:        if (sgarbf != FALSE) {  /* Screen is garbage.    */
        !           422:                sgarbf = FALSE; /* Erase-page clears     */
        !           423:                epresf = FALSE; /* the message area.     */
        !           424:                tttop = HUGE;   /* Forget where you set */
        !           425:                ttbot = HUGE;   /* scroll region.        */
        !           426:                tthue = CNONE;  /* Color unknown.        */
1.1       deraadt   427:                ttmove(0, 0);
                    428:                tteeop();
1.3     ! millert   429:                for (i = 0; i < nrow - 1; ++i) {
1.1       deraadt   430:                        uline(i, vscreen[i], &blanks);
                    431:                        ucopy(vscreen[i], pscreen[i]);
                    432:                }
                    433:                ttmove(currow, curcol - lbound);
                    434:                ttflush();
                    435:                return;
                    436:        }
                    437: #ifdef GOSLING
                    438:        if (hflag != FALSE) {                   /* Hard update?         */
1.3     ! millert   439:                for (i = 0; i < nrow - 1; ++i) {/* Compute hash data.   */
1.1       deraadt   440:                        hash(vscreen[i]);
                    441:                        hash(pscreen[i]);
                    442:                }
                    443:                offs = 0;                       /* Get top match.       */
1.3     ! millert   444:                while (offs != nrow - 1) {
1.1       deraadt   445:                        vp1 = vscreen[offs];
                    446:                        vp2 = pscreen[offs];
                    447:                        if (vp1->v_color != vp2->v_color
1.3     ! millert   448:                            || vp1->v_hash != vp2->v_hash)
1.1       deraadt   449:                                break;
                    450:                        uline(offs, vp1, vp2);
                    451:                        ucopy(vp1, vp2);
                    452:                        ++offs;
                    453:                }
1.3     ! millert   454:                if (offs == nrow - 1) {         /* Might get it all.    */
1.1       deraadt   455:                        ttmove(currow, curcol - lbound);
                    456:                        ttflush();
                    457:                        return;
                    458:                }
1.3     ! millert   459:                size = nrow - 1;                /* Get bottom match.    */
1.1       deraadt   460:                while (size != offs) {
1.3     ! millert   461:                        vp1 = vscreen[size - 1];
        !           462:                        vp2 = pscreen[size - 1];
1.1       deraadt   463:                        if (vp1->v_color != vp2->v_color
1.3     ! millert   464:                            || vp1->v_hash != vp2->v_hash)
1.1       deraadt   465:                                break;
1.3     ! millert   466:                        uline(size - 1, vp1, vp2);
1.1       deraadt   467:                        ucopy(vp1, vp2);
                    468:                        --size;
                    469:                }
                    470:                if ((size -= offs) == 0)        /* Get screen size.     */
                    471:                        panic("Illegal screen size in update");
                    472:                setscores(offs, size);          /* Do hard update.      */
                    473:                traceback(offs, size, size, size);
1.3     ! millert   474:                for (i = 0; i < size; ++i)
        !           475:                        ucopy(vscreen[offs + i], pscreen[offs + i]);
1.1       deraadt   476:                ttmove(currow, curcol - lbound);
                    477:                ttflush();
                    478:                return;
                    479:        }
                    480: #endif
1.3     ! millert   481:        for (i = 0; i < nrow - 1; ++i) {        /* Easy update.         */
1.1       deraadt   482:                vp1 = vscreen[i];
                    483:                vp2 = pscreen[i];
1.3     ! millert   484:                if ((vp1->v_flag & VFCHG) != 0) {
1.1       deraadt   485:                        uline(i, vp1, vp2);
                    486:                        ucopy(vp1, vp2);
                    487:                }
                    488:        }
                    489:        ttmove(currow, curcol - lbound);
                    490:        ttflush();
                    491: }
                    492:
                    493: /*
                    494:  * Update a saved copy of a line,
                    495:  * kept in a VIDEO structure. The "vvp" is
                    496:  * the one in the "vscreen". The "pvp" is the one
                    497:  * in the "pscreen". This is called to make the
                    498:  * virtual and physical screens the same when
                    499:  * display has done an update.
                    500:  */
                    501: VOID
1.3     ! millert   502: ucopy(vvp, pvp)
        !           503:        VIDEO *vvp;
        !           504:        VIDEO *pvp;
        !           505: {
1.1       deraadt   506:
1.3     ! millert   507:        vvp->v_flag &= ~VFCHG;          /* Changes done.         */
        !           508:        pvp->v_flag = vvp->v_flag;      /* Update model.         */
        !           509:        pvp->v_hash = vvp->v_hash;
        !           510:        pvp->v_cost = vvp->v_cost;
1.1       deraadt   511:        pvp->v_color = vvp->v_color;
                    512:        bcopy(vvp->v_text, pvp->v_text, ncol);
                    513: }
                    514:
1.3     ! millert   515: /*
        !           516:  * updext: update the extended line which the cursor is currently on at a
        !           517:  * column greater than the terminal width. The line will be scrolled right or
        !           518:  * left to let the user see where the cursor is
1.1       deraadt   519:  */
                    520: VOID
                    521: updext(currow, curcol)
1.3     ! millert   522:        int    currow, curcol;
1.1       deraadt   523: {
1.3     ! millert   524:        LINE  *lp;                      /* pointer to current line */
        !           525:        int    j;                       /* index into line */
1.1       deraadt   526:
1.3     ! millert   527:        /*
        !           528:         * calculate what column the left bound should be
        !           529:         * (force cursor into middle half of screen)
        !           530:         */
        !           531:        lbound = curcol - (curcol % (ncol >> 1)) - (ncol >> 2);
        !           532:        /*
        !           533:         * scan through the line outputing characters to the virtual screen
        !           534:         * once we reach the left edge
        !           535:         */
        !           536:        vtmove(currow, -lbound);                /* start scanning offscreen */
        !           537:        lp = curwp->w_dotp;                     /* line to output */
        !           538:        for (j = 0; j < llength(lp); ++j)       /* until the end-of-line */
        !           539:                vtpute(lgetc(lp, j));
        !           540:        vteeol();               /* truncate the virtual line */
        !           541:        vscreen[currow]->v_text[0] = '$';       /* and put a '$' in column 1 */
1.1       deraadt   542: }
                    543:
                    544: /*
                    545:  * Update a single line. This routine only
                    546:  * uses basic functionality (no insert and delete character,
                    547:  * but erase to end of line). The "vvp" points at the VIDEO
                    548:  * structure for the line on the virtual screen, and the "pvp"
                    549:  * is the same for the physical screen. Avoid erase to end of
                    550:  * line when updating CMODE color lines, because of the way that
                    551:  * reverse video works on most terminals.
                    552:  */
1.3     ! millert   553: VOID
        !           554: uline(row, vvp, pvp)
        !           555:        int             row;
        !           556:        VIDEO          *vvp;
        !           557:        VIDEO          *pvp;
        !           558: {
1.1       deraadt   559: #ifdef MEMMAP
1.3     ! millert   560:        putline(row + 1, 1, &vvp->v_text[0]);
1.1       deraadt   561: #else
1.3     ! millert   562:        char  *cp1;
        !           563:        char  *cp2;
        !           564:        char  *cp3;
        !           565:        char  *cp4;
        !           566:        char  *cp5;
        !           567:        int    nbflag;
1.1       deraadt   568:
1.3     ! millert   569:        if (vvp->v_color != pvp->v_color) {     /* Wrong color, do a     */
        !           570:                ttmove(row, 0);                 /* full redraw.          */
1.1       deraadt   571: #ifdef STANDOUT_GLITCH
1.2       millert   572:                if (pvp->v_color != CTEXT && magic_cookie_glitch >= 0)
                    573:                        tteeol();
1.1       deraadt   574: #endif
                    575:                ttcolor(vvp->v_color);
                    576: #ifdef STANDOUT_GLITCH
1.2       millert   577:                cp1 = &vvp->v_text[magic_cookie_glitch > 0 ? magic_cookie_glitch : 0];
1.3     ! millert   578:                /*
        !           579:                 * the odd code for magic_cookie_glitch==0 is to avoid
        !           580:                 * putting the invisable glitch character on the next line.
1.1       deraadt   581:                 * (Hazeltine executive 80 model 30)
                    582:                 */
1.3     ! millert   583:                cp2 = &vvp->v_text[ncol - (magic_cookie_glitch >= 0 ? (magic_cookie_glitch != 0 ? magic_cookie_glitch : 1) : 0)];
1.1       deraadt   584: #else
                    585:                cp1 = &vvp->v_text[0];
                    586:                cp2 = &vvp->v_text[ncol];
                    587: #endif
                    588:                while (cp1 != cp2) {
                    589:                        ttputc(*cp1++);
                    590:                        ++ttcol;
                    591:                }
                    592: #ifndef MOVE_STANDOUT
                    593:                ttcolor(CTEXT);
                    594: #endif
                    595:                return;
                    596:        }
1.3     ! millert   597:        cp1 = &vvp->v_text[0];  /* Compute left match.   */
1.1       deraadt   598:        cp2 = &pvp->v_text[0];
1.3     ! millert   599:        while (cp1 != &vvp->v_text[ncol] && cp1[0] == cp2[0]) {
1.1       deraadt   600:                ++cp1;
                    601:                ++cp2;
                    602:        }
1.3     ! millert   603:        if (cp1 == &vvp->v_text[ncol])  /* All equal.            */
1.1       deraadt   604:                return;
                    605:        nbflag = FALSE;
1.3     ! millert   606:        cp3 = &vvp->v_text[ncol];       /* Compute right match. */
1.1       deraadt   607:        cp4 = &pvp->v_text[ncol];
                    608:        while (cp3[-1] == cp4[-1]) {
                    609:                --cp3;
                    610:                --cp4;
1.3     ! millert   611:                if (cp3[0] != ' ')      /* Note non-blanks in    */
        !           612:                        nbflag = TRUE;  /* the right match.      */
1.1       deraadt   613:        }
1.3     ! millert   614:        cp5 = cp3;                      /* Is erase good?        */
        !           615:        if (nbflag == FALSE && vvp->v_color == CTEXT) {
        !           616:                while (cp5 != cp1 && cp5[-1] == ' ')
1.1       deraadt   617:                        --cp5;
                    618:                /* Alcyon hack */
1.3     ! millert   619:                if ((int) (cp3 - cp5) <= tceeol)
1.1       deraadt   620:                        cp5 = cp3;
                    621:        }
                    622:        /* Alcyon hack */
1.3     ! millert   623:        ttmove(row, (int) (cp1 - &vvp->v_text[0]));
1.1       deraadt   624: #ifdef STANDOUT_GLITCH
1.2       millert   625:        if (vvp->v_color != CTEXT && magic_cookie_glitch > 0) {
1.3     ! millert   626:                if (cp1 < &vvp->v_text[magic_cookie_glitch])
        !           627:                        cp1 = &vvp->v_text[magic_cookie_glitch];
        !           628:                if (cp5 > &vvp->v_text[ncol - magic_cookie_glitch])
        !           629:                        cp5 = &vvp->v_text[ncol - magic_cookie_glitch];
1.2       millert   630:        } else if (magic_cookie_glitch < 0)
1.1       deraadt   631: #endif
                    632:                ttcolor(vvp->v_color);
                    633:        while (cp1 != cp5) {
                    634:                ttputc(*cp1++);
                    635:                ++ttcol;
                    636:        }
1.3     ! millert   637:        if (cp5 != cp3)                 /* Do erase.             */
1.1       deraadt   638:                tteeol();
                    639: #endif
                    640: }
                    641:
                    642: /*
1.3     ! millert   643:  * Redisplay the mode line for the window pointed to by the "wp".
        !           644:  * This is the only routine that has any idea of how the modeline is
        !           645:  * formatted. You can change the modeline format by hacking at this
        !           646:  * routine. Called by "update" any time there is a dirty window.  Note
        !           647:  * that if STANDOUT_GLITCH is defined, first and last magic_cookie_glitch
        !           648:  * characters may never be seen.
        !           649:  */
        !           650: VOID
        !           651: modeline(wp)
        !           652:        MGWIN  *wp;
        !           653: {
        !           654:        int     n;
        !           655:        BUFFER *bp;
        !           656:        int     mode;
        !           657:
        !           658:        n = wp->w_toprow + wp->w_ntrows;        /* Location.             */
        !           659:        vscreen[n]->v_color = CMODE;            /* Mode line color.      */
        !           660:        vscreen[n]->v_flag |= (VFCHG | VFHBAD); /* Recompute, display.   */
        !           661:        vtmove(n, 0);                           /* Seek to right line.   */
1.1       deraadt   662:        bp = wp->w_bufp;
1.3     ! millert   663:        vtputc('-');
        !           664:        vtputc('-');
        !           665:        if ((bp->b_flag & BFCHG) != 0) {        /* "*" if changed.       */
        !           666:                vtputc('*');
        !           667:                vtputc('*');
1.1       deraadt   668:        } else {
1.3     ! millert   669:                vtputc('-');
        !           670:                vtputc('-');
1.1       deraadt   671:        }
                    672:        vtputc('-');
1.3     ! millert   673:        n = 5;
1.1       deraadt   674:        n += vtputs("Mg: ");
                    675:        if (bp->b_bname[0] != '\0')
                    676:                n += vtputs(&(bp->b_bname[0]));
1.3     ! millert   677:        while (n < 42) {                /* Pad out with blanks   */
1.1       deraadt   678:                vtputc(' ');
                    679:                ++n;
                    680:        }
                    681:        vtputc('(');
                    682:        ++n;
1.3     ! millert   683:        for (mode = 0;;) {
        !           684:                n += vtputs(bp->b_modes[mode]->p_name);
        !           685:                if (++mode > bp->b_nmodes)
        !           686:                        break;
        !           687:                vtputc('-');
        !           688:                ++n;
1.1       deraadt   689:        }
                    690:        vtputc(')');
                    691:        ++n;
1.3     ! millert   692:        while (n < ncol) {              /* Pad out.              */
1.1       deraadt   693:                vtputc('-');
                    694:                ++n;
                    695:        }
                    696: }
                    697: /*
                    698:  * output a string to the mode line, report how long it was.
                    699:  */
1.3     ! millert   700: int
        !           701: vtputs(s)
        !           702:        char  *s;
        !           703: {
        !           704:        int    n = 0;
1.1       deraadt   705:
                    706:        while (*s != '\0') {
                    707:                vtputc(*s++);
                    708:                ++n;
                    709:        }
                    710:        return n;
                    711: }
1.3     ! millert   712:
1.1       deraadt   713: #ifdef GOSLING
                    714: /*
1.3     ! millert   715:  * Compute the hash code for the line pointed to by the "vp".
        !           716:  * Recompute it if necessary. Also set the approximate redisplay
        !           717:  * cost. The validity of the hash code is marked by a flag bit.
        !           718:  * The cost understand the advantages of erase to end of line.
        !           719:  * Tuned for the VAX by Bob McNamara; better than it used to be on
1.1       deraadt   720:  * just about any machine.
                    721:  */
                    722: VOID
1.3     ! millert   723: hash(vp)
        !           724:        VIDEO *vp;
        !           725: {
        !           726:        int    i;
        !           727:        int    n;
        !           728:        char  *s;
        !           729:
        !           730:        if ((vp->v_flag & VFHBAD) != 0) {       /* Hash bad.             */
        !           731:                s = &vp->v_text[ncol - 1];
        !           732:                for (i = ncol; i != 0; --i, --s)
1.1       deraadt   733:                        if (*s != ' ')
                    734:                                break;
1.3     ! millert   735:                n = ncol - i;                   /* Erase cheaper?        */
1.1       deraadt   736:                if (n > tceeol)
                    737:                        n = tceeol;
1.3     ! millert   738:                vp->v_cost = i + n;             /* Bytes + blanks.       */
        !           739:                for (n = 0; i != 0; --i, --s)
        !           740:                        n = (n << 5) + n + *s;
        !           741:                vp->v_hash = n;                 /* Hash code.            */
        !           742:                vp->v_flag &= ~VFHBAD;          /* Flag as all done.     */
1.1       deraadt   743:        }
                    744: }
                    745:
                    746: /*
                    747:  * Compute the Insert-Delete
                    748:  * cost matrix. The dynamic programming algorithm
                    749:  * described by James Gosling is used. This code assumes
                    750:  * that the line above the echo line is the last line involved
                    751:  * in the scroll region. This is easy to arrange on the VT100
                    752:  * because of the scrolling region. The "offs" is the origin 0
                    753:  * offset of the first row in the virtual/physical screen that
                    754:  * is being updated; the "size" is the length of the chunk of
                    755:  * screen being updated. For a full screen update, use offs=0
                    756:  * and size=nrow-1.
                    757:  *
                    758:  * Older versions of this code implemented the score matrix by
                    759:  * a two dimensional array of SCORE nodes. This put all kinds of
                    760:  * multiply instructions in the code! This version is written to
                    761:  * use a linear array and pointers, and contains no multiplication
                    762:  * at all. The code has been carefully looked at on the VAX, with
                    763:  * only marginal checking on other machines for efficiency. In
                    764:  * fact, this has been tuned twice! Bob McNamara tuned it even
                    765:  * more for the VAX, which is a big issue for him because of
                    766:  * the 66 line X displays.
                    767:  *
                    768:  * On some machines, replacing the "for (i=1; i<=size; ++i)" with
                    769:  * i = 1; do { } while (++i <=size)" will make the code quite a
                    770:  * bit better; but it looks ugly.
                    771:  */
                    772: VOID
1.3     ! millert   773: setscores(offs, size)
        !           774:        int offs;
        !           775:        int size;
        !           776: {
        !           777:        SCORE *sp;
        !           778:        SCORE *sp1;
        !           779:        int    tempcost;
        !           780:        int    bestcost;
        !           781:        int    j;
        !           782:        int    i;
        !           783:        VIDEO **vp, **pp;
        !           784:        VIDEO **vbase, **pbase;
        !           785:
        !           786:        vbase = &vscreen[offs - 1];     /* By hand CSE's.        */
        !           787:        pbase = &pscreen[offs - 1];
        !           788:        score[0].s_itrace = 0;          /* [0, 0]                */
1.1       deraadt   789:        score[0].s_jtrace = 0;
1.3     ! millert   790:        score[0].s_cost = 0;
        !           791:        sp = &score[1];                 /* Row 0, inserts.       */
1.1       deraadt   792:        tempcost = 0;
                    793:        vp = &vbase[1];
1.3     ! millert   794:        for (j = 1; j <= size; ++j) {
1.1       deraadt   795:                sp->s_itrace = 0;
1.3     ! millert   796:                sp->s_jtrace = j - 1;
1.1       deraadt   797:                tempcost += tcinsl;
                    798:                tempcost += (*vp)->v_cost;
                    799:                sp->s_cost = tempcost;
                    800:                ++vp;
                    801:                ++sp;
                    802:        }
1.3     ! millert   803:        sp = &score[NROW];              /* Column 0, deletes.    */
1.1       deraadt   804:        tempcost = 0;
1.3     ! millert   805:        for (i = 1; i <= size; ++i) {
        !           806:                sp->s_itrace = i - 1;
1.1       deraadt   807:                sp->s_jtrace = 0;
1.3     ! millert   808:                tempcost += tcdell;
1.1       deraadt   809:                sp->s_cost = tempcost;
                    810:                sp += NROW;
                    811:        }
1.3     ! millert   812:        sp1 = &score[NROW + 1];         /* [1, 1].               */
1.1       deraadt   813:        pp = &pbase[1];
1.3     ! millert   814:        for (i = 1; i <= size; ++i) {
1.1       deraadt   815:                sp = sp1;
                    816:                vp = &vbase[1];
1.3     ! millert   817:                for (j = 1; j <= size; ++j) {
        !           818:                        sp->s_itrace = i - 1;
1.1       deraadt   819:                        sp->s_jtrace = j;
1.3     ! millert   820:                        bestcost = (sp - NROW)->s_cost;
        !           821:                        if (j != size)  /* Cd(A[i])=0 @ Dis.     */
1.1       deraadt   822:                                bestcost += tcdell;
1.3     ! millert   823:                        tempcost = (sp - 1)->s_cost;
1.1       deraadt   824:                        tempcost += (*vp)->v_cost;
1.3     ! millert   825:                        if (i != size)  /* Ci(B[j])=0 @ Dsj.     */
1.1       deraadt   826:                                tempcost += tcinsl;
                    827:                        if (tempcost < bestcost) {
                    828:                                sp->s_itrace = i;
1.3     ! millert   829:                                sp->s_jtrace = j - 1;
1.1       deraadt   830:                                bestcost = tempcost;
                    831:                        }
1.3     ! millert   832:                        tempcost = (sp - NROW - 1)->s_cost;
1.1       deraadt   833:                        if ((*pp)->v_color != (*vp)->v_color
1.3     ! millert   834:                            || (*pp)->v_hash != (*vp)->v_hash)
1.1       deraadt   835:                                tempcost += (*vp)->v_cost;
                    836:                        if (tempcost < bestcost) {
1.3     ! millert   837:                                sp->s_itrace = i - 1;
        !           838:                                sp->s_jtrace = j - 1;
1.1       deraadt   839:                                bestcost = tempcost;
                    840:                        }
                    841:                        sp->s_cost = bestcost;
1.3     ! millert   842:                        ++sp;           /* Next column.          */
1.1       deraadt   843:                        ++vp;
                    844:                }
                    845:                ++pp;
1.3     ! millert   846:                sp1 += NROW;            /* Next row.             */
1.1       deraadt   847:        }
                    848: }
                    849:
                    850: /*
                    851:  * Trace back through the dynamic programming cost
                    852:  * matrix, and update the screen using an optimal sequence
                    853:  * of redraws, insert lines, and delete lines. The "offs" is
                    854:  * the origin 0 offset of the chunk of the screen we are about to
                    855:  * update. The "i" and "j" are always started in the lower right
                    856:  * corner of the matrix, and imply the size of the screen.
                    857:  * A full screen traceback is called with offs=0 and i=j=nrow-1.
                    858:  * There is some do-it-yourself double subscripting here,
                    859:  * which is acceptable because this routine is much less compute
                    860:  * intensive then the code that builds the score matrix!
                    861:  */
1.3     ! millert   862: VOID
        !           863: traceback(offs, size, i, j)
        !           864:        int    offs;
        !           865:        int    size;
        !           866:        int    i;
        !           867:        int    j;
        !           868: {
        !           869:        int    itrace;
        !           870:        int    jtrace;
        !           871:        int    k;
        !           872:        int    ninsl;
        !           873:        int    ndraw;
        !           874:        int    ndell;
1.1       deraadt   875:
1.3     ! millert   876:        if (i == 0 && j == 0)   /* End of update.        */
1.1       deraadt   877:                return;
1.3     ! millert   878:        itrace = score[(NROW * i) + j].s_itrace;
        !           879:        jtrace = score[(NROW * i) + j].s_jtrace;
        !           880:        if (itrace == i) {      /* [i, j-1]              */
        !           881:                ninsl = 0;      /* Collect inserts.      */
1.1       deraadt   882:                if (i != size)
                    883:                        ninsl = 1;
                    884:                ndraw = 1;
1.3     ! millert   885:                while (itrace != 0 || jtrace != 0) {
        !           886:                        if (score[(NROW * itrace) + jtrace].s_itrace != itrace)
1.1       deraadt   887:                                break;
1.3     ! millert   888:                        jtrace = score[(NROW * itrace) + jtrace].s_jtrace;
1.1       deraadt   889:                        if (i != size)
                    890:                                ++ninsl;
                    891:                        ++ndraw;
                    892:                }
                    893:                traceback(offs, size, itrace, jtrace);
                    894:                if (ninsl != 0) {
                    895:                        ttcolor(CTEXT);
1.3     ! millert   896:                        ttinsl(offs + j - ninsl, offs + size - 1, ninsl);
1.1       deraadt   897:                }
1.3     ! millert   898:                do {            /* B[j], A[j] blank.     */
        !           899:                        k = offs + j - ndraw;
1.1       deraadt   900:                        uline(k, vscreen[k], &blanks);
                    901:                } while (--ndraw);
                    902:                return;
                    903:        }
1.3     ! millert   904:        if (jtrace == j) {      /* [i-1, j]              */
        !           905:                ndell = 0;      /* Collect deletes.      */
1.1       deraadt   906:                if (j != size)
                    907:                        ndell = 1;
1.3     ! millert   908:                while (itrace != 0 || jtrace != 0) {
        !           909:                        if (score[(NROW * itrace) + jtrace].s_jtrace != jtrace)
1.1       deraadt   910:                                break;
1.3     ! millert   911:                        itrace = score[(NROW * itrace) + jtrace].s_itrace;
1.1       deraadt   912:                        if (j != size)
                    913:                                ++ndell;
                    914:                }
                    915:                if (ndell != 0) {
                    916:                        ttcolor(CTEXT);
1.3     ! millert   917:                        ttdell(offs + i - ndell, offs + size - 1, ndell);
1.1       deraadt   918:                }
                    919:                traceback(offs, size, itrace, jtrace);
                    920:                return;
                    921:        }
                    922:        traceback(offs, size, itrace, jtrace);
1.3     ! millert   923:        k = offs + j - 1;
        !           924:        uline(k, vscreen[k], pscreen[offs + i - 1]);
1.1       deraadt   925: }
                    926: #endif