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