[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.1

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