/* Copyright (c) 1983 University of Maryland Computer Science Department */ /* Ultra-hot screen management package Original code copyright (c) James Gosling, January 1980 */ /* Severe munging and destruction by Chris Torek, 1982,1983 */ /**************************************************************** /-------------\ / \ / \ / \ | XXXX XXXX | | XXXX XXXX | | XXX XXX | \ X / --\ XXX /-- | | XXX | | | | | | | I I I I I I I | | I I I I I I | \ / -- -- \-------/ XXX XXX XXXXX XXXXX XXXXXXXXX XXXXXXXXXX XXXXX XXXXX XXXXXXX XXXXX XXXXX XXXXXXXXX XXXXXXXXXX XXXXX XXXXX XXX XXX ************** * BEWARE!! * ************** All ye who enter here: Most of the code in this module is twisted beyond belief! Tread carefully. If you think you understand it, You Don't, So Look Again. ****************************************************************/ /* DJH -- Added Ding() for bell */ #include "win.h" #include "Trm.h" #include #include #ifdef lint #undef VAX /* Don't let lint know about Vax dependent stuff */ #endif /* the following macros are used to access terminal specific routines. Really, no one outside of display.c should be using them, except for the initialize/cleanup routines */ #define topos (*W_tt.t_topos) #define reset (*W_tt.t_reset) #define INSmode (*W_tt.t_INSmode) #define insertlines (*W_tt.t_inslines) #define deletelines (*W_tt.t_dellines) #define blanks (*W_tt.t_blanks) #define wipeline (*W_tt.t_wipeline) #define wipescreen (*W_tt.t_wipescreen) #define deletechars (*W_tt.t_delchars) #define ScreenWidth (W_tt.t_width) #define ScreenLength (W_tt.t_length) #define MScreenWidth 135 #define MScreenLength 60 #define min(a,b) (ab ? a : b) #define hidden static #define visible #define procedure #define function hidden struct line { /* a line as it appears in a list of lines (as in the physical and virtual display lists) */ int hash; /* hash value for this line, 0 if not known */ struct line *next; /* pointer to the next line in a list of lines */ short DrawCost; /* the cost of redrawing this line */ short length; /* the number of valid characters in the line */ short touched; /* true iff UpdateLine should be done */ Ch body[MScreenWidth]; /* the actual text of the line */ } *FreeLines; /* free space list */ hidden WindowSize; /* the number of lines on which line ID operations should be done */ hidden Ch NullStr[MScreenWidth];/* type Ch equivalent of line of blanks */ int baud_rate; /* Terminal speed, so we can calculate the number of characters required to make the cursor sit still for n secs. */ hidden CheckForInput; /* -ve iff UpdateLine should bother checking for input */ hidden char OneLineBuf[MScreenWidth];/* For use by dumpstring and UpdateEasyLine */ /* 'newline' returns a pointer to a new line object, either from the free list or from the general unix pool */ hidden struct line *newline () { register struct line *p = FreeLines; register Ch *c; if (p) { FreeLines = p -> next; #ifdef DEBUG if (p -> hash != 12345) { /* register FILE *f = fopen ("EMACS_TRACE", "w"); topos (23, 1); printf ("*****Bogus value in display free list"); */ FreeLines = 0; /* if (f) { register int *p1 = ((int *) p) - 10; register char *p2 = (char *) p1; register i; fprintf (f, "Bogus value in display free list at %o\n", p); for (i=0; i<25; i++) { fprintf (f, "%11o: %011o %9d %03o %03o %03o %03o\n", p1, *p1, *p1, p2[0], p2[1], p2[2], p2[3]); p1++; p2 += 4; } fclose (f); } */ return newline (); } #endif } else { static Leakage; p = (struct line *) malloc (sizeof *p); if (++Leakage>(2*MScreenLength)) printf ("*****Display core leakage!"); } p -> length = 0; p -> hash = 0; p -> touched = 1; for (c = &p -> body[ScreenWidth]; c > p -> body;) (--c) -> ch_all = ' '; return p; } /* 'ReleaseLine' returns a line object to the free list */ hidden procedure ReleaseLine (p) register struct line *p; { if (p) { if (p -> hash == 12345) { printf("\rBogus re-release!"); fflush(stdout); /* abort(); */ return; } p -> next = FreeLines; p -> hash = 12345; FreeLines = p; } } hidden struct line *PhysScreen[MScreenLength + 1]; /* the current (physical) screen */ hidden struct line *DesiredScreen[MScreenLength + 1]; /* the desired (virtual) screen */ visible int ScreenGarbaged, /* set to 1 iff screen content is uncertain. */ InputPending, /* true iff input is known to be pending */ LastRedisplayPaused,/* true iff last redisplay paused */ #ifdef DEBUG RDdebug, /* line redraw debug switch */ IDdebug, /* line insertion/deletion debug */ #endif DEBUG WDCurrentLine, /* current line for writing to the virtual screen. */ WDleft; /* number of columns left on the current line of the virtual screen. */ visible Ch *WDcursor; /* pointer into a line object, indicates where to put the next character */ /* 'WDCharAt' returns a pointer to the Ch at position (row,col) in the virtual screen. This is purely for the grotesque attributes in HP264?s where one must know what attribute is desired after the end of a string. */ visible Ch *WDCharAt (row, col) { register struct line *p; if ((p = DesiredScreen[row]) == 0 || p -> length < col) return &NullStr[0]; /* blank */ else return &p -> body[col - 1]; } /* 'WDsetpos' positions the cursor at position (row,col) in the virtual screen */ visible procedure WDsetpos (row, col) register row, col; { register struct line *p; register n; if (WDCurrentLine >= 0 && (p = DesiredScreen[WDCurrentLine]) -> length <= (n = ScreenWidth - WDleft)) p -> length = WDleft > 0 ? n : ScreenWidth; if (!DesiredScreen[row]) DesiredScreen[row] = newline (); (p = DesiredScreen[row]) -> hash = 0; p -> touched = 1; WDcursor = &p -> body[col - 1]; WDCurrentLine = row; WDleft = ScreenWidth + 1 - col; } /* 'WDclearline' positions the cursor at the beginning of the indicated line and clears the line (in the image) */ visible procedure WDclearline (row) { register Ch *c; register struct line *p; WDsetpos (row, 1); (p = DesiredScreen[row]) -> length = 0; for (c = &p -> body[ScreenWidth]; c > p -> body;) (--c) -> ch_all = ' '; } /* 'hashline' computes a hash value for a line, unless the hash value is already known. This hash code has a few important properties: - it is independant of the number of leading and trailing spaces - it will never be zero As a side effect, an estimate of the cost of redrawing the line is calculated */ hidden procedure hashline (p) register struct line *p; { register Ch *c, *l; register h; if (!p || p -> hash) { if (p && p->hash==12345) printf ("****Free line in screen"); return; } h = 0; c = p -> body; l = &p -> body[p -> length]; while (--l > c && l -> ch_all == ' '); while (c <= l && c -> ch_all == ' ') c++; p -> DrawCost = l - c + 1; while (c <= l) h = (h << 5) + h + c++ -> ch_all; p -> hash = h!=12345 && h ? h : 1; } /* 1 2 3 4 .... Each Mij represents the minumum cost of +---+---+---+---+----- rearranging the first i lines to map onto 1 | | | | | the first j lines (the j direction +---+---+---+---+----- represents the desired contents of a line, 2 | | \| ^ | | i the current contents). The algorithm +---+---\-|-+---+----- used is a dynamic programming one, where 3 | | <-+Mij| | M[i,j] = min( M[i-1,j], +---+---+---+---+----- M[i,j-1]+redraw cost for j,2 4 | | | | | M[i-1,j-1]+the cost of +---+---+---+---+----- converting line i to line j); . | | | | | Line i can be converted to line j by either . just drawing j, or if they match, by moving . line i to line j (with insert/delete line) */ hidden struct Msquare { short cost; /* the value of Mij */ char fromi, fromj; /* the coordinates of the square that the optimal move comes from */ } M[MScreenLength + 1][MScreenLength + 1]; hidden procedure calcM () { register struct Msquare *p; register i, j, movecost, cost; int reDrawCost, idcost, leftcost; double fidcost; cost = 0; movecost = 0; for (i = 0; i <= ScreenLength; i++) { p = &M[i][0]; /* M[i][i].cost = 0; */ p[i].cost = 0; M[0][i].cost = cost + movecost; /* M[i][0].cost = movecost; */ p[0].cost = movecost; M[0][i].fromi = 0; /* M[0][i].fromj = M[i][i].fromj = i - 1; */ M[0][i].fromj = p[i].fromj = i - 1; /* M[i][0].fromi = M[i][i].fromi = i - 1; */ p[0].fromi = p[i].fromi = i - 1; /* M[i][0].fromj = 0; */ p[0].fromj = 0; movecost += W_tt.t_ILmf * (ScreenLength - i) + W_tt.t_ILov; if (DesiredScreen[i + 1]) cost += DesiredScreen[i + 1] -> DrawCost; } fidcost = W_tt.t_ILmf * (WindowSize + 1) + W_tt.t_ILov; for (i = 1; i <= WindowSize; i++) { p = &M[i][0]; fidcost -= W_tt.t_ILmf; idcost = fidcost; for (j = 1; j <= WindowSize; j++) { p++; /* p = &M[i][j]; */ cost = DesiredScreen[j] ? DesiredScreen[j] -> DrawCost : 0; reDrawCost = cost; if (PhysScreen[i] && DesiredScreen[j] && PhysScreen[i] -> hash == DesiredScreen[j] -> hash) cost = 0; /* idcost = W_tt.t_ILmf * (WindowSize - i + 1) + W_tt.t_ILov; */ /* movecost = M[i - 1][j].cost + (j == WindowSize ? 0 : idcost); */ movecost = p[-MScreenLength-1].cost + (j == WindowSize ? 0 : idcost); p -> fromi = i - 1; /* now using movecost for */ p -> fromj = j; /* the minumum cost. */ if (( /* leftcost = M[i][j - 1].cost */ leftcost = p[-1].cost + (i == WindowSize ? 0 : idcost) + reDrawCost ) < movecost) { movecost = leftcost; p -> fromi = i; p -> fromj = j - 1; } /* cost += M[i - 1][j - 1].cost; */ cost += p[-MScreenLength-2].cost; if (cost < movecost) movecost = cost, p -> fromi = i - 1, p -> fromj = j - 1; p -> cost = movecost; } } } /* calculate and perform the optimal sequence of insertions/deltions given the matrix M from routine calcM */ hidden procedure CalcID (i, j, InsertsDesired) register i, j; { register ni, nj; register struct Msquare *p = &M[i][j]; if (i > 0 || j > 0) { ni = p -> fromi; nj = p -> fromj; if (ni == i) { CalcID (ni, nj, i != WindowSize ? InsertsDesired + 1 : 0); InsertsDesired = 0; if (InputPending) { if (PhysScreen[j] != DesiredScreen[j]) ReleaseLine (PhysScreen[j]); PhysScreen[j] = 0; ReleaseLine (DesiredScreen[j]); DesiredScreen[j] = 0; LastRedisplayPaused++; } else { UpdateLine ((struct line *) 0, DesiredScreen[j], j); if (PhysScreen[j] != DesiredScreen[j]) ReleaseLine (PhysScreen[j]); PhysScreen[j] = DesiredScreen[j]; DesiredScreen[j] = 0; } } else if (nj == j) { if (j != WindowSize) { register nni, dlc = 1; for (; ni;) { p = &M[ni][nj]; nni = p -> fromi; if (p -> fromj == nj) { dlc++; ni = nni; } else break; } topos (i - dlc + 1, 1); deletelines (dlc); } CalcID (ni, nj, 0); } else { register struct line *old = PhysScreen[i]; #ifdef DOEARLY register DoneEarly = 0; #endif if (old == DesiredScreen[i]) DesiredScreen[i] = 0; PhysScreen[i] = 0; #ifdef DOEARLY /* The following hack and all following lines involving the variable "DoneEarly" cause the bottom line of the screen to be redisplayed before any others if it has changed and it would be redrawn in-place. This is purely for Emacs, people using this package for other things might want to lobotomize this section. */ if (i == ScreenLength && j == ScreenLength /* && old != PhysScreen[j]) { */ && DesiredScreen[j]) { DoneEarly++; UpdateLine (old, DesiredScreen[j], j); } #endif CalcID (ni, nj, 0); if (InputPending #ifdef DOEARLY && !DoneEarly #endif ) { if (PhysScreen[j] != old) ReleaseLine (PhysScreen[j]); if (DesiredScreen[j] != old && DesiredScreen[j] != PhysScreen[j]) ReleaseLine (DesiredScreen[j]); PhysScreen[j] = old; DesiredScreen[j] = 0; LastRedisplayPaused++; } else { if ( #ifdef DOEARLY !DoneEarly && #endif (DesiredScreen[j] || i != j)) UpdateLine (old, DesiredScreen[j], j); if (PhysScreen[j] != DesiredScreen[j]) ReleaseLine (PhysScreen[j]); if (old != DesiredScreen[j] && old != PhysScreen[j]) ReleaseLine (old); PhysScreen[j] = DesiredScreen[j]; DesiredScreen[j] = 0; } } } if (InsertsDesired) { topos (j + 1, 1); insertlines (InsertsDesired); } } /* modify current screen line 'old' to match desired line 'new', the old line is at position ln. Each line is scanned and partitioned into 4 regions: <----m1-----><-od--><----m2-----> old: " Twas brillig and the slithy toves" new: " Twas brillig where a slithy toves" <-nsp--><----m1-----><-nd--><----m2-----> nsp, osp - number of leading spaces on each line m1 - length of a leading matching sequence m2 - length of a trailing matching sequence nd, od - length of the differing sequences */ hidden procedure UpdateLine (old, new, ln) register struct line *old, *new; { register Ch *op, *np, *ol, *nl; Ch *Iop, *Inp; /* for saving initial values */ int osp, nsp, m1, m2, od, nd, t, OldLineWipeTo, rv = 1; if (old == new) return 0; /* did nothing */ if (old) { op = old -> body; ol = &old -> body[OldLineWipeTo = old -> length]; } else op = NullStr, ol = op, OldLineWipeTo = 1; if (new) { np = new -> body; nl = &new -> body[new -> length]; } else np = NullStr, nl = np; /* ACT 11-Nov-1982 Do cheap update if obvious that fanciness goes nowhere */ if (!W_tt.t_needspaces && np != NullStr && op == NullStr) { UpdateEasyLine (ln, np, nl); goto cleanup; } Inp = np, Iop = op; osp = 0, nsp = 0, m1 = 0, m2 = 0; /* calculate the magic parameters */ while ((--ol) -> ch_all == ' ' && ol >= op) --OldLineWipeTo; while ((--nl) -> ch_all == ' ' && nl >= np) --new -> length; while (op -> ch_all == ' ' && op <= ol) op++, osp++; while (np -> ch_all == ' ' && np <= nl) np++, nsp++; if (ol < op && !W_tt.t_needspaces) osp = nsp; while (op -> ch_all == np -> ch_all && op <= ol && np <= nl) op++, np++, m1++; while (ol -> ch_all == nl -> ch_all && op <= ol && np <= nl) ol--, nl--, m2++; od = ol - op + 1; nd = nl - np + 1; /* forget matches which would be expensive to capitalize on */ if (m1 || m2) { register int c0, c1, c2, c3; c0 = nsp + m1 + m2; if (c1 = nsp - osp) c1 = c1<0 ? W_tt.t_DCov - c1*W_tt.t_DCmf : W_tt.t_ICov + c1*W_tt.t_ICmf; if (c3 = nd - od) c3 = c3<0 ? W_tt.t_DCov - c3*W_tt.t_DCmf : W_tt.t_ICov + c3*W_tt.t_ICmf; if (c2 = (nsp + nd) - (osp + od)) c2 = c2<0 ? W_tt.t_DCov - c2*W_tt.t_DCmf : W_tt.t_ICov + c2*W_tt.t_ICmf; c3 += c1; c1 += m2; c2 += m1; if (m2 && (c0 < c2 && c0 < c3 || c1 < c2 && c1 < c3)) { nd += m2; od += m2; ol += m2; nl += m2; m2 = 0; } if (m1 && (c0 < c1 && c0 < c3 || c2 < c1 && c2 < c3)) { nd += m1; od += m1; np -= m1; op -= m1; m1 = 0; } } #ifdef DEBUG if (RDdebug && (m1 || m2 || nd || od)) { fprintf (stderr,"%2d nsp=%2d osp=%2d m1=%2d nd=%2d od=%2d m2=%2d\n", ln, nsp, osp, m1, nd, od, m2); } #endif if (m1 == 0) if (m2 == 0) { if (od == 0 && nd == 0) { rv = 0; /* Jackpot! */ goto cleanup; } INSmode (0); if (W_tt.t_needspaces) { if (nsp > osp) { topos (ln, min (nsp, osp) + 1); (*W_tt.t_modes) (0); blanks (nsp - osp); } dumpstring (np, nl); } else dumps2 (Inp, nl, Iop, ln, 0); if (nsp + nd < osp + od) { topos (ln, nsp + nd + 1); wipeline (0, OldLineWipeTo); } } else { /* m1==0 && m2!=0 && (nd!=0 || od!=0) */ t = (nsp + nd) - (osp + od); topos (ln, min (nsp, osp) + 1); if (nsp > osp) np -= nsp - osp; if (t >= 0) { if (nl - t >= np) { INSmode (0); if (W_tt.t_needspaces) dumpstring (np, nl - t); else dumps2 (Inp, nl - t, Iop, ln, np - Inp); if (t > 0) topos (ln, nl - t - Inp + 1); } if (t > 0) INSmode (1), dumpstring (nl - t + 1, nl); } else { INSmode (0); if (W_tt.t_needspaces) dumpstring (np, nl); else dumps2 (Inp, nl, Iop, ln, np - Inp); topos (ln, nsp + nd + 1); deletechars (-t); } } else { /* m1!=0 */ register lsp = osp; if (nsp < osp) { topos (ln, 1); deletechars (osp - nsp); lsp = nsp; } if (m2 == 0) { if (nd == 0 && od == 0) { if (nsp > osp) { topos (ln, 1); INSmode (1); (*W_tt.t_modes) (0); blanks (nsp - osp); } goto cleanup; } #ifndef notdef if (od == 0 && !W_tt.t_needspaces) while (np -> ch_all == ' ' && np <= nl) np++, m1++; #endif topos (ln, lsp + m1 + 1); INSmode (0); if (nsp != osp || W_tt.t_needspaces) dumpstring (np, nl); else dumps2 (Inp, nl, Iop, ln, np - Inp); if (nd < od) { topos (ln, lsp + m1 + nd + 1); wipeline (0, OldLineWipeTo); } if (nsp > osp) { topos (ln, 1); INSmode (1); (*W_tt.t_modes) (0); blanks (nsp - osp); } } else { /* m1!=0 && m2!=0 && (nd!=0 || od!=0) */ topos (ln, lsp + m1 + 1); t = nd - od; if (nd > 0 && od > 0) { INSmode (0); if (nsp == osp && !W_tt.t_needspaces) { dumps2 (Inp, np + min (nd, od) - 1, Iop, ln, np - Inp); if (nd != od) topos (ln, lsp + m1 + min (nd, od) + 1); } else dumpstring (np, np + min (nd, od) - 1); } if (nd < od) deletechars (od - nd); else if (nd > od) INSmode (1), dumpstring (np + od, nl); if (nsp > osp) { topos (ln, 1); INSmode (1); (*W_tt.t_modes) (0); blanks (nsp - osp); } } } cleanup:; #ifdef FIONREAD if(--CheckForInput<0 && !InputPending && ((stdout->_ptr - stdout->_base) > 20)){ fflush (stdout); #ifdef TIOCOUTQ /* prevent system I/O buffering */ if (baud_rate < 2400) { int out1; float outtime; if (ioctl (fileno(stdin), TIOCOUTQ, &out1)) out1 = 0; out1 *= 10; outtime = ((float) out1) / ((float) baud_rate); if (outtime >= 1.5) sleep ((unsigned) (outtime - .5)); } #endif ioctl (fileno(stdin), FIONREAD, &InputPending); CheckForInput = baud_rate / 2400; } #endif return rv; } /* Update a line that used to be completely blank */ hidden procedure UpdateEasyLine (ln, st, en) register Ch *st, *en; { register char *p; register mode; Ch *xstart = st, *ostart; INSmode (0); while (st < en) { if (st -> ch_all == ' ' && (st+1) < en && (st+1) -> ch_all == ' ') { while (st < en && st -> ch_all == ' ') st++; continue; } ostart = st; mode = st -> Mode; p = OneLineBuf; while (st < en && st -> Mode == mode) { if (st -> ch_all == ' ' && (st+2) < en && (st+1) -> ch_all == ' ' && (st+2) -> ch_all == ' ') break; *p++ = st++ -> Char; } topos (ln, ostart-xstart+1); (*W_tt.t_modes) (mode); (*W_tt.t_writechars) (OneLineBuf, p - 1); } } visible procedure WDUpdateScreen (SlowUpdate, NoInputCheck) { register n, /* NOTE: n MUST be first register! */ c; CheckForInput = 9999; if (ScreenGarbaged) { reset (); ScreenGarbaged = 0; SlowUpdate = 0; for (n = 0; n <= ScreenLength; n++) { ReleaseLine (PhysScreen[n]); PhysScreen[n] = 0; } } #ifdef FIONREAD /* one quick test */ if (!NoInputCheck && !InputPending) ioctl (fileno(stdin), FIONREAD, &InputPending); #endif if (WDCurrentLine >= 0 && DesiredScreen[WDCurrentLine] -> length <= ScreenWidth - WDleft) DesiredScreen[WDCurrentLine] -> length = WDleft > 0 ? ScreenWidth - WDleft : ScreenWidth; WDCurrentLine = -1; if (W_tt.t_ILov == MissingFeature) SlowUpdate = 0; if (SlowUpdate) { for (n = 1; n <= ScreenLength; n++) { /* if (DesiredScreen[n] == 0)/* Fortunately for my current hacking, /* this is never true. ACT 24-Mar-83 */ /* DesiredScreen[n] = PhysScreen[n]; /* else */ hashline (DesiredScreen[n]); hashline (PhysScreen[n]); } c = 0; for (n = ScreenLength; n >= 1 && c <= 2; n--) if (PhysScreen[n] != DesiredScreen[n] && PhysScreen[n] && DesiredScreen[n] -> hash != PhysScreen[n] -> hash) c++; if (c <= 2) SlowUpdate = 0; else { if (W_tt.t_window) { for (n = ScreenLength; n >= 1 && (PhysScreen[n] == DesiredScreen[n] || PhysScreen[n] && DesiredScreen[n] -> hash == PhysScreen[n] -> hash); n--); WindowSize = n; (*W_tt.t_window) (n); } else WindowSize = ScreenLength; calcM (); CheckForInput = NoInputCheck ? 9999 : baud_rate / 2400; CalcID (ScreenLength, ScreenLength, 0); /* for (n = 1; n <= ScreenLength; n++) { if (DesiredScreen[n] != PhysScreen[n]) { ReleaseLine (PhysScreen[n]); PhysScreen[n] = DesiredScreen[n]; } DesiredScreen[n] = 0; } */ } } if (!SlowUpdate) { /* fast update */ for (n = 1; n <= ScreenLength; n++) if (DesiredScreen[n] && DesiredScreen[n] -> touched) { if (UpdateLine (PhysScreen[n], DesiredScreen[n], n)) { /* if (PhysScreen[n] != DesiredScreen[n]) */ ReleaseLine (PhysScreen[n]); PhysScreen[n] = DesiredScreen[n]; DesiredScreen[n] = 0; } } } if (WSetRealCursor && !InputPending) topos (WRCurRow + 1, WRCurCol + 1); if (W_tt.t_donerefresh) (*W_tt.t_donerefresh) (); for (n = 1; n <= ScreenLength; n++) { if (PhysScreen[n] != 0 && DesiredScreen[n] == 0) { DesiredScreen[n] = newline (); #ifdef VAX /* This bit of trickery helps a LOT. */ asm ("movl _PhysScreen[r11],r1"); /*r1=from, r0=to*/ asm ("clrw 12(r0)"); /*r0->touched=0*/ asm ("movw 10(r1),10(r0)"); /*r0->length=r1->length*/ asm ("cvtwl 10(r1),r2"); /*r2=2*r1->length*/ asm ("addl2 r2,r2"); asm ("movc3 r2,14(r1),14(r0)"); /*bcopy(r1->body,r0->body,r2)*/ #else CopyLine (PhysScreen[n], DesiredScreen[n]); #endif } } } #ifndef VAX hidden procedure CopyLine (from, to) register struct line *from, *to; { register Ch *cp = from -> body, *tp = to -> body; register n = from -> length; to -> touched = 0; to -> length = from -> length; while (--n>=0) *tp++ = *cp++; } #endif visible int VisibleBell; /* If true and the terminal will support it then the screen will flash instead of feeping when an error occurs */ visible int InverseVideo; /* If true and the terminal will support it then we will use inverse video */ /* DJH common routine for a feep */ Ding () { /* BOGUS! this should really be terminal type specific! */ if (VisibleBell && W_tt.t_flash) (*W_tt.t_flash) (); else putchar (07); fflush (stdout); /* 23 May 1983 ACT */ } /* initialize the teminal package */ WDterm_init () { static short baud_convert[] = { 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200 }; int rv = 0; /* Return value: 0 = OK */ struct sgttyb sg; extern short ospeed; extern WTtyFd; /* For gttying on the terminal */ static BeenHere; /* true iff we've been here before (some things must only be done once!) */ #ifdef DEBUG RDdebug = 0; /* line redraw debug switch */ IDdebug = 0; /* line insertion/deletion debug */ #endif DEBUG WDCurrentLine = -1; /* current line for writing to the virtual screen. */ WDleft = -1; /* number of columns left on the current line of the virtual screen. */ gtty (WTtyFd, &sg); ospeed = sg.sg_ospeed; baud_rate = sg.sg_ospeed == 0 ? 1200 : sg.sg_ospeed < sizeof baud_convert / sizeof baud_convert[0] ? baud_convert[sg.sg_ospeed] : 9600; if (!BeenHere) { char *tname = (char *) getenv ("TERM"); struct termtype { char *name; int cmplen; int (*startup) (); }; /* A terminal driver is selected by looking up the value of the environment variable TERM in the following table. The string is matched against the name, considering at most "cmplen" characters to be significant. "startup" points to the function that sets up the terminal driver. The driver is called with the terminal type as a parameter and is free to use that to specialize itself. */ /* NOTE: The driver should return 0 if the terminal is useable. For now, only the TrmTERM driver does so. */ struct termtype *p; extern TrmTEK4025 (); extern TrmAmb (); /* extern TrmC100 (); */ /* extern TrmI400 (); */ /* extern TrmMiniB (); */ /* extern TrmPERQ (); */ extern TrmVT100 (); extern TrmBitG (); /* extern TrmGT40 (); */ /* extern TrmGigi (); */ static struct termtype termtable[] = { "4025", 99, TrmTEK4025, "aaa", 99, TrmAmb, "amb", 99, TrmAmb, "ambassador",99, TrmAmb, "BG", 99, TrmBitG, "Bit", 3, TrmBitG, /* "C10", 3, TrmC100, */ /* "c10", 3, TrmC100, */ /* "Concept", 7, TrmC100, */ /* "concept", 7, TrmC100, */ /* "d4", 99, TrmGT40, */ "D5", 99, TrmVT100, "Dq", 2, TrmVT100, "DT80", 99, TrmVT100, /* "GG", 99, TrmGigi, */ /* "Gigi", 4, TrmGigi, */ /* "gt40", 99, TrmGT40, */ /* "GT40", 99, TrmGT40, */ /* "perq", 4, TrmC100, */ /* "i400", 99, TrmI400, */ "Mb", 99, TrmAmb, /* "minibee", 99, TrmMiniB, */ "tek4025", 99, TrmTEK4025, "VT1", 3, TrmVT100, "vt1", 3, TrmVT100, "X5", 99, TrmTEK4025, 0, 0, 0 }; BeenHere++; if (tname == 0) tname = "sd"; { /* Initialize NullStr */ register Ch *p; for (p = NullStr; p < &NullStr[MScreenWidth]; ) p++ -> ch_all = ' '; } W_tt.t_frames[0] = '+', W_tt.t_frames[2] = '+'; W_tt.t_frames[5] = '+', W_tt.t_frames[7] = '+'; W_tt.t_frames[1] = '-', W_tt.t_frames[6] = '-'; W_tt.t_frames[3] = '|', W_tt.t_frames[4] = '|'; for (p = termtable; p -> name; p++) if (strcmpn (p -> name, tname, p -> cmplen) == 0) { rv = (*p -> startup) (tname); break; } if (p -> name == 0) rv = TrmTERM (tname); if (rv) return rv; } rv = (*W_tt.t_init) (baud_rate); if (rv) return rv; if (W_tt.t_length > MScreenLength) W_tt.t_length = MScreenLength; if (W_tt.t_width > MScreenWidth) W_tt.t_width = MScreenWidth; (*W_tt.t_reset) (); return 0; } /* Debugging routines -- called from sdb only */ /* print out the insert/delete cost matrix */ #ifdef DEBUG PrintM () { register i, j; register struct Msquare *p; for (i = 0; i <= ScreenLength; i++) { for (j = 0; j <= ScreenLength; j++) { p = &M[i][j]; fprintf (stderr, "%4d%c", p -> cost, p -> fromi < i && p -> fromj < j ? '\\' : p -> fromi < i ? '^' : p -> fromj < j ? '<' : ' '); } fprintf (stderr, "\n"); } fprintf (stderr, "\014"); } #endif visible procedure NoOperation () {} hidden procedure dumpstring (start, end) register Ch *start, *end; { register char *p; register mode; do { mode = start -> Mode; p = OneLineBuf; while (start <= end && start -> Mode == mode) *p++ = start++ -> Char; (*W_tt.t_modes) (mode); (*W_tt.t_writechars) (OneLineBuf, p - 1); } while (start <= end); } /* Update a line that hasn't shifted left or right -- can compare char by char and skip over equal chunks */ /* NOTE: We have carefully guaranteed that whenever st<=en, os<=(the end of the line that os pointed to) and that all "extra" chars in a line (ie past the "end") are (type Ch) blanks */ hidden procedure dumps2 (st, en, os, ln, skip) register Ch *st, *en, *os; { register char *p; register mode; Ch *xstart = st, *ostart; st += skip; os += skip; while (st <= en) { if (st -> ch_all == os -> ch_all && st+1 <= en && (st+1)->ch_all == (os+1)->ch_all) { while (st <= en && st -> ch_all == os -> ch_all) st++, os++; continue; } ostart = st; mode = st -> Mode; p = OneLineBuf; while (st <= en && st -> Mode == mode) { if (st->ch_all == os->ch_all && st+2 <= en && (st+1)->ch_all == (os+1)->ch_all && (st+2)->ch_all == (os+2)->ch_all) break; *p++ = st++ -> Char; os++; } topos (ln, ostart-xstart+1); (*W_tt.t_modes) (mode); (*W_tt.t_writechars) (OneLineBuf, p - 1); } }