home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin.
- * Not derived from licensed software.
- *
- * Permission is granted to freely use, copy, modify, and redistribute
- * this software, provided that no attempt is made to gain profit from it,
- * the author is not construed to be liable for any results of using the
- * software, alterations are clearly marked as such, and this notice is
- * not modified.
- */
-
- char AnsiVersion[] = "ansi 2.0a 19-Oct-88";
-
- #include <stdio.h>
- #include <sys/types.h>
- #include "screen.h"
-
- #define A_SO 0x1 /* Standout mode */
- #define A_US 0x2 /* Underscore mode */
- #define A_BL 0x4 /* Blinking */
- #define A_BD 0x8 /* Bold mode */
- #define A_DI 0x10 /* Dim mode */
- #define A_RV 0x20 /* Reverse mode */
- #define A_MAX 0x20
-
- /* Types of movement used by Goto() */
- enum move_t {
- M_NONE,
- M_UP,
- M_DO,
- M_LE,
- M_RI,
- M_RW,
- M_CR,
- };
-
- #define EXPENSIVE 1000
-
- #define G0 0
- #define G1 1
- #define G2 2
- #define G3 3
-
- #define ASCII 0
-
- extern char *getenv(), *tgetstr(), *tgoto(), *malloc();
-
- int rows, cols;
- int status;
- int flowctl;
- char Term[] = "TERM=screen";
- char Termcap[1024];
- char *blank;
- char PC;
- int ISO2022;
- time_t TimeDisplayed;
-
- static char tbuf[1024], tentry[1024];
- static char *tp = tentry;
- static char *TI, *TE, *BL, *VB, *BC, *CR, *NL, *CL, *IS, *CM;
- static char *US, *UE, *SO, *SE, *CE, *CD, *DO, *SR, *SF, *AL;
- static char *CS, *DL, *DC, *IC, *IM, *EI, *UP, *ND, *KS, *KE;
- static char *MB, *MD, *MH, *MR, *ME, *PO, *PF;
- static char *CDC, *CDL, *CAL;
- static AM;
- static char GlobalAttr, TmpAttr, GlobalCharset, TmpCharset;
- static char *OldImage, *OldAttr, *OldFont;
- static last_x, last_y;
- static struct win *curr;
- static display = 1;
- static StrCost;
- static UPcost, DOcost, LEcost, NDcost, CRcost, IMcost, EIcost;
- static tcLineLen = 100;
- static char *null;
- static StatLen;
- static insert;
- static keypad;
-
- static char *KeyCaps[] = {
- "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9",
- "kb", "kd", "kh", "kl", "ko", "kr", "ku",
- 0
- };
-
- static char TermcapConst[] = "TERMCAP=\
- SC|screen|VT 100/ANSI X3.64 virtual terminal|\\\n\
- \t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\
- \t:cd=\\E[J:ce=\\E[K:cl=\\E[2J\\E[H:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\
- \t:do=\\E[B:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\E[A:le=^H:";
-
- InitTerm () {
- register char *s;
-
- if ((s = getenv ("TERM")) == 0)
- Msg (0, "No TERM in environment.");
- if (tgetent (tbuf, s) != 1)
- Msg (0, "Cannot find termcap entry for %s.", s);
- cols = tgetnum ("co");
- rows = tgetnum ("li");
- if (cols <= 0)
- cols = 80;
- if (rows <= 0)
- rows = 24;
- if (tgetflag ("hc"))
- Msg (0, "You can't run screen on a hardcopy terminal.");
- if (tgetflag ("os"))
- Msg (0, "You can't run screen on a terminal that overstrikes.");
- if (tgetflag ("ns"))
- Msg (0, "Terminal must support scrolling.");
- if (!(CL = tgetstr ("cl", &tp)))
- Msg (0, "Clear screen capability required.");
- if (!(CM = tgetstr ("cm", &tp)))
- Msg (0, "Addressable cursor capability required.");
- if (s = tgetstr ("ps", &tp))
- PC = s[0];
- flowctl = !tgetflag ("NF");
- AM = tgetflag ("am");
- if (tgetflag ("LP"))
- AM = 0;
- TI = tgetstr ("ti", &tp);
- TE = tgetstr ("te", &tp);
- if (!(BL = tgetstr ("bl", &tp)))
- BL = "\007";
- VB = tgetstr ("vb", &tp);
- if (!(BC = tgetstr ("bc", &tp))) {
- if (tgetflag ("bs"))
- BC = "\b";
- else
- BC = tgetstr ("le", &tp);
- }
- if (!(CR = tgetstr ("cr", &tp)))
- CR = "\r";
- if (!(NL = tgetstr ("nl", &tp)))
- NL = "\n";
- IS = tgetstr ("is", &tp);
- if (tgetnum ("sg") <= 0) {
- US = tgetstr ("us", &tp);
- UE = tgetstr ("ue", &tp);
- SO = tgetstr ("so", &tp);
- SE = tgetstr ("se", &tp);
- MB = tgetstr ("mb", &tp);
- MD = tgetstr ("md", &tp);
- MH = tgetstr ("mh", &tp);
- MR = tgetstr ("mr", &tp);
- ME = tgetstr ("me", &tp);
- /*
- * Does ME also reverse the effect of SO and/or US? This is not
- * clearly specified by the termcap manual.
- * Anyway, we should at least look whether ME and SE/UE are equal:
- */
- if (SE && UE && ME && (strcmp (SE, UE) == 0 || strcmp (ME, UE) == 0))
- UE = 0;
- if (SE && ME && strcmp (SE, ME) == 0)
- SE = 0;
- }
- CE = tgetstr ("ce", &tp);
- CD = tgetstr ("cd", &tp);
- if (!(DO = tgetstr ("do", &tp)))
- DO = NL;
- UP = tgetstr ("up", &tp);
- ND = tgetstr ("nd", &tp);
- SR = tgetstr ("sr", &tp);
- if (!(SF = tgetstr ("sf", &tp)))
- SF = NL;
- AL = tgetstr ("al", &tp);
- DL = tgetstr ("dl", &tp);
- CS = tgetstr ("cs", &tp);
- DC = tgetstr ("dc", &tp);
- IC = tgetstr ("ic", &tp);
- CDC = tgetstr ("DC", &tp);
- CDL = tgetstr ("DL", &tp);
- CAL = tgetstr ("AL", &tp);
- IM = tgetstr ("im", &tp);
- EI = tgetstr ("ei", &tp);
- if (tgetflag ("in"))
- IC = IM = 0;
- if (IC && IC[0] == '\0')
- IC = 0;
- if (IM && IM[0] == '\0')
- IM = 0;
- if (EI && EI[0] == '\0')
- EI = 0;
- KS = tgetstr ("ks", &tp);
- KE = tgetstr ("ke", &tp);
- ISO2022 = tgetflag ("G0");
- PO = tgetstr ("po", &tp);
- if (!(PF = tgetstr ("pf", &tp)))
- PO = 0;
- blank = malloc (cols);
- null = malloc (cols);
- OldImage = malloc (cols);
- OldAttr = malloc (cols);
- OldFont = malloc (cols);
- if (!(blank && null && OldImage && OldAttr && OldFont))
- Msg (0, "Out of memory.");
- MakeBlankLine (blank, cols);
- bzero (null, cols);
- UPcost = CalcCost (UP);
- DOcost = CalcCost (DO);
- LEcost = CalcCost (BC);
- NDcost = CalcCost (ND);
- CRcost = CalcCost (CR);
- IMcost = CalcCost (IM);
- EIcost = CalcCost (EI);
- PutStr (IS);
- PutStr (TI);
- PutStr (CL);
- }
-
- FinitTerm () {
- PutStr (TE);
- PutStr (IS);
- }
-
- static AddCap (s) char *s; {
- register n;
-
- if (tcLineLen + (n = strlen (s)) > 55) {
- strcat (Termcap, "\\\n\t:");
- tcLineLen = 0;
- }
- strcat (Termcap, s);
- tcLineLen += n;
- }
-
- char *MakeTermcap (aflag) {
- char buf[1024];
- register char **pp, *p;
-
- strcpy (Termcap, TermcapConst);
- sprintf (buf, "li#%d:co#%d:", rows, cols);
- AddCap (buf);
- if (VB)
- AddCap ("vb=\\E[?5h\\E[?5l:");
- if (US) {
- AddCap ("us=\\E[4m:");
- AddCap ("ue=\\E[24m:");
- }
- if (SO) {
- AddCap ("so=\\E[3m:");
- AddCap ("se=\\E[23m:");
- }
- if (MB)
- AddCap ("mb=\\E[5m:");
- if (MD)
- AddCap ("md=\\E[1m:");
- if (MH)
- AddCap ("mh=\\E[2m:");
- if (MR)
- AddCap ("mr=\\E[7m:");
- if (MB || MD || MH || MR)
- AddCap ("me=\\E[0m:");
- if ((CS && SR) || AL || CAL || aflag) {
- AddCap ("sr=\\EM:");
- AddCap ("al=\\E[L:");
- AddCap ("AL=\\E[%dL:");
- }
- if (CS || DL || CDL || aflag) {
- AddCap ("dl=\\E[M:");
- AddCap ("DL=\\E[%dM:");
- }
- if (CS)
- AddCap ("cs=\\E[%i%d;%dr:");
- if (DC || CDC || aflag) {
- AddCap ("dc=\\E[P:");
- AddCap ("DC=\\E[%dP:");
- }
- if (IC || IM || aflag) {
- AddCap ("im=\\E[4h:");
- AddCap ("ei=\\E[4l:");
- AddCap ("ic=:");
- AddCap ("IC=\\E[%d@:");
- }
- if (KS)
- AddCap ("ks=\\E=:");
- if (KE)
- AddCap ("ke=\\E>:");
- if (ISO2022)
- AddCap ("G0:");
- if (PO) {
- AddCap ("po=\\E[5i:");
- AddCap ("pf=\\E[4i:");
- }
- for (pp = KeyCaps; *pp; ++pp)
- if (p = tgetstr (*pp, &tp)) {
- MakeString (*pp, buf, p);
- AddCap (buf);
- }
- return Termcap;
- }
-
- static MakeString (cap, buf, s) char *cap, *buf; register char *s; {
- register char *p = buf;
- register unsigned c;
-
- *p++ = *cap++; *p++ = *cap; *p++ = '=';
- while (c = *s++) {
- switch (c) {
- case '\033':
- *p++ = '\\'; *p++ = 'E'; break;
- case ':':
- sprintf (p, "\\072"); p += 4; break;
- case '^': case '\\':
- *p++ = '\\'; *p++ = c; break;
- default:
- if (c >= 200) {
- sprintf (p, "\\%03o", c & 0377); p += 4;
- } else if (c < ' ') {
- *p++ = '^'; *p++ = c + '@';
- } else *p++ = c;
- }
- }
- *p++ = ':'; *p = '\0';
- }
-
- Activate (wp) struct win *wp; {
- RemoveStatus (wp);
- curr = wp;
- display = 1;
- NewRendition (GlobalAttr, curr->LocalAttr);
- GlobalAttr = curr->LocalAttr;
- NewCharset (GlobalCharset, curr->charsets[curr->LocalCharset]);
- GlobalCharset = curr->charsets[curr->LocalCharset];
- if (CS)
- PutStr (tgoto (CS, curr->bot, curr->top));
- Redisplay ();
- KeypadMode (curr->keypad);
- }
-
- ResetScreen (p) register struct win *p; {
- register i;
-
- bzero (p->tabs, cols);
- for (i = 8; i < cols; i += 8)
- p->tabs[i] = 1;
- p->wrap = 1;
- p->origin = 0;
- p->insert = 0;
- p->vbwait = 0;
- p->keypad = 0;
- p->top = 0;
- p->bot = rows - 1;
- p->saved = 0;
- p->LocalAttr = 0;
- p->x = p->y = 0;
- p->state = LIT;
- p->StringType = NONE;
- p->ss = 0;
- p->LocalCharset = G0;
- for (i = G0; i <= G3; i++)
- p->charsets[i] = ASCII;
- }
-
- WriteString (wp, buf, len) struct win *wp; register char *buf; {
- register c, intermediate = 0;
-
- if (!len)
- return;
- curr = wp;
- display = curr->active;
- if (display)
- RemoveStatus (wp);
- do {
- c = *buf++;
- if (c == '\0' || c == '\177')
- continue;
- NextChar:
- switch (curr->state) {
- case PRIN:
- switch (c) {
- case '\033':
- curr->state = PRINESC; break;
- default:
- PrintChar (c);
- }
- break;
- case PRINESC:
- switch (c) {
- case '[':
- curr->state = PRINCSI; break;
- default:
- PrintChar ('\033'); PrintChar (c);
- curr->state = PRIN;
- }
- break;
- case PRINCSI:
- switch (c) {
- case '4':
- curr->state = PRIN4; break;
- default:
- PrintChar ('\033'); PrintChar ('['); PrintChar (c);
- curr->state = PRIN;
- }
- break;
- case PRIN4:
- switch (c) {
- case 'i':
- curr->state = LIT;
- PrintFlush ();
- break;
- default:
- PrintChar ('\033'); PrintChar ('['); PrintChar ('4');
- PrintChar (c);
- curr->state = PRIN;
- }
- break;
- case TERM:
- switch (c) {
- case '\\':
- curr->state = LIT;
- *(curr->stringp) = '\0';
- if (curr->StringType == PM && display) {
- MakeStatus (curr->string, curr);
- if (status && len > 1) {
- curr->outlen = len-1;
- bcopy (buf, curr->outbuf, curr->outlen);
- return;
- }
- }
- break;
- default:
- curr->state = STR;
- AddChar ('\033');
- AddChar (c);
- }
- break;
- case STR:
- switch (c) {
- case '\0':
- break;
- case '\033':
- curr->state = TERM; break;
- default:
- AddChar (c);
- }
- break;
- case ESC:
- switch (c) {
- case '[':
- curr->NumArgs = 0;
- intermediate = 0;
- bzero ((char *)curr->args, MAXARGS * sizeof (int));
- bzero (curr->GotArg, MAXARGS);
- curr->state = CSI;
- break;
- case ']':
- StartString (OSC); break;
- case '_':
- StartString (APC); break;
- case 'P':
- StartString (DCS); break;
- case '^':
- StartString (PM); break;
- default:
- if (Special (c))
- break;
- if (c >= ' ' && c <= '/') {
- intermediate = intermediate ? -1 : c;
- } else if (c >= '0' && c <= '~') {
- DoESC (c, intermediate);
- curr->state = LIT;
- } else {
- curr->state = LIT;
- goto NextChar;
- }
- }
- break;
- case CSI:
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if (curr->NumArgs < MAXARGS) {
- curr->args[curr->NumArgs] =
- 10 * curr->args[curr->NumArgs] + c - '0';
- curr->GotArg[curr->NumArgs] = 1;
- }
- break;
- case ';': case ':':
- curr->NumArgs++; break;
- default:
- if (Special (c))
- break;
- if (c >= '@' && c <= '~') {
- curr->NumArgs++;
- DoCSI (c, intermediate);
- if (curr->state != PRIN)
- curr->state = LIT;
- } else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?')) {
- intermediate = intermediate ? -1 : c;
- } else {
- curr->state = LIT;
- goto NextChar;
- }
- }
- break;
- default:
- if (!Special (c)) {
- if (c == '\033') {
- intermediate = 0;
- curr->state = ESC;
- } else if (c < ' ') {
- break;
- } else {
- if (curr->ss)
- NewCharset (GlobalCharset, curr->charsets[curr->ss]);
- if (curr->x < cols-1) {
- if (curr->insert) {
- InsertAChar (c);
- } else {
- if (display)
- putchar (c);
- SetChar (c);
- }
- curr->x++;
- } else if (curr->x == cols-1) {
- SetChar (c);
- if (!(AM && curr->y == curr->bot)) {
- if (display)
- putchar (c);
- Goto (-1, -1, curr->y, curr->x);
- }
- curr->x++;
- } else {
- if (curr->wrap) {
- Return ();
- LineFeed ();
- if (curr->insert) {
- InsertAChar (c);
- } else {
- if (display)
- putchar (c);
- SetChar (c);
- }
- curr->x = 1;
- } else curr->x = cols;
- }
- if (curr->ss) {
- NewCharset (curr->charsets[curr->ss], GlobalCharset);
- curr->ss = 0;
- }
- }
- }
- }
- } while (--len);
- curr->outlen = 0;
- if (curr->state == PRIN)
- PrintFlush ();
- }
-
- static Special (c) register c; {
- switch (c) {
- case '\b':
- BackSpace (); return 1;
- case '\r':
- Return (); return 1;
- case '\n':
- LineFeed (); return 1;
- case '\007':
- PutStr (BL);
- if (!display)
- curr->bell = 1;
- return 1;
- case '\t':
- ForwardTab (); return 1;
- case '\017': /* SI */
- MapCharset (G0); return 1;
- case '\016': /* SO */
- MapCharset (G1); return 1;
- }
- return 0;
- }
-
- static DoESC (c, intermediate) {
- switch (intermediate) {
- case 0:
- switch (c) {
- case 'E':
- Return ();
- LineFeed ();
- break;
- case 'D':
- LineFeed ();
- break;
- case 'M':
- ReverseLineFeed ();
- break;
- case 'H':
- curr->tabs[curr->x] = 1;
- break;
- case '7':
- SaveCursor ();
- break;
- case '8':
- RestoreCursor ();
- break;
- case 'c':
- ClearScreen ();
- Goto (curr->y, curr->x, 0, 0);
- NewRendition (GlobalAttr, 0);
- SetRendition (0);
- NewCharset (GlobalCharset, ASCII);
- GlobalCharset = ASCII;
- if (curr->insert)
- InsertMode (0);
- if (curr->keypad)
- KeypadMode (0);
- if (CS)
- PutStr (tgoto (CS, rows-1, 0));
- ResetScreen (curr);
- break;
- case '=':
- KeypadMode (1);
- curr->keypad = 1;
- break;
- case '>':
- KeypadMode (0);
- curr->keypad = 0;
- break;
- case 'n': /* LS2 */
- MapCharset (G2); break;
- case 'o': /* LS3 */
- MapCharset (G3); break;
- case 'N': /* SS2 */
- if (GlobalCharset == curr->charsets[G2])
- curr->ss = 0;
- else
- curr->ss = G2;
- break;
- case 'O': /* SS3 */
- if (GlobalCharset == curr->charsets[G3])
- curr->ss = 0;
- else
- curr->ss = G3;
- break;
- }
- break;
- case '#':
- switch (c) {
- case '8':
- FillWithEs ();
- break;
- }
- break;
- case '(':
- DesignateCharset (c, G0); break;
- case ')':
- DesignateCharset (c, G1); break;
- case '*':
- DesignateCharset (c, G2); break;
- case '+':
- DesignateCharset (c, G3); break;
- }
- }
-
- static DoCSI (c, intermediate) {
- register i, a1 = curr->args[0], a2 = curr->args[1];
-
- if (curr->NumArgs >= MAXARGS)
- curr->NumArgs = MAXARGS;
- for (i = 0; i < curr->NumArgs; ++i)
- if (curr->args[i] == 0)
- curr->GotArg[i] = 0;
- switch (intermediate) {
- case 0:
- switch (c) {
- case 'H': case 'f':
- if (!curr->GotArg[0]) a1 = 1;
- if (!curr->GotArg[1]) a2 = 1;
- if (curr->origin)
- a1 += curr->top;
- if (a1 < 1)
- a1 = 1;
- if (a1 > rows)
- a1 = rows;
- if (a2 < 1)
- a2 = 1;
- if (a2 > cols)
- a2 = cols;
- a1--; a2--;
- Goto (curr->y, curr->x, a1, a2);
- curr->y = a1;
- curr->x = a2;
- break;
- case 'J':
- if (!curr->GotArg[0] || a1 < 0 || a1 > 2)
- a1 = 0;
- switch (a1) {
- case 0:
- ClearToEOS (); break;
- case 1:
- ClearFromBOS (); break;
- case 2:
- ClearScreen ();
- Goto (0, 0, curr->y, curr->x);
- break;
- }
- break;
- case 'K':
- if (!curr->GotArg[0] || a1 < 0 || a1 > 2)
- a1 %= 3;
- switch (a1) {
- case 0:
- ClearToEOL (); break;
- case 1:
- ClearFromBOL (); break;
- case 2:
- ClearLine (); break;
- }
- break;
- case 'A':
- CursorUp (curr->GotArg[0] ? a1 : 1);
- break;
- case 'B':
- CursorDown (curr->GotArg[0] ? a1 : 1);
- break;
- case 'C':
- CursorRight (curr->GotArg[0] ? a1 : 1);
- break;
- case 'D':
- CursorLeft (curr->GotArg[0] ? a1 : 1);
- break;
- case 'm':
- SelectRendition ();
- break;
- case 'g':
- if (!curr->GotArg[0] || a1 == 0)
- curr->tabs[curr->x] = 0;
- else if (a1 == 3)
- bzero (curr->tabs, cols);
- break;
- case 'r':
- if (!CS)
- break;
- if (!curr->GotArg[0]) a1 = 1;
- if (!curr->GotArg[1]) a2 = rows;
- if (a1 < 1 || a2 > rows || a1 >= a2)
- break;
- curr->top = a1-1;
- curr->bot = a2-1;
- PutStr (tgoto (CS, curr->bot, curr->top));
- if (curr->origin) {
- Goto (-1, -1, curr->top, 0);
- curr->y = curr->top;
- curr->x = 0;
- } else {
- Goto (-1, -1, 0, 0);
- curr->y = curr->x = 0;
- }
- break;
- case 'I':
- if (!curr->GotArg[0]) a1 = 1;
- while (a1--)
- ForwardTab ();
- break;
- case 'Z':
- if (!curr->GotArg[0]) a1 = 1;
- while (a1--)
- BackwardTab ();
- break;
- case 'L':
- InsertLine (curr->GotArg[0] ? a1 : 1);
- break;
- case 'M':
- DeleteLine (curr->GotArg[0] ? a1 : 1);
- break;
- case 'P':
- DeleteChar (curr->GotArg[0] ? a1 : 1);
- break;
- case '@':
- InsertChar (curr->GotArg[0] ? a1 : 1);
- break;
- case 'h':
- SetMode (1);
- break;
- case 'l':
- SetMode (0);
- break;
- case 'i':
- if (PO && curr->GotArg[0] && a1 == 5) {
- curr->stringp = curr->string;
- curr->state = PRIN;
- }
- break;
- }
- break;
- case '?':
- if (c != 'h' && c != 'l')
- break;
- if (!curr->GotArg[0])
- break;
- i = (c == 'h');
- if (a1 == 5) {
- if (i) {
- curr->vbwait = 1;
- } else {
- if (curr->vbwait)
- PutStr (VB);
- curr->vbwait = 0;
- }
- } else if (a1 == 6) {
- curr->origin = i;
- if (curr->origin) {
- Goto (curr->y, curr->x, curr->top, 0);
- curr->y = curr->top;
- curr->x = 0;
- } else {
- Goto (curr->y, curr->x, 0, 0);
- curr->y = curr->x = 0;
- }
- } else if (a1 == 7) {
- curr->wrap = i;
- }
- break;
- }
- }
-
- static PutChar (c) {
- putchar (c);
- }
-
- static PutStr (s) char *s; {
- if (display && s)
- tputs (s, 1, PutChar);
- }
-
- static CPutStr (s, c) char *s; {
- if (display && s)
- tputs (tgoto (s, 0, c), 1, PutChar); /* XXX */
- }
-
- static SetChar (c) register c; {
- register struct win *p = curr;
-
- p->image[p->y][p->x] = c;
- p->attr[p->y][p->x] = p->LocalAttr;
- p->font[p->y][p->x] = p->charsets[p->ss ? p->ss : p->LocalCharset];
- }
-
- static StartString (type) enum string_t type; {
- curr->StringType = type;
- curr->stringp = curr->string;
- curr->state = STR;
- }
-
- static AddChar (c) {
- if (curr->stringp >= curr->string+MAXSTR-1)
- curr->state = LIT;
- else
- *(curr->stringp)++ = c;
- }
-
- static PrintChar (c) {
- if (curr->stringp >= curr->string+MAXSTR-1)
- PrintFlush ();
- else
- *(curr->stringp)++ = c;
- }
-
- static PrintFlush () {
- if (curr->stringp > curr->string) {
- tputs (PO, 1, PutChar);
- (void) fflush (stdout);
- (void) write (1, curr->string, curr->stringp - curr->string);
- tputs (PF, 1, PutChar);
- (void) fflush (stdout);
- curr->stringp = curr->string;
- }
- }
-
- /* Insert mode is a toggle on some terminals, so we need this hack:
- */
- static InsertMode (on) {
- if (on) {
- if (!insert)
- PutStr (IM);
- } else if (insert)
- PutStr (EI);
- insert = on;
- }
-
- /* ...and maybe keypad application mode is a toggle, too:
- */
- static KeypadMode (on) {
- if (on) {
- if (!keypad)
- PutStr (KS);
- } else if (keypad)
- PutStr (KE);
- keypad = on;
- }
-
- static DesignateCharset (c, n) {
- curr->ss = 0;
- if (c == 'B')
- c = ASCII;
- if (curr->charsets[n] != c) {
- curr->charsets[n] = c;
- if (curr->LocalCharset == n) {
- NewCharset (GlobalCharset, c);
- GlobalCharset = c;
- }
- }
- }
-
- static MapCharset (n) {
- curr->ss = 0;
- if (curr->LocalCharset != n) {
- curr->LocalCharset = n;
- NewCharset (GlobalCharset, curr->charsets[n]);
- GlobalCharset = curr->charsets[n];
- }
- }
-
- static NewCharset (old, new) {
- char buf[8];
-
- if (old == new)
- return;
- if (ISO2022) {
- sprintf (buf, "\033(%c", new == ASCII ? 'B' : new);
- PutStr (buf);
- }
- }
-
- static SaveCursor () {
- curr->saved = 1;
- curr->Saved_x = curr->x;
- curr->Saved_y = curr->y;
- curr->SavedLocalAttr = curr->LocalAttr;
- curr->SavedLocalCharset = curr->LocalCharset;
- bcopy ((char *)curr->charsets, (char *)curr->SavedCharsets,
- 4 * sizeof (int));
- }
-
- static RestoreCursor () {
- if (curr->saved) {
- curr->LocalAttr = curr->SavedLocalAttr;
- NewRendition (GlobalAttr, curr->LocalAttr);
- GlobalAttr = curr->LocalAttr;
- bcopy ((char *)curr->SavedCharsets, (char *)curr->charsets,
- 4 * sizeof (int));
- curr->LocalCharset = curr->SavedLocalCharset;
- NewCharset (GlobalCharset, curr->charsets[curr->LocalCharset]);
- GlobalCharset = curr->charsets[curr->LocalCharset];
- Goto (curr->y, curr->x, curr->Saved_y, curr->Saved_x);
- curr->x = curr->Saved_x;
- curr->y = curr->Saved_y;
- }
- }
-
- /*ARGSUSED*/
- static CountChars (c) {
- StrCost++;
- }
-
- static CalcCost (s) register char *s; {
- if (s) {
- StrCost = 0;
- tputs (s, 1, CountChars);
- return StrCost;
- } else return EXPENSIVE;
- }
-
- static Goto (y1, x1, y2, x2) {
- register dy, dx;
- register cost = 0;
- register char *s;
- int CMcost, n, m;
- enum move_t xm = M_NONE, ym = M_NONE;
-
- if (!display)
- return;
- if (x1 == cols || x2 == cols) {
- if (x2 == cols) --x2;
- goto DoCM;
- }
- dx = x2 - x1;
- dy = y2 - y1;
- if (dy == 0 && dx == 0)
- return;
- if (y1 == -1 || x1 == -1 || y2 >= curr->bot || y2 <= curr->top) {
- DoCM:
- PutStr (tgoto (CM, x2, y2));
- return;
- }
- CMcost = CalcCost (tgoto (CM, x2, y2));
- if (dx > 0) {
- if ((n = RewriteCost (y1, x1, x2)) < (m = dx * NDcost)) {
- cost = n;
- xm = M_RW;
- } else {
- cost = m;
- xm = M_RI;
- }
- } else if (dx < 0) {
- cost = -dx * LEcost;
- xm = M_LE;
- }
- if (dx && (n = RewriteCost (y1, 0, x2) + CRcost) < cost) {
- cost = n;
- xm = M_CR;
- }
- if (cost >= CMcost)
- goto DoCM;
- if (dy > 0) {
- cost += dy * DOcost;
- ym = M_DO;
- } else if (dy < 0) {
- cost += -dy * UPcost;
- ym = M_UP;
- }
- if (cost >= CMcost)
- goto DoCM;
- if (xm != M_NONE) {
- if (xm == M_LE || xm == M_RI) {
- if (xm == M_LE) {
- s = BC; dx = -dx;
- } else s = ND;
- while (dx-- > 0)
- PutStr (s);
- } else {
- if (xm == M_CR) {
- PutStr (CR);
- x1 = 0;
- }
- if (x1 < x2) {
- if (curr->insert)
- InsertMode (0);
- for (s = curr->image[y1]+x1; x1 < x2; x1++, s++)
- putchar (*s);
- if (curr->insert)
- InsertMode (1);
- }
- }
- }
- if (ym != M_NONE) {
- if (ym == M_UP) {
- s = UP; dy = -dy;
- } else s = DO;
- while (dy-- > 0)
- PutStr (s);
- }
- }
-
- static RewriteCost (y, x1, x2) {
- register cost, dx;
- register char *p = curr->attr[y]+x1, *f = curr->font[y]+x1;
-
- if (AM && y == rows-1 && x2 == cols-1)
- return EXPENSIVE;
- cost = dx = x2 - x1;
- if (dx == 0)
- return 0;
- if (curr->insert)
- cost += EIcost + IMcost;
- do {
- if (*p++ != GlobalAttr || *f++ != GlobalCharset)
- return EXPENSIVE;
- } while (--dx);
- return cost;
- }
-
- static BackSpace () {
- if (curr->x > 0) {
- if (curr->x < cols) {
- if (BC)
- PutStr (BC);
- else
- Goto (curr->y, curr->x, curr->y, curr->x-1);
- }
- curr->x--;
- }
- }
-
- static Return () {
- if (curr->x > 0) {
- curr->x = 0;
- PutStr (CR);
- }
- }
-
- static LineFeed () {
- if (curr->y == curr->bot) {
- ScrollUpMap (curr->image);
- ScrollUpMap (curr->attr);
- ScrollUpMap (curr->font);
- } else if (curr->y < rows-1) {
- curr->y++;
- }
- PutStr (NL);
- }
-
- static ReverseLineFeed () {
- if (curr->y == curr->top) {
- ScrollDownMap (curr->image);
- ScrollDownMap (curr->attr);
- ScrollDownMap (curr->font);
- if (SR) {
- PutStr (SR);
- } else if (AL) {
- Goto (curr->top, curr->x, curr->top, 0);
- PutStr (AL);
- Goto (curr->top, 0, curr->top, curr->x);
- } else Redisplay ();
- } else if (curr->y > 0) {
- CursorUp (1);
- }
- }
-
- static InsertAChar (c) {
- register y = curr->y, x = curr->x;
-
- if (x == cols)
- x--;
- bcopy (curr->image[y], OldImage, cols);
- bcopy (curr->attr[y], OldAttr, cols);
- bcopy (curr->font[y], OldFont, cols);
- bcopy (curr->image[y]+x, curr->image[y]+x+1, cols-x-1);
- bcopy (curr->attr[y]+x, curr->attr[y]+x+1, cols-x-1);
- bcopy (curr->font[y]+x, curr->font[y]+x+1, cols-x-1);
- SetChar (c);
- if (!display)
- return;
- if (IC || IM) {
- if (!curr->insert)
- InsertMode (1);
- PutStr (IC);
- putchar (c);
- if (!curr->insert)
- InsertMode (0);
- } else {
- RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
- ++x;
- Goto (y, last_x, y, x);
- }
- }
-
- static InsertChar (n) {
- register i, y = curr->y, x = curr->x;
-
- if (x == cols)
- return;
- bcopy (curr->image[y], OldImage, cols);
- bcopy (curr->attr[y], OldAttr, cols);
- bcopy (curr->font[y], OldFont, cols);
- if (n > cols-x)
- n = cols-x;
- bcopy (curr->image[y]+x, curr->image[y]+x+n, cols-x-n);
- bcopy (curr->attr[y]+x, curr->attr[y]+x+n, cols-x-n);
- bcopy (curr->font[y]+x, curr->font[y]+x+n, cols-x-n);
- ClearInLine (0, y, x, x+n-1);
- if (!display)
- return;
- if (IC || IM) {
- if (!curr->insert)
- InsertMode (1);
- for (i = n; i; i--) {
- PutStr (IC);
- putchar (' ');
- }
- if (!curr->insert)
- InsertMode (0);
- Goto (y, x+n, y, x);
- } else {
- RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
- Goto (y, last_x, y, x);
- }
- }
-
- static DeleteChar (n) {
- register i, y = curr->y, x = curr->x;
-
- if (x == cols)
- return;
- bcopy (curr->image[y], OldImage, cols);
- bcopy (curr->attr[y], OldAttr, cols);
- bcopy (curr->font[y], OldFont, cols);
- if (n > cols-x)
- n = cols-x;
- bcopy (curr->image[y]+x+n, curr->image[y]+x, cols-x-n);
- bcopy (curr->attr[y]+x+n, curr->attr[y]+x, cols-x-n);
- bcopy (curr->font[y]+x+n, curr->font[y]+x, cols-x-n);
- ClearInLine (0, y, cols-n, cols-1);
- if (!display)
- return;
- if (CDC && !(n == 1 && DC)) {
- CPutStr (CDC, n);
- } else if (DC) {
- for (i = n; i; i--)
- PutStr (DC);
- } else {
- RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
- Goto (y, last_x, y, x);
- }
- }
-
- static DeleteLine (n) {
- register i, old = curr->top;
-
- if (n > curr->bot-curr->y+1)
- n = curr->bot-curr->y+1;
- curr->top = curr->y;
- for (i = n; i; i--) {
- ScrollUpMap (curr->image);
- ScrollUpMap (curr->attr);
- ScrollUpMap (curr->font);
- }
- if (DL || CDL) {
- Goto (curr->y, curr->x, curr->y, 0);
- if (CDL && !(n == 1 && DL)) {
- CPutStr (CDL, n);
- } else {
- for (i = n; i; i--)
- PutStr (DL);
- }
- Goto (curr->y, 0, curr->y, curr->x);
- } else if (CS) {
- PutStr (tgoto (CS, curr->bot, curr->top));
- Goto (-1, -1, curr->bot, 0);
- for (i = n; i; i--)
- PutStr (SF);
- PutStr (tgoto (CS, curr->bot, old));
- Goto (-1, -1, curr->y, curr->x);
- } else Redisplay ();
- curr->top = old;
- }
-
- static InsertLine (n) {
- register i, old = curr->top;
-
- if (n > curr->bot-curr->y+1)
- n = curr->bot-curr->y+1;
- curr->top = curr->y;
- for (i = n; i; i--) {
- ScrollDownMap (curr->image);
- ScrollDownMap (curr->attr);
- ScrollDownMap (curr->font);
- }
- if (AL || CAL) {
- Goto (curr->y, curr->x, curr->y, 0);
- if (CAL && !(n == 1 && AL)) {
- CPutStr (CAL, n);
- } else {
- for (i = n; i; i--)
- PutStr (AL);
- }
- Goto (curr->y, 0, curr->y, curr->x);
- } else if (CS && SR) {
- PutStr (tgoto (CS, curr->bot, curr->top));
- Goto (-1, -1, curr->y, 0);
- for (i = n; i; i--)
- PutStr (SR);
- PutStr (tgoto (CS, curr->bot, old));
- Goto (-1, -1, curr->y, curr->x);
- } else Redisplay ();
- curr->top = old;
- }
-
- static ScrollUpMap (pp) char **pp; {
- register char *tmp = pp[curr->top];
-
- bcopy ((char *)(pp+curr->top+1), (char *)(pp+curr->top),
- (curr->bot-curr->top) * sizeof (char *));
- if (pp == curr->image)
- bclear (tmp, cols);
- else
- bzero (tmp, cols);
- pp[curr->bot] = tmp;
- }
-
- static ScrollDownMap (pp) char **pp; {
- register char *tmp = pp[curr->bot];
-
- bcopy ((char *)(pp+curr->top), (char *)(pp+curr->top+1),
- (curr->bot-curr->top) * sizeof (char *));
- if (pp == curr->image)
- bclear (tmp, cols);
- else
- bzero (tmp, cols);
- pp[curr->top] = tmp;
- }
-
- static ForwardTab () {
- register x = curr->x;
-
- if (curr->tabs[x] && x < cols-1)
- ++x;
- while (x < cols-1 && !curr->tabs[x])
- x++;
- Goto (curr->y, curr->x, curr->y, x);
- curr->x = x;
- }
-
- static BackwardTab () {
- register x = curr->x;
-
- if (curr->tabs[x] && x > 0)
- x--;
- while (x > 0 && !curr->tabs[x])
- x--;
- Goto (curr->y, curr->x, curr->y, x);
- curr->x = x;
- }
-
- static ClearScreen () {
- register i;
-
- PutStr (CL);
- for (i = 0; i < rows; ++i) {
- bclear (curr->image[i], cols);
- bzero (curr->attr[i], cols);
- bzero (curr->font[i], cols);
- }
- }
-
- static ClearFromBOS () {
- register n, y = curr->y, x = curr->x;
-
- for (n = 0; n < y; ++n)
- ClearInLine (1, n, 0, cols-1);
- ClearInLine (1, y, 0, x);
- Goto (curr->y, curr->x, y, x);
- curr->y = y; curr->x = x;
- }
-
- static ClearToEOS () {
- register n, y = curr->y, x = curr->x;
-
- if (CD)
- PutStr (CD);
- ClearInLine (!CD, y, x, cols-1);
- for (n = y+1; n < rows; n++)
- ClearInLine (!CD, n, 0, cols-1);
- Goto (curr->y, curr->x, y, x);
- curr->y = y; curr->x = x;
- }
-
- static ClearLine () {
- register y = curr->y, x = curr->x;
-
- ClearInLine (1, y, 0, cols-1);
- Goto (curr->y, curr->x, y, x);
- curr->y = y; curr->x = x;
- }
-
- static ClearToEOL () {
- register y = curr->y, x = curr->x;
-
- ClearInLine (1, y, x, cols-1);
- Goto (curr->y, curr->x, y, x);
- curr->y = y; curr->x = x;
- }
-
- static ClearFromBOL () {
- register y = curr->y, x = curr->x;
-
- ClearInLine (1, y, 0, x);
- Goto (curr->y, curr->x, y, x);
- curr->y = y; curr->x = x;
- }
-
- static ClearInLine (displ, y, x1, x2) {
- register i, n;
-
- if (x1 == cols) x1--;
- if (x2 == cols) x2--;
- if (n = x2 - x1 + 1) {
- bclear (curr->image[y]+x1, n);
- bzero (curr->attr[y]+x1, n);
- bzero (curr->font[y]+x1, n);
- if (displ && display) {
- if (x2 == cols-1 && CE) {
- Goto (curr->y, curr->x, y, x1);
- curr->y = y; curr->x = x1;
- PutStr (CE);
- return;
- }
- if (y == rows-1 && AM)
- --n;
- if (n == 0)
- return;
- SaveAttr (0);
- Goto (curr->y, curr->x, y, x1);
- for (i = n; i > 0; i--)
- putchar (' ');
- curr->y = y; curr->x = x1 + n;
- RestoreAttr (0);
- }
- }
- }
-
- static CursorRight (n) register n; {
- register x = curr->x;
-
- if (x == cols)
- return;
- if ((curr->x += n) >= cols)
- curr->x = cols-1;
- Goto (curr->y, x, curr->y, curr->x);
- }
-
- static CursorUp (n) register n; {
- register y = curr->y;
-
- if ((curr->y -= n) < curr->top)
- curr->y = curr->top;
- Goto (y, curr->x, curr->y, curr->x);
- }
-
- static CursorDown (n) register n; {
- register y = curr->y;
-
- if ((curr->y += n) > curr->bot)
- curr->y = curr->bot;
- Goto (y, curr->x, curr->y, curr->x);
- }
-
- static CursorLeft (n) register n; {
- register x = curr->x;
-
- if ((curr->x -= n) < 0)
- curr->x = 0;
- Goto (curr->y, x, curr->y, curr->x);
- }
-
- static SetMode (on) {
- register i;
-
- for (i = 0; i < curr->NumArgs; ++i) {
- switch (curr->args[i]) {
- case 4:
- curr->insert = on;
- InsertMode (on);
- break;
- }
- }
- }
-
- static SelectRendition () {
- register i, old = GlobalAttr;
-
- if (curr->NumArgs == 0)
- SetRendition (0);
- else for (i = 0; i < curr->NumArgs; ++i)
- SetRendition (curr->args[i]);
- NewRendition (old, GlobalAttr);
- }
-
- static SetRendition (n) register n; {
- switch (n) {
- case 0:
- GlobalAttr = 0; break;
- case 1:
- GlobalAttr |= A_BD; break;
- case 2:
- GlobalAttr |= A_DI; break;
- case 3:
- GlobalAttr |= A_SO; break;
- case 4:
- GlobalAttr |= A_US; break;
- case 5:
- GlobalAttr |= A_BL; break;
- case 7:
- GlobalAttr |= A_RV; break;
- case 22:
- GlobalAttr &= ~(A_BD|A_SO|A_DI); break;
- case 23:
- GlobalAttr &= ~A_SO; break;
- case 24:
- GlobalAttr &= ~A_US; break;
- case 25:
- GlobalAttr &= ~A_BL; break;
- case 27:
- GlobalAttr &= ~A_RV; break;
- }
- curr->LocalAttr = GlobalAttr;
- }
-
- static NewRendition (old, new) register old, new; {
- register i;
-
- if (old == new)
- return;
- for (i = 1; i <= A_MAX; i <<= 1) {
- if ((old & i) && !(new & i)) {
- PutStr (UE);
- PutStr (SE);
- PutStr (ME);
- if (new & A_US) PutStr (US);
- if (new & A_SO) PutStr (SO);
- if (new & A_BL) PutStr (MB);
- if (new & A_BD) PutStr (MD);
- if (new & A_DI) PutStr (MH);
- if (new & A_RV) PutStr (MR);
- return;
- }
- }
- if ((new & A_US) && !(old & A_US))
- PutStr (US);
- if ((new & A_SO) && !(old & A_SO))
- PutStr (SO);
- if ((new & A_BL) && !(old & A_BL))
- PutStr (MB);
- if ((new & A_BD) && !(old & A_BD))
- PutStr (MD);
- if ((new & A_DI) && !(old & A_DI))
- PutStr (MH);
- if ((new & A_RV) && !(old & A_RV))
- PutStr (MR);
- }
-
- static SaveAttr (newattr) {
- NewRendition (GlobalAttr, newattr);
- NewCharset (GlobalCharset, ASCII);
- if (curr->insert)
- InsertMode (0);
- }
-
- static RestoreAttr (oldattr) {
- NewRendition (oldattr, GlobalAttr);
- NewCharset (ASCII, GlobalCharset);
- if (curr->insert)
- InsertMode (1);
- }
-
- static FillWithEs () {
- register i;
- register char *p, *ep;
-
- curr->y = curr->x = 0;
- SaveAttr (0);
- for (i = 0; i < rows; ++i) {
- bzero (curr->attr[i], cols);
- bzero (curr->font[i], cols);
- p = curr->image[i];
- ep = p + cols;
- for ( ; p < ep; ++p)
- *p = 'E';
- }
- RestoreAttr (0);
- Redisplay ();
- }
-
- static Redisplay () {
- register i;
-
- PutStr (CL);
- TmpAttr = GlobalAttr;
- TmpCharset = GlobalCharset;
- InsertMode (0);
- last_x = last_y = 0;
- for (i = 0; i < rows; ++i)
- DisplayLine (blank, null, null, curr->image[i], curr->attr[i],
- curr->font[i], i, 0, cols-1);
- if (curr->insert)
- InsertMode (1);
- NewRendition (TmpAttr, GlobalAttr);
- NewCharset (TmpCharset, GlobalCharset);
- Goto (last_y, last_x, curr->y, curr->x);
- }
-
- static DisplayLine (os, oa, of, s, as, fs, y, from, to)
- register char *os, *oa, *of, *s, *as, *fs; {
- register i, x, a, f;
-
- if (to == cols)
- --to;
- if (AM && y == rows-1 && to == cols-1)
- --to;
- a = TmpAttr;
- f = TmpCharset;
- for (x = i = from; i <= to; ++i, ++x) {
- if (s[i] == os[i] && as[i] == oa[i] && as[i] == a
- && of[i] == fs[i] && fs[i] == f)
- continue;
- Goto (last_y, last_x, y, x);
- last_y = y;
- last_x = x;
- if ((a = as[i]) != TmpAttr) {
- NewRendition (TmpAttr, a);
- TmpAttr = a;
- }
- if ((f = fs[i]) != TmpCharset) {
- NewCharset (TmpCharset, f);
- TmpCharset = f;
- }
- putchar (s[i]);
- last_x++;
- }
- }
-
- static RedisplayLine (os, oa, of, y, from, to) char *os, *oa, *of; {
- if (curr->insert)
- InsertMode (0);
- NewRendition (GlobalAttr, 0);
- TmpAttr = 0;
- NewCharset (GlobalCharset, ASCII);
- TmpCharset = ASCII;
- last_y = y;
- last_x = from;
- DisplayLine (os, oa, of, curr->image[y], curr->attr[y],
- curr->font[y], y, from, to);
- NewRendition (TmpAttr, GlobalAttr);
- NewCharset (TmpCharset, GlobalCharset);
- if (curr->insert)
- InsertMode (1);
- }
-
- static MakeBlankLine (p, n) register char *p; register n; {
- do *p++ = ' ';
- while (--n);
- }
-
- MakeStatus (msg, wp) char *msg; struct win *wp; {
- struct win *ocurr = curr;
- int odisplay = display;
- register char *s, *t;
- register max = AM ? cols-1 : cols;
-
- for (s = t = msg; *s && t - msg < max; ++s)
- if (*s >= ' ' && *s <= '~')
- *t++ = *s;
- *t = '\0';
- curr = wp;
- display = 1;
- if (status) {
- if (time ((time_t *)0) - TimeDisplayed < 2)
- sleep (1);
- RemoveStatus (wp);
- }
- if (t > msg) {
- status = 1;
- StatLen = t - msg;
- Goto (curr->y, curr->x, rows-1, 0);
- SaveAttr (A_SO);
- printf ("%s", msg);
- RestoreAttr (A_SO);
- (void) fflush (stdout);
- time (&TimeDisplayed);
- }
- curr = ocurr;
- display = odisplay;
- }
-
- RemoveStatus (p) struct win *p; {
- struct win *ocurr = curr;
- int odisplay = display;
-
- if (!status)
- return;
- status = 0;
- curr = p;
- display = 1;
- Goto (-1, -1, rows-1, 0);
- RedisplayLine (null, null, null, rows-1, 0, StatLen);
- Goto (rows-1, last_x, curr->y, curr->x);
- curr = ocurr;
- display = odisplay;
- }
-