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