home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume17 / screen2 / part01 / ansi.c next >
Encoding:
C/C++ Source or Header  |  1989-02-06  |  35.1 KB  |  1,659 lines

  1. /* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin.
  2.  * Not derived from licensed software.
  3.  *
  4.  * Permission is granted to freely use, copy, modify, and redistribute
  5.  * this software, provided that no attempt is made to gain profit from it,
  6.  * the author is not construed to be liable for any results of using the
  7.  * software, alterations are clearly marked as such, and this notice is
  8.  * not modified.
  9.  */
  10.  
  11. char AnsiVersion[] = "ansi 2.0a 19-Oct-88";
  12.  
  13. #include <stdio.h>
  14. #include <sys/types.h>
  15. #include "screen.h"
  16.  
  17. #define A_SO     0x1    /* Standout mode */
  18. #define A_US     0x2    /* Underscore mode */
  19. #define A_BL     0x4    /* Blinking */
  20. #define A_BD     0x8    /* Bold mode */
  21. #define A_DI    0x10    /* Dim mode */
  22. #define A_RV    0x20    /* Reverse mode */
  23. #define A_MAX   0x20
  24.  
  25. /* Types of movement used by Goto() */
  26. enum move_t {
  27.     M_NONE,
  28.     M_UP,
  29.     M_DO,
  30.     M_LE,
  31.     M_RI,
  32.     M_RW,
  33.     M_CR,
  34. };
  35.  
  36. #define EXPENSIVE    1000
  37.  
  38. #define G0           0
  39. #define G1           1
  40. #define G2           2
  41. #define G3           3
  42.  
  43. #define ASCII        0
  44.  
  45. extern char *getenv(), *tgetstr(), *tgoto(), *malloc();
  46.  
  47. int rows, cols;
  48. int status;
  49. int flowctl;
  50. char Term[] = "TERM=screen";
  51. char Termcap[1024];
  52. char *blank;
  53. char PC;
  54. int ISO2022;
  55. time_t TimeDisplayed;
  56.  
  57. static char tbuf[1024], tentry[1024];
  58. static char *tp = tentry;
  59. static char *TI, *TE, *BL, *VB, *BC, *CR, *NL, *CL, *IS, *CM;
  60. static char *US, *UE, *SO, *SE, *CE, *CD, *DO, *SR, *SF, *AL;
  61. static char *CS, *DL, *DC, *IC, *IM, *EI, *UP, *ND, *KS, *KE;
  62. static char *MB, *MD, *MH, *MR, *ME, *PO, *PF;
  63. static char *CDC, *CDL, *CAL;
  64. static AM;
  65. static char GlobalAttr, TmpAttr, GlobalCharset, TmpCharset;
  66. static char *OldImage, *OldAttr, *OldFont;
  67. static last_x, last_y;
  68. static struct win *curr;
  69. static display = 1;
  70. static StrCost;
  71. static UPcost, DOcost, LEcost, NDcost, CRcost, IMcost, EIcost;
  72. static tcLineLen = 100;
  73. static char *null;
  74. static StatLen;
  75. static insert;
  76. static keypad;
  77.  
  78. static char *KeyCaps[] = {
  79.     "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9",
  80.     "kb", "kd", "kh", "kl", "ko", "kr", "ku",
  81.     0
  82. };
  83.  
  84. static char TermcapConst[] = "TERMCAP=\
  85. SC|screen|VT 100/ANSI X3.64 virtual terminal|\\\n\
  86. \t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\
  87. \t:cd=\\E[J:ce=\\E[K:cl=\\E[2J\\E[H:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\
  88. \t:do=\\E[B:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\E[A:le=^H:";
  89.  
  90. InitTerm () {
  91.     register char *s;
  92.  
  93.     if ((s = getenv ("TERM")) == 0)
  94.     Msg (0, "No TERM in environment.");
  95.     if (tgetent (tbuf, s) != 1)
  96.     Msg (0, "Cannot find termcap entry for %s.", s);
  97.     cols = tgetnum ("co");
  98.     rows = tgetnum ("li");
  99.     if (cols <= 0)
  100.     cols = 80;
  101.     if (rows <= 0)
  102.     rows = 24;
  103.     if (tgetflag ("hc"))
  104.     Msg (0, "You can't run screen on a hardcopy terminal.");
  105.     if (tgetflag ("os"))
  106.     Msg (0, "You can't run screen on a terminal that overstrikes.");
  107.     if (tgetflag ("ns"))
  108.     Msg (0, "Terminal must support scrolling.");
  109.     if (!(CL = tgetstr ("cl", &tp)))
  110.     Msg (0, "Clear screen capability required.");
  111.     if (!(CM = tgetstr ("cm", &tp)))
  112.     Msg (0, "Addressable cursor capability required.");
  113.     if (s = tgetstr ("ps", &tp))
  114.     PC = s[0];
  115.     flowctl = !tgetflag ("NF");
  116.     AM = tgetflag ("am");
  117.     if (tgetflag ("LP"))
  118.     AM = 0;
  119.     TI = tgetstr ("ti", &tp);
  120.     TE = tgetstr ("te", &tp);
  121.     if (!(BL = tgetstr ("bl", &tp)))
  122.     BL = "\007";
  123.     VB = tgetstr ("vb", &tp);
  124.     if (!(BC = tgetstr ("bc", &tp))) {
  125.     if (tgetflag ("bs"))
  126.         BC = "\b";
  127.     else
  128.         BC = tgetstr ("le", &tp);
  129.     }
  130.     if (!(CR = tgetstr ("cr", &tp)))
  131.     CR = "\r";
  132.     if (!(NL = tgetstr ("nl", &tp)))
  133.     NL = "\n";
  134.     IS = tgetstr ("is", &tp);
  135.     if (tgetnum ("sg") <= 0) {
  136.     US = tgetstr ("us", &tp);
  137.     UE = tgetstr ("ue", &tp);
  138.     SO = tgetstr ("so", &tp);
  139.     SE = tgetstr ("se", &tp);
  140.     MB = tgetstr ("mb", &tp);
  141.     MD = tgetstr ("md", &tp);
  142.     MH = tgetstr ("mh", &tp);
  143.     MR = tgetstr ("mr", &tp);
  144.     ME = tgetstr ("me", &tp);
  145.     /*
  146.      * Does ME also reverse the effect of SO and/or US?  This is not
  147.      * clearly specified by the termcap manual.
  148.      * Anyway, we should at least look whether ME and SE/UE are equal:
  149.      */
  150.     if (SE && UE && ME && (strcmp (SE, UE) == 0 || strcmp (ME, UE) == 0))
  151.         UE = 0;
  152.     if (SE && ME && strcmp (SE, ME) == 0)
  153.         SE = 0;
  154.     }
  155.     CE = tgetstr ("ce", &tp);
  156.     CD = tgetstr ("cd", &tp);
  157.     if (!(DO = tgetstr ("do", &tp)))
  158.     DO = NL;
  159.     UP = tgetstr ("up", &tp);
  160.     ND = tgetstr ("nd", &tp);
  161.     SR = tgetstr ("sr", &tp);
  162.     if (!(SF = tgetstr ("sf", &tp)))
  163.     SF = NL;
  164.     AL = tgetstr ("al", &tp);
  165.     DL = tgetstr ("dl", &tp);
  166.     CS = tgetstr ("cs", &tp);
  167.     DC = tgetstr ("dc", &tp);
  168.     IC = tgetstr ("ic", &tp);
  169.     CDC = tgetstr ("DC", &tp);
  170.     CDL = tgetstr ("DL", &tp);
  171.     CAL = tgetstr ("AL", &tp);
  172.     IM = tgetstr ("im", &tp);
  173.     EI = tgetstr ("ei", &tp);
  174.     if (tgetflag ("in"))
  175.     IC = IM = 0;
  176.     if (IC && IC[0] == '\0')
  177.     IC = 0;
  178.     if (IM && IM[0] == '\0')
  179.     IM = 0;
  180.     if (EI && EI[0] == '\0')
  181.     EI = 0;
  182.     KS = tgetstr ("ks", &tp);
  183.     KE = tgetstr ("ke", &tp);
  184.     ISO2022 = tgetflag ("G0");
  185.     PO = tgetstr ("po", &tp);
  186.     if (!(PF = tgetstr ("pf", &tp)))
  187.     PO = 0;
  188.     blank = malloc (cols);
  189.     null = malloc (cols);
  190.     OldImage = malloc (cols);
  191.     OldAttr = malloc (cols);
  192.     OldFont = malloc (cols);
  193.     if (!(blank && null && OldImage && OldAttr && OldFont))
  194.     Msg (0, "Out of memory.");
  195.     MakeBlankLine (blank, cols);
  196.     bzero (null, cols);
  197.     UPcost = CalcCost (UP);
  198.     DOcost = CalcCost (DO);
  199.     LEcost = CalcCost (BC);
  200.     NDcost = CalcCost (ND);
  201.     CRcost = CalcCost (CR);
  202.     IMcost = CalcCost (IM);
  203.     EIcost = CalcCost (EI);
  204.     PutStr (IS);
  205.     PutStr (TI);
  206.     PutStr (CL);
  207. }
  208.  
  209. FinitTerm () {
  210.     PutStr (TE);
  211.     PutStr (IS);
  212. }
  213.  
  214. static AddCap (s) char *s; {
  215.     register n;
  216.  
  217.     if (tcLineLen + (n = strlen (s)) > 55) {
  218.     strcat (Termcap, "\\\n\t:");
  219.     tcLineLen = 0;
  220.     }
  221.     strcat (Termcap, s);
  222.     tcLineLen += n;
  223. }
  224.  
  225. char *MakeTermcap (aflag) {
  226.     char buf[1024];
  227.     register char **pp, *p;
  228.  
  229.     strcpy (Termcap, TermcapConst);
  230.     sprintf (buf, "li#%d:co#%d:", rows, cols);
  231.     AddCap (buf);
  232.     if (VB)
  233.     AddCap ("vb=\\E[?5h\\E[?5l:");
  234.     if (US) {
  235.     AddCap ("us=\\E[4m:");
  236.     AddCap ("ue=\\E[24m:");
  237.     }
  238.     if (SO) {
  239.     AddCap ("so=\\E[3m:");
  240.     AddCap ("se=\\E[23m:");
  241.     }
  242.     if (MB)
  243.     AddCap ("mb=\\E[5m:");
  244.     if (MD)
  245.     AddCap ("md=\\E[1m:");
  246.     if (MH)
  247.     AddCap ("mh=\\E[2m:");
  248.     if (MR)
  249.     AddCap ("mr=\\E[7m:");
  250.     if (MB || MD || MH || MR)
  251.     AddCap ("me=\\E[0m:");
  252.     if ((CS && SR) || AL || CAL || aflag) {
  253.     AddCap ("sr=\\EM:");
  254.     AddCap ("al=\\E[L:");
  255.     AddCap ("AL=\\E[%dL:");
  256.     }
  257.     if (CS || DL || CDL || aflag) {
  258.     AddCap ("dl=\\E[M:");
  259.     AddCap ("DL=\\E[%dM:");
  260.     }
  261.     if (CS)
  262.     AddCap ("cs=\\E[%i%d;%dr:");
  263.     if (DC || CDC || aflag) {
  264.     AddCap ("dc=\\E[P:");
  265.     AddCap ("DC=\\E[%dP:");
  266.     }
  267.     if (IC || IM || aflag) {
  268.     AddCap ("im=\\E[4h:");
  269.     AddCap ("ei=\\E[4l:");
  270.     AddCap ("ic=:");
  271.     AddCap ("IC=\\E[%d@:");
  272.     }
  273.     if (KS)
  274.     AddCap ("ks=\\E=:");
  275.     if (KE)
  276.     AddCap ("ke=\\E>:");
  277.     if (ISO2022)
  278.     AddCap ("G0:");
  279.     if (PO) {
  280.     AddCap ("po=\\E[5i:");
  281.     AddCap ("pf=\\E[4i:");
  282.     }
  283.     for (pp = KeyCaps; *pp; ++pp)
  284.     if (p = tgetstr (*pp, &tp)) {
  285.         MakeString (*pp, buf, p);
  286.         AddCap (buf);
  287.     }
  288.     return Termcap;
  289. }
  290.  
  291. static MakeString (cap, buf, s) char *cap, *buf; register char *s; {
  292.     register char *p = buf;
  293.     register unsigned c;
  294.  
  295.     *p++ = *cap++; *p++ = *cap; *p++ = '=';
  296.     while (c = *s++) {
  297.     switch (c) {
  298.     case '\033':
  299.         *p++ = '\\'; *p++ = 'E'; break;
  300.     case ':':
  301.         sprintf (p, "\\072"); p += 4; break;
  302.     case '^': case '\\':
  303.         *p++ = '\\'; *p++ = c; break;
  304.     default:
  305.         if (c >= 200) {
  306.         sprintf (p, "\\%03o", c & 0377); p += 4;
  307.         } else if (c < ' ') {
  308.         *p++ = '^'; *p++ = c + '@';
  309.         } else *p++ = c;
  310.     }
  311.     }
  312.     *p++ = ':'; *p = '\0';
  313. }
  314.  
  315. Activate (wp) struct win *wp; {
  316.     RemoveStatus (wp);
  317.     curr = wp;
  318.     display = 1;
  319.     NewRendition (GlobalAttr, curr->LocalAttr);
  320.     GlobalAttr = curr->LocalAttr;
  321.     NewCharset (GlobalCharset, curr->charsets[curr->LocalCharset]);
  322.     GlobalCharset = curr->charsets[curr->LocalCharset];
  323.     if (CS)
  324.     PutStr (tgoto (CS, curr->bot, curr->top));
  325.     Redisplay ();
  326.     KeypadMode (curr->keypad);
  327. }
  328.  
  329. ResetScreen (p) register struct win *p; {
  330.     register i;
  331.  
  332.     bzero (p->tabs, cols);
  333.     for (i = 8; i < cols; i += 8)
  334.     p->tabs[i] = 1;
  335.     p->wrap = 1;
  336.     p->origin = 0;
  337.     p->insert = 0;
  338.     p->vbwait = 0;
  339.     p->keypad = 0;
  340.     p->top = 0;
  341.     p->bot = rows - 1;
  342.     p->saved = 0;
  343.     p->LocalAttr = 0;
  344.     p->x = p->y = 0;
  345.     p->state = LIT;
  346.     p->StringType = NONE;
  347.     p->ss = 0;
  348.     p->LocalCharset = G0;
  349.     for (i = G0; i <= G3; i++)
  350.     p->charsets[i] = ASCII;
  351. }
  352.  
  353. WriteString (wp, buf, len) struct win *wp; register char *buf; {
  354.     register c, intermediate = 0;
  355.  
  356.     if (!len)
  357.     return;
  358.     curr = wp;
  359.     display = curr->active;
  360.     if (display)
  361.     RemoveStatus (wp);
  362.     do {
  363.     c = *buf++;
  364.     if (c == '\0' || c == '\177')
  365.         continue;
  366. NextChar:
  367.     switch (curr->state) {
  368.     case PRIN:
  369.         switch (c) {
  370.         case '\033':
  371.         curr->state = PRINESC; break;
  372.         default:
  373.         PrintChar (c);
  374.         }
  375.         break;
  376.     case PRINESC:
  377.         switch (c) {
  378.         case '[':
  379.         curr->state = PRINCSI; break;
  380.         default:
  381.         PrintChar ('\033'); PrintChar (c);
  382.         curr->state = PRIN;
  383.         }
  384.         break;
  385.     case PRINCSI:
  386.         switch (c) {
  387.         case '4':
  388.         curr->state = PRIN4; break;
  389.         default:
  390.         PrintChar ('\033'); PrintChar ('['); PrintChar (c);
  391.         curr->state = PRIN;
  392.         }
  393.         break;
  394.     case PRIN4:
  395.         switch (c) {
  396.         case 'i':
  397.         curr->state = LIT;
  398.         PrintFlush ();
  399.         break;
  400.         default:
  401.         PrintChar ('\033'); PrintChar ('['); PrintChar ('4');
  402.         PrintChar (c);
  403.         curr->state = PRIN;
  404.         }
  405.         break;
  406.     case TERM:
  407.         switch (c) {
  408.         case '\\':
  409.         curr->state = LIT;
  410.         *(curr->stringp) = '\0';
  411.         if (curr->StringType == PM && display) {
  412.             MakeStatus (curr->string, curr);
  413.             if (status && len > 1) {
  414.             curr->outlen = len-1;
  415.             bcopy (buf, curr->outbuf, curr->outlen);
  416.             return;
  417.             }
  418.         }
  419.         break;
  420.         default:
  421.         curr->state = STR;
  422.         AddChar ('\033');
  423.         AddChar (c);
  424.         }
  425.         break;
  426.     case STR:
  427.         switch (c) {
  428.         case '\0':
  429.         break;
  430.         case '\033':
  431.         curr->state = TERM; break;
  432.         default:
  433.         AddChar (c);
  434.         }
  435.         break;
  436.     case ESC:
  437.         switch (c) {
  438.         case '[':
  439.         curr->NumArgs = 0;
  440.         intermediate = 0;
  441.         bzero ((char *)curr->args, MAXARGS * sizeof (int));
  442.         bzero (curr->GotArg, MAXARGS);
  443.         curr->state = CSI;
  444.         break;
  445.         case ']':
  446.         StartString (OSC); break;
  447.         case '_':
  448.         StartString (APC); break;
  449.         case 'P':
  450.         StartString (DCS); break;
  451.         case '^':
  452.         StartString (PM); break;
  453.         default:
  454.         if (Special (c))
  455.             break;
  456.         if (c >= ' ' && c <= '/') {
  457.             intermediate = intermediate ? -1 : c;
  458.         } else if (c >= '0' && c <= '~') {
  459.             DoESC (c, intermediate);
  460.             curr->state = LIT;
  461.         } else {
  462.             curr->state = LIT;
  463.             goto NextChar;
  464.         }
  465.         }
  466.         break;
  467.     case CSI:
  468.         switch (c) {
  469.         case '0': case '1': case '2': case '3': case '4':
  470.         case '5': case '6': case '7': case '8': case '9':
  471.         if (curr->NumArgs < MAXARGS) {
  472.             curr->args[curr->NumArgs] =
  473.                         10 * curr->args[curr->NumArgs] + c - '0';
  474.             curr->GotArg[curr->NumArgs] = 1;
  475.         }
  476.         break;
  477.         case ';': case ':':
  478.         curr->NumArgs++; break;
  479.         default:
  480.         if (Special (c))
  481.             break;
  482.         if (c >= '@' && c <= '~') {
  483.             curr->NumArgs++;
  484.             DoCSI (c, intermediate);
  485.             if (curr->state != PRIN)
  486.             curr->state = LIT;
  487.         } else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?')) {
  488.             intermediate = intermediate ? -1 : c;
  489.         } else {
  490.             curr->state = LIT;
  491.             goto NextChar;
  492.         }
  493.         }
  494.         break;
  495.     default:
  496.         if (!Special (c)) {
  497.         if (c == '\033') {
  498.             intermediate = 0;
  499.             curr->state = ESC;
  500.         } else if (c < ' ') {
  501.             break;
  502.         } else {
  503.             if (curr->ss)
  504.             NewCharset (GlobalCharset, curr->charsets[curr->ss]);
  505.             if (curr->x < cols-1) {
  506.             if (curr->insert) {
  507.                 InsertAChar (c);
  508.             } else {
  509.                 if (display)
  510.                 putchar (c);
  511.                 SetChar (c);
  512.             }
  513.             curr->x++;
  514.             } else if (curr->x == cols-1) {
  515.             SetChar (c);
  516.             if (!(AM && curr->y == curr->bot)) {
  517.                 if (display)
  518.                 putchar (c);
  519.                 Goto (-1, -1, curr->y, curr->x);
  520.             }
  521.             curr->x++;
  522.             } else {
  523.             if (curr->wrap) {
  524.                 Return ();
  525.                 LineFeed ();
  526.                 if (curr->insert) {
  527.                 InsertAChar (c);
  528.                 } else {
  529.                 if (display)
  530.                     putchar (c);
  531.                 SetChar (c);
  532.                 }
  533.                 curr->x = 1;
  534.             } else curr->x = cols;
  535.             }
  536.             if (curr->ss) {
  537.             NewCharset (curr->charsets[curr->ss], GlobalCharset);
  538.             curr->ss = 0;
  539.             }
  540.         }
  541.         }
  542.     }
  543.     } while (--len);
  544.     curr->outlen = 0;
  545.     if (curr->state == PRIN)
  546.     PrintFlush ();
  547. }
  548.  
  549. static Special (c) register c; {
  550.     switch (c) {
  551.     case '\b':
  552.     BackSpace (); return 1;
  553.     case '\r':
  554.     Return (); return 1;
  555.     case '\n':
  556.     LineFeed (); return 1;
  557.     case '\007':
  558.     PutStr (BL);
  559.     if (!display)
  560.         curr->bell = 1;
  561.     return 1;
  562.     case '\t':
  563.     ForwardTab (); return 1;
  564.     case '\017':   /* SI */
  565.     MapCharset (G0); return 1;
  566.     case '\016':   /* SO */
  567.     MapCharset (G1); return 1;
  568.     }
  569.     return 0;
  570. }
  571.  
  572. static DoESC (c, intermediate) {
  573.     switch (intermediate) {
  574.     case 0:
  575.     switch (c) {
  576.     case 'E':
  577.         Return ();
  578.         LineFeed ();
  579.         break;
  580.     case 'D':
  581.         LineFeed (); 
  582.         break;
  583.     case 'M':
  584.         ReverseLineFeed ();
  585.         break;
  586.     case 'H':
  587.         curr->tabs[curr->x] = 1;
  588.         break;
  589.     case '7':
  590.         SaveCursor ();
  591.         break;
  592.     case '8':
  593.         RestoreCursor ();
  594.         break;
  595.     case 'c':
  596.         ClearScreen ();
  597.         Goto (curr->y, curr->x, 0, 0);
  598.         NewRendition (GlobalAttr, 0);
  599.         SetRendition (0);
  600.         NewCharset (GlobalCharset, ASCII);
  601.         GlobalCharset = ASCII;
  602.         if (curr->insert)
  603.         InsertMode (0);
  604.         if (curr->keypad)
  605.         KeypadMode (0);
  606.         if (CS)
  607.         PutStr (tgoto (CS, rows-1, 0));
  608.         ResetScreen (curr);
  609.         break;
  610.     case '=':
  611.         KeypadMode (1);
  612.         curr->keypad = 1;
  613.         break;
  614.     case '>':
  615.         KeypadMode (0);
  616.         curr->keypad = 0;
  617.         break;
  618.     case 'n':   /* LS2 */
  619.         MapCharset (G2); break;
  620.     case 'o':   /* LS3 */
  621.         MapCharset (G3); break;
  622.     case 'N':   /* SS2 */
  623.         if (GlobalCharset == curr->charsets[G2])
  624.         curr->ss = 0;
  625.         else
  626.         curr->ss = G2;
  627.         break;
  628.     case 'O':   /* SS3 */
  629.         if (GlobalCharset == curr->charsets[G3])
  630.         curr->ss = 0;
  631.         else
  632.         curr->ss = G3;
  633.         break;
  634.     }
  635.     break;
  636.     case '#':
  637.     switch (c) {
  638.     case '8':
  639.         FillWithEs ();
  640.         break;
  641.     }
  642.     break;
  643.     case '(':
  644.     DesignateCharset (c, G0); break;
  645.     case ')':
  646.     DesignateCharset (c, G1); break;
  647.     case '*':
  648.     DesignateCharset (c, G2); break;
  649.     case '+':
  650.     DesignateCharset (c, G3); break;
  651.     }
  652. }
  653.  
  654. static DoCSI (c, intermediate) {
  655.     register i, a1 = curr->args[0], a2 = curr->args[1];
  656.  
  657.     if (curr->NumArgs >= MAXARGS)
  658.     curr->NumArgs = MAXARGS;
  659.     for (i = 0; i < curr->NumArgs; ++i)
  660.     if (curr->args[i] == 0)
  661.         curr->GotArg[i] = 0;
  662.     switch (intermediate) {
  663.     case 0:
  664.     switch (c) {
  665.     case 'H': case 'f':
  666.         if (!curr->GotArg[0]) a1 = 1;
  667.         if (!curr->GotArg[1]) a2 = 1;
  668.         if (curr->origin)
  669.         a1 += curr->top;
  670.         if (a1 < 1)
  671.         a1 = 1;
  672.         if (a1 > rows)
  673.         a1 = rows;
  674.         if (a2 < 1)
  675.         a2 = 1;
  676.         if (a2 > cols)
  677.         a2 = cols;
  678.         a1--; a2--;
  679.         Goto (curr->y, curr->x, a1, a2);
  680.         curr->y = a1;
  681.         curr->x = a2;
  682.         break;
  683.     case 'J':
  684.         if (!curr->GotArg[0] || a1 < 0 || a1 > 2)
  685.         a1 = 0;
  686.         switch (a1) {
  687.         case 0:
  688.         ClearToEOS (); break;
  689.         case 1:
  690.         ClearFromBOS (); break;
  691.         case 2:
  692.         ClearScreen ();
  693.         Goto (0, 0, curr->y, curr->x);
  694.         break;
  695.         }
  696.         break;
  697.     case 'K':
  698.         if (!curr->GotArg[0] || a1 < 0 || a1 > 2)
  699.         a1 %= 3;
  700.         switch (a1) {
  701.         case 0:
  702.         ClearToEOL (); break;
  703.         case 1:
  704.         ClearFromBOL (); break;
  705.         case 2:
  706.         ClearLine (); break;
  707.         }
  708.         break;
  709.     case 'A':
  710.         CursorUp (curr->GotArg[0] ? a1 : 1);
  711.         break;
  712.     case 'B':
  713.         CursorDown (curr->GotArg[0] ? a1 : 1);
  714.         break;
  715.     case 'C':
  716.         CursorRight (curr->GotArg[0] ? a1 : 1);
  717.         break;
  718.     case 'D':
  719.         CursorLeft (curr->GotArg[0] ? a1 : 1);
  720.         break;
  721.     case 'm':
  722.         SelectRendition ();
  723.         break;
  724.     case 'g':
  725.         if (!curr->GotArg[0] || a1 == 0)
  726.         curr->tabs[curr->x] = 0;
  727.         else if (a1 == 3)
  728.         bzero (curr->tabs, cols);
  729.         break;
  730.     case 'r':
  731.         if (!CS)
  732.         break;
  733.         if (!curr->GotArg[0]) a1 = 1;
  734.         if (!curr->GotArg[1]) a2 = rows;
  735.         if (a1 < 1 || a2 > rows || a1 >= a2)
  736.         break;
  737.         curr->top = a1-1;
  738.         curr->bot = a2-1;
  739.         PutStr (tgoto (CS, curr->bot, curr->top));
  740.         if (curr->origin) {
  741.         Goto (-1, -1, curr->top, 0);
  742.         curr->y = curr->top;
  743.         curr->x = 0;
  744.         } else {
  745.         Goto (-1, -1, 0, 0);
  746.         curr->y = curr->x = 0;
  747.         }
  748.         break;
  749.     case 'I':
  750.         if (!curr->GotArg[0]) a1 = 1;
  751.         while (a1--)
  752.         ForwardTab ();
  753.         break;
  754.     case 'Z':
  755.         if (!curr->GotArg[0]) a1 = 1;
  756.         while (a1--)
  757.         BackwardTab ();
  758.         break;
  759.     case 'L':
  760.         InsertLine (curr->GotArg[0] ? a1 : 1);
  761.         break;
  762.     case 'M':
  763.         DeleteLine (curr->GotArg[0] ? a1 : 1);
  764.         break;
  765.     case 'P':
  766.         DeleteChar (curr->GotArg[0] ? a1 : 1);
  767.         break;
  768.     case '@':
  769.         InsertChar (curr->GotArg[0] ? a1 : 1);
  770.         break;
  771.     case 'h':
  772.         SetMode (1);
  773.         break;
  774.     case 'l':
  775.         SetMode (0);
  776.         break;
  777.     case 'i':
  778.         if (PO && curr->GotArg[0] && a1 == 5) {
  779.         curr->stringp = curr->string;
  780.         curr->state = PRIN;
  781.         }
  782.         break;
  783.     }
  784.     break;
  785.     case '?':
  786.     if (c != 'h' && c != 'l')
  787.         break;
  788.     if (!curr->GotArg[0])
  789.         break;
  790.     i = (c == 'h');
  791.     if (a1 == 5) {
  792.         if (i) {
  793.         curr->vbwait = 1;
  794.         } else {
  795.         if (curr->vbwait)
  796.             PutStr (VB);
  797.         curr->vbwait = 0;
  798.         }
  799.     } else if (a1 == 6) {
  800.         curr->origin = i;
  801.         if (curr->origin) {
  802.         Goto (curr->y, curr->x, curr->top, 0);
  803.         curr->y = curr->top;
  804.         curr->x = 0;
  805.         } else {
  806.         Goto (curr->y, curr->x, 0, 0);
  807.         curr->y = curr->x = 0;
  808.         }
  809.     } else if (a1 == 7) {
  810.         curr->wrap = i;
  811.     }
  812.     break;
  813.     }
  814. }
  815.  
  816. static PutChar (c) {
  817.     putchar (c);
  818. }
  819.  
  820. static PutStr (s) char *s; {
  821.     if (display && s)
  822.     tputs (s, 1, PutChar);
  823. }
  824.  
  825. static CPutStr (s, c) char *s; {
  826.     if (display && s)
  827.     tputs (tgoto (s, 0, c), 1, PutChar);  /* XXX */
  828. }
  829.  
  830. static SetChar (c) register c; {
  831.     register struct win *p = curr;
  832.  
  833.     p->image[p->y][p->x] = c;
  834.     p->attr[p->y][p->x] = p->LocalAttr;
  835.     p->font[p->y][p->x] = p->charsets[p->ss ? p->ss : p->LocalCharset];
  836. }
  837.  
  838. static StartString (type) enum string_t type; {
  839.     curr->StringType = type;
  840.     curr->stringp = curr->string;
  841.     curr->state = STR;
  842. }
  843.  
  844. static AddChar (c) {
  845.     if (curr->stringp >= curr->string+MAXSTR-1)
  846.     curr->state = LIT;
  847.     else
  848.     *(curr->stringp)++ = c;
  849. }
  850.  
  851. static PrintChar (c) {
  852.     if (curr->stringp >= curr->string+MAXSTR-1)
  853.     PrintFlush ();
  854.     else
  855.     *(curr->stringp)++ = c;
  856. }
  857.  
  858. static PrintFlush () {
  859.     if (curr->stringp > curr->string) {
  860.     tputs (PO, 1, PutChar);
  861.     (void) fflush (stdout);
  862.     (void) write (1, curr->string, curr->stringp - curr->string);
  863.     tputs (PF, 1, PutChar);
  864.     (void) fflush (stdout);
  865.     curr->stringp = curr->string;
  866.     }
  867. }
  868.  
  869. /* Insert mode is a toggle on some terminals, so we need this hack:
  870.  */
  871. static InsertMode (on) {
  872.     if (on) {
  873.     if (!insert)
  874.         PutStr (IM);
  875.     } else if (insert)
  876.     PutStr (EI);
  877.     insert = on;
  878. }
  879.  
  880. /* ...and maybe keypad application mode is a toggle, too:
  881.  */
  882. static KeypadMode (on) {
  883.     if (on) {
  884.     if (!keypad)
  885.         PutStr (KS);
  886.     } else if (keypad)
  887.     PutStr (KE);
  888.     keypad = on;
  889. }
  890.  
  891. static DesignateCharset (c, n) {
  892.     curr->ss = 0;
  893.     if (c == 'B')
  894.     c = ASCII;
  895.     if (curr->charsets[n] != c) {
  896.     curr->charsets[n] = c;
  897.     if (curr->LocalCharset == n) {
  898.         NewCharset (GlobalCharset, c);
  899.         GlobalCharset = c;
  900.     }
  901.     }
  902. }
  903.  
  904. static MapCharset (n) {
  905.     curr->ss = 0;
  906.     if (curr->LocalCharset != n) {
  907.     curr->LocalCharset = n;
  908.     NewCharset (GlobalCharset, curr->charsets[n]);
  909.     GlobalCharset = curr->charsets[n];
  910.     }
  911. }
  912.  
  913. static NewCharset (old, new) {
  914.     char buf[8];
  915.  
  916.     if (old == new)
  917.     return;
  918.     if (ISO2022) {
  919.     sprintf (buf, "\033(%c", new == ASCII ? 'B' : new);
  920.     PutStr (buf);
  921.     }
  922. }
  923.  
  924. static SaveCursor () {
  925.     curr->saved = 1;
  926.     curr->Saved_x = curr->x;
  927.     curr->Saved_y = curr->y;
  928.     curr->SavedLocalAttr = curr->LocalAttr;
  929.     curr->SavedLocalCharset = curr->LocalCharset;
  930.     bcopy ((char *)curr->charsets, (char *)curr->SavedCharsets,
  931.     4 * sizeof (int));
  932. }
  933.  
  934. static RestoreCursor () {
  935.     if (curr->saved) {
  936.     curr->LocalAttr = curr->SavedLocalAttr;
  937.     NewRendition (GlobalAttr, curr->LocalAttr);
  938.     GlobalAttr = curr->LocalAttr;
  939.     bcopy ((char *)curr->SavedCharsets, (char *)curr->charsets,
  940.         4 * sizeof (int));
  941.     curr->LocalCharset = curr->SavedLocalCharset;
  942.     NewCharset (GlobalCharset, curr->charsets[curr->LocalCharset]);
  943.     GlobalCharset = curr->charsets[curr->LocalCharset];
  944.     Goto (curr->y, curr->x, curr->Saved_y, curr->Saved_x);
  945.     curr->x = curr->Saved_x;
  946.     curr->y = curr->Saved_y;
  947.     }
  948. }
  949.  
  950. /*ARGSUSED*/
  951. static CountChars (c) {
  952.     StrCost++;
  953. }
  954.  
  955. static CalcCost (s) register char *s; {
  956.     if (s) {
  957.     StrCost = 0;
  958.     tputs (s, 1, CountChars);
  959.     return StrCost;
  960.     } else return EXPENSIVE;
  961. }
  962.  
  963. static Goto (y1, x1, y2, x2) {
  964.     register dy, dx;
  965.     register cost = 0;
  966.     register char *s;
  967.     int CMcost, n, m;
  968.     enum move_t xm = M_NONE, ym = M_NONE;
  969.  
  970.     if (!display)
  971.     return;
  972.     if (x1 == cols || x2 == cols) {
  973.     if (x2 == cols) --x2;
  974.     goto DoCM;
  975.     }
  976.     dx = x2 - x1;
  977.     dy = y2 - y1;
  978.     if (dy == 0 && dx == 0)
  979.     return;
  980.     if (y1 == -1 || x1 == -1 || y2 >= curr->bot || y2 <= curr->top) {
  981. DoCM:
  982.     PutStr (tgoto (CM, x2, y2));
  983.     return;
  984.     }
  985.     CMcost = CalcCost (tgoto (CM, x2, y2));
  986.     if (dx > 0) {
  987.     if ((n = RewriteCost (y1, x1, x2)) < (m = dx * NDcost)) {
  988.         cost = n;
  989.         xm = M_RW;
  990.     } else {
  991.         cost = m;
  992.         xm = M_RI;
  993.     }
  994.     } else if (dx < 0) {
  995.     cost = -dx * LEcost;
  996.     xm = M_LE;
  997.     }
  998.     if (dx && (n = RewriteCost (y1, 0, x2) + CRcost) < cost) {
  999.     cost = n;
  1000.     xm = M_CR;
  1001.     }
  1002.     if (cost >= CMcost)
  1003.     goto DoCM;
  1004.     if (dy > 0) {
  1005.     cost += dy * DOcost;
  1006.     ym = M_DO;
  1007.     } else if (dy < 0) {
  1008.     cost += -dy * UPcost;
  1009.     ym = M_UP;
  1010.     }
  1011.     if (cost >= CMcost)
  1012.     goto DoCM;
  1013.     if (xm != M_NONE) {
  1014.     if (xm == M_LE || xm == M_RI) {
  1015.         if (xm == M_LE) {
  1016.         s = BC; dx = -dx;
  1017.         } else s = ND;
  1018.         while (dx-- > 0)
  1019.         PutStr (s);
  1020.     } else {
  1021.         if (xm == M_CR) {
  1022.         PutStr (CR);
  1023.         x1 = 0;
  1024.         }
  1025.         if (x1 < x2) {
  1026.         if (curr->insert)
  1027.             InsertMode (0);
  1028.         for (s = curr->image[y1]+x1; x1 < x2; x1++, s++)
  1029.             putchar (*s);
  1030.         if (curr->insert)
  1031.             InsertMode (1);
  1032.         }
  1033.     }
  1034.     }
  1035.     if (ym != M_NONE) {
  1036.     if (ym == M_UP) {
  1037.         s = UP; dy = -dy;
  1038.     } else s = DO;
  1039.     while (dy-- > 0)
  1040.         PutStr (s);
  1041.     }
  1042. }
  1043.  
  1044. static RewriteCost (y, x1, x2) {
  1045.     register cost, dx;
  1046.     register char *p = curr->attr[y]+x1, *f = curr->font[y]+x1;
  1047.  
  1048.     if (AM && y == rows-1 && x2 == cols-1)
  1049.     return EXPENSIVE;
  1050.     cost = dx = x2 - x1;
  1051.     if (dx == 0)
  1052.     return 0;
  1053.     if (curr->insert)
  1054.     cost += EIcost + IMcost;
  1055.     do {
  1056.     if (*p++ != GlobalAttr || *f++ != GlobalCharset)
  1057.         return EXPENSIVE;
  1058.     } while (--dx);
  1059.     return cost;
  1060. }
  1061.  
  1062. static BackSpace () {
  1063.     if (curr->x > 0) {
  1064.     if (curr->x < cols) {
  1065.         if (BC)
  1066.         PutStr (BC);
  1067.         else
  1068.         Goto (curr->y, curr->x, curr->y, curr->x-1);
  1069.     }
  1070.     curr->x--;
  1071.     }
  1072. }
  1073.  
  1074. static Return () {
  1075.     if (curr->x > 0) {
  1076.     curr->x = 0;
  1077.     PutStr (CR);
  1078.     }
  1079. }
  1080.  
  1081. static LineFeed () {
  1082.     if (curr->y == curr->bot) {
  1083.     ScrollUpMap (curr->image);
  1084.     ScrollUpMap (curr->attr);
  1085.     ScrollUpMap (curr->font);
  1086.     } else if (curr->y < rows-1) {
  1087.     curr->y++;
  1088.     }
  1089.     PutStr (NL);
  1090. }
  1091.  
  1092. static ReverseLineFeed () {
  1093.     if (curr->y == curr->top) {
  1094.     ScrollDownMap (curr->image);
  1095.     ScrollDownMap (curr->attr);
  1096.     ScrollDownMap (curr->font);
  1097.     if (SR) {
  1098.         PutStr (SR);
  1099.     } else if (AL) {
  1100.         Goto (curr->top, curr->x, curr->top, 0);
  1101.         PutStr (AL);
  1102.         Goto (curr->top, 0, curr->top, curr->x);
  1103.     } else Redisplay ();
  1104.     } else if (curr->y > 0) {
  1105.     CursorUp (1);
  1106.     }
  1107. }
  1108.  
  1109. static InsertAChar (c) {
  1110.     register y = curr->y, x = curr->x;
  1111.  
  1112.     if (x == cols)
  1113.     x--;
  1114.     bcopy (curr->image[y], OldImage, cols);
  1115.     bcopy (curr->attr[y], OldAttr, cols);
  1116.     bcopy (curr->font[y], OldFont, cols);
  1117.     bcopy (curr->image[y]+x, curr->image[y]+x+1, cols-x-1);
  1118.     bcopy (curr->attr[y]+x, curr->attr[y]+x+1, cols-x-1);
  1119.     bcopy (curr->font[y]+x, curr->font[y]+x+1, cols-x-1);
  1120.     SetChar (c);
  1121.     if (!display)
  1122.     return;
  1123.     if (IC || IM) {
  1124.     if (!curr->insert)
  1125.         InsertMode (1);
  1126.     PutStr (IC);
  1127.     putchar (c);
  1128.     if (!curr->insert)
  1129.         InsertMode (0);
  1130.     } else {
  1131.     RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
  1132.     ++x;
  1133.     Goto (y, last_x, y, x);
  1134.     }
  1135. }
  1136.  
  1137. static InsertChar (n) {
  1138.     register i, y = curr->y, x = curr->x;
  1139.  
  1140.     if (x == cols)
  1141.     return;
  1142.     bcopy (curr->image[y], OldImage, cols);
  1143.     bcopy (curr->attr[y], OldAttr, cols);
  1144.     bcopy (curr->font[y], OldFont, cols);
  1145.     if (n > cols-x)
  1146.     n = cols-x;
  1147.     bcopy (curr->image[y]+x, curr->image[y]+x+n, cols-x-n);
  1148.     bcopy (curr->attr[y]+x, curr->attr[y]+x+n, cols-x-n);
  1149.     bcopy (curr->font[y]+x, curr->font[y]+x+n, cols-x-n);
  1150.     ClearInLine (0, y, x, x+n-1);
  1151.     if (!display)
  1152.     return;
  1153.     if (IC || IM) {
  1154.     if (!curr->insert)
  1155.         InsertMode (1);
  1156.     for (i = n; i; i--) {
  1157.         PutStr (IC);
  1158.         putchar (' ');
  1159.     }
  1160.     if (!curr->insert)
  1161.         InsertMode (0);
  1162.     Goto (y, x+n, y, x);
  1163.     } else {
  1164.     RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
  1165.     Goto (y, last_x, y, x);
  1166.     }
  1167. }
  1168.  
  1169. static DeleteChar (n) {
  1170.     register i, y = curr->y, x = curr->x;
  1171.  
  1172.     if (x == cols)
  1173.     return;
  1174.     bcopy (curr->image[y], OldImage, cols);
  1175.     bcopy (curr->attr[y], OldAttr, cols);
  1176.     bcopy (curr->font[y], OldFont, cols);
  1177.     if (n > cols-x)
  1178.     n = cols-x;
  1179.     bcopy (curr->image[y]+x+n, curr->image[y]+x, cols-x-n);
  1180.     bcopy (curr->attr[y]+x+n, curr->attr[y]+x, cols-x-n);
  1181.     bcopy (curr->font[y]+x+n, curr->font[y]+x, cols-x-n);
  1182.     ClearInLine (0, y, cols-n, cols-1);
  1183.     if (!display)
  1184.     return;
  1185.     if (CDC && !(n == 1 && DC)) {
  1186.     CPutStr (CDC, n);
  1187.     } else if (DC) {
  1188.     for (i = n; i; i--)
  1189.         PutStr (DC);
  1190.     } else {
  1191.     RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
  1192.     Goto (y, last_x, y, x);
  1193.     }
  1194. }
  1195.  
  1196. static DeleteLine (n) {
  1197.     register i, old = curr->top;
  1198.  
  1199.     if (n > curr->bot-curr->y+1)
  1200.     n = curr->bot-curr->y+1;
  1201.     curr->top = curr->y;
  1202.     for (i = n; i; i--) {
  1203.     ScrollUpMap (curr->image);
  1204.     ScrollUpMap (curr->attr);
  1205.     ScrollUpMap (curr->font);
  1206.     }
  1207.     if (DL || CDL) {
  1208.     Goto (curr->y, curr->x, curr->y, 0);
  1209.     if (CDL && !(n == 1 && DL)) {
  1210.         CPutStr (CDL, n);
  1211.     } else {
  1212.         for (i = n; i; i--)
  1213.         PutStr (DL);
  1214.     }
  1215.     Goto (curr->y, 0, curr->y, curr->x);
  1216.     } else if (CS) {
  1217.     PutStr (tgoto (CS, curr->bot, curr->top));
  1218.     Goto (-1, -1, curr->bot, 0);
  1219.     for (i = n; i; i--)
  1220.         PutStr (SF);
  1221.     PutStr (tgoto (CS, curr->bot, old));
  1222.     Goto (-1, -1, curr->y, curr->x);
  1223.     } else Redisplay ();
  1224.     curr->top = old;
  1225. }
  1226.  
  1227. static InsertLine (n) {
  1228.     register i, old = curr->top;
  1229.  
  1230.     if (n > curr->bot-curr->y+1)
  1231.     n = curr->bot-curr->y+1;
  1232.     curr->top = curr->y;
  1233.     for (i = n; i; i--) {
  1234.     ScrollDownMap (curr->image);
  1235.     ScrollDownMap (curr->attr);
  1236.     ScrollDownMap (curr->font);
  1237.     }
  1238.     if (AL || CAL) {
  1239.     Goto (curr->y, curr->x, curr->y, 0);
  1240.     if (CAL && !(n == 1 && AL)) {
  1241.         CPutStr (CAL, n);
  1242.     } else {
  1243.         for (i = n; i; i--)
  1244.         PutStr (AL);
  1245.     }
  1246.     Goto (curr->y, 0, curr->y, curr->x);
  1247.     } else if (CS && SR) {
  1248.     PutStr (tgoto (CS, curr->bot, curr->top));
  1249.     Goto (-1, -1, curr->y, 0);
  1250.     for (i = n; i; i--)
  1251.         PutStr (SR);
  1252.     PutStr (tgoto (CS, curr->bot, old));
  1253.     Goto (-1, -1, curr->y, curr->x);
  1254.     } else Redisplay ();
  1255.     curr->top = old;
  1256. }
  1257.  
  1258. static ScrollUpMap (pp) char **pp; {
  1259.     register char *tmp = pp[curr->top];
  1260.  
  1261.     bcopy ((char *)(pp+curr->top+1), (char *)(pp+curr->top),
  1262.     (curr->bot-curr->top) * sizeof (char *));
  1263.     if (pp == curr->image)
  1264.     bclear (tmp, cols);
  1265.     else
  1266.     bzero (tmp, cols);
  1267.     pp[curr->bot] = tmp;
  1268. }
  1269.  
  1270. static ScrollDownMap (pp) char **pp; {
  1271.     register char *tmp = pp[curr->bot];
  1272.  
  1273.     bcopy ((char *)(pp+curr->top), (char *)(pp+curr->top+1),
  1274.     (curr->bot-curr->top) * sizeof (char *));
  1275.     if (pp == curr->image)
  1276.     bclear (tmp, cols);
  1277.     else
  1278.     bzero (tmp, cols);
  1279.     pp[curr->top] = tmp;
  1280. }
  1281.  
  1282. static ForwardTab () {
  1283.     register x = curr->x;
  1284.  
  1285.     if (curr->tabs[x] && x < cols-1)
  1286.     ++x;
  1287.     while (x < cols-1 && !curr->tabs[x])
  1288.     x++;
  1289.     Goto (curr->y, curr->x, curr->y, x);
  1290.     curr->x = x;
  1291. }
  1292.  
  1293. static BackwardTab () {
  1294.     register x = curr->x;
  1295.  
  1296.     if (curr->tabs[x] && x > 0)
  1297.     x--;
  1298.     while (x > 0 && !curr->tabs[x])
  1299.     x--;
  1300.     Goto (curr->y, curr->x, curr->y, x);
  1301.     curr->x = x;
  1302. }
  1303.  
  1304. static ClearScreen () {
  1305.     register i;
  1306.  
  1307.     PutStr (CL);
  1308.     for (i = 0; i < rows; ++i) {
  1309.     bclear (curr->image[i], cols);
  1310.     bzero (curr->attr[i], cols);
  1311.     bzero (curr->font[i], cols);
  1312.     }
  1313. }
  1314.  
  1315. static ClearFromBOS () {
  1316.     register n, y = curr->y, x = curr->x;
  1317.  
  1318.     for (n = 0; n < y; ++n)
  1319.     ClearInLine (1, n, 0, cols-1);
  1320.     ClearInLine (1, y, 0, x);
  1321.     Goto (curr->y, curr->x, y, x);
  1322.     curr->y = y; curr->x = x;
  1323. }
  1324.  
  1325. static ClearToEOS () {
  1326.     register n, y = curr->y, x = curr->x;
  1327.  
  1328.     if (CD)
  1329.     PutStr (CD);
  1330.     ClearInLine (!CD, y, x, cols-1);
  1331.     for (n = y+1; n < rows; n++)
  1332.     ClearInLine (!CD, n, 0, cols-1);
  1333.     Goto (curr->y, curr->x, y, x);
  1334.     curr->y = y; curr->x = x;
  1335. }
  1336.  
  1337. static ClearLine () {
  1338.     register y = curr->y, x = curr->x;
  1339.  
  1340.     ClearInLine (1, y, 0, cols-1);
  1341.     Goto (curr->y, curr->x, y, x);
  1342.     curr->y = y; curr->x = x;
  1343. }
  1344.  
  1345. static ClearToEOL () {
  1346.     register y = curr->y, x = curr->x;
  1347.  
  1348.     ClearInLine (1, y, x, cols-1);
  1349.     Goto (curr->y, curr->x, y, x);
  1350.     curr->y = y; curr->x = x;
  1351. }
  1352.  
  1353. static ClearFromBOL () {
  1354.     register y = curr->y, x = curr->x;
  1355.  
  1356.     ClearInLine (1, y, 0, x);
  1357.     Goto (curr->y, curr->x, y, x);
  1358.     curr->y = y; curr->x = x;
  1359. }
  1360.  
  1361. static ClearInLine (displ, y, x1, x2) {
  1362.     register i, n;
  1363.  
  1364.     if (x1 == cols) x1--;
  1365.     if (x2 == cols) x2--;
  1366.     if (n = x2 - x1 + 1) {
  1367.     bclear (curr->image[y]+x1, n);
  1368.     bzero (curr->attr[y]+x1, n);
  1369.     bzero (curr->font[y]+x1, n);
  1370.     if (displ && display) {
  1371.         if (x2 == cols-1 && CE) {
  1372.         Goto (curr->y, curr->x, y, x1);
  1373.         curr->y = y; curr->x = x1;
  1374.         PutStr (CE);
  1375.         return;
  1376.         }
  1377.         if (y == rows-1 && AM)
  1378.         --n;
  1379.         if (n == 0)
  1380.         return;
  1381.         SaveAttr (0);
  1382.         Goto (curr->y, curr->x, y, x1);
  1383.         for (i = n; i > 0; i--)
  1384.         putchar (' ');
  1385.         curr->y = y; curr->x = x1 + n;
  1386.         RestoreAttr (0);
  1387.     }
  1388.     }
  1389. }
  1390.  
  1391. static CursorRight (n) register n; {
  1392.     register x = curr->x;
  1393.  
  1394.     if (x == cols)
  1395.     return;
  1396.     if ((curr->x += n) >= cols)
  1397.     curr->x = cols-1;
  1398.     Goto (curr->y, x, curr->y, curr->x);
  1399. }
  1400.  
  1401. static CursorUp (n) register n; {
  1402.     register y = curr->y;
  1403.  
  1404.     if ((curr->y -= n) < curr->top)
  1405.     curr->y = curr->top;
  1406.     Goto (y, curr->x, curr->y, curr->x);
  1407. }
  1408.  
  1409. static CursorDown (n) register n; {
  1410.     register y = curr->y;
  1411.  
  1412.     if ((curr->y += n) > curr->bot)
  1413.     curr->y = curr->bot;
  1414.     Goto (y, curr->x, curr->y, curr->x);
  1415. }
  1416.  
  1417. static CursorLeft (n) register n; {
  1418.     register x = curr->x;
  1419.  
  1420.     if ((curr->x -= n) < 0)
  1421.     curr->x = 0;
  1422.     Goto (curr->y, x, curr->y, curr->x);
  1423. }
  1424.  
  1425. static SetMode (on) {
  1426.     register i;
  1427.  
  1428.     for (i = 0; i < curr->NumArgs; ++i) {
  1429.     switch (curr->args[i]) {
  1430.     case 4:
  1431.         curr->insert = on;
  1432.         InsertMode (on);
  1433.         break;
  1434.     }
  1435.     }
  1436. }
  1437.  
  1438. static SelectRendition () {
  1439.     register i, old = GlobalAttr;
  1440.  
  1441.     if (curr->NumArgs == 0)
  1442.     SetRendition (0);
  1443.     else for (i = 0; i < curr->NumArgs; ++i)
  1444.     SetRendition (curr->args[i]);
  1445.     NewRendition (old, GlobalAttr);
  1446. }
  1447.  
  1448. static SetRendition (n) register n; {
  1449.     switch (n) {
  1450.     case 0:
  1451.     GlobalAttr = 0; break;
  1452.     case 1:
  1453.     GlobalAttr |= A_BD; break;
  1454.     case 2:
  1455.     GlobalAttr |= A_DI; break;
  1456.     case 3:
  1457.     GlobalAttr |= A_SO; break;
  1458.     case 4:
  1459.     GlobalAttr |= A_US; break;
  1460.     case 5:
  1461.     GlobalAttr |= A_BL; break;
  1462.     case 7:
  1463.     GlobalAttr |= A_RV; break;
  1464.     case 22:
  1465.     GlobalAttr &= ~(A_BD|A_SO|A_DI); break;
  1466.     case 23:
  1467.     GlobalAttr &= ~A_SO; break;
  1468.     case 24:
  1469.     GlobalAttr &= ~A_US; break;
  1470.     case 25:
  1471.     GlobalAttr &= ~A_BL; break;
  1472.     case 27:
  1473.     GlobalAttr &= ~A_RV; break;
  1474.     }
  1475.     curr->LocalAttr = GlobalAttr;
  1476. }
  1477.  
  1478. static NewRendition (old, new) register old, new; {
  1479.     register i;
  1480.  
  1481.     if (old == new)
  1482.     return;
  1483.     for (i = 1; i <= A_MAX; i <<= 1) {
  1484.     if ((old & i) && !(new & i)) {
  1485.         PutStr (UE);
  1486.         PutStr (SE);
  1487.         PutStr (ME);
  1488.         if (new & A_US) PutStr (US);
  1489.         if (new & A_SO) PutStr (SO);
  1490.         if (new & A_BL) PutStr (MB);
  1491.         if (new & A_BD) PutStr (MD);
  1492.         if (new & A_DI) PutStr (MH);
  1493.         if (new & A_RV) PutStr (MR);
  1494.         return;
  1495.     }
  1496.     }
  1497.     if ((new & A_US) && !(old & A_US))
  1498.     PutStr (US);
  1499.     if ((new & A_SO) && !(old & A_SO))
  1500.     PutStr (SO);
  1501.     if ((new & A_BL) && !(old & A_BL))
  1502.     PutStr (MB);
  1503.     if ((new & A_BD) && !(old & A_BD))
  1504.     PutStr (MD);
  1505.     if ((new & A_DI) && !(old & A_DI))
  1506.     PutStr (MH);
  1507.     if ((new & A_RV) && !(old & A_RV))
  1508.     PutStr (MR);
  1509. }
  1510.  
  1511. static SaveAttr (newattr) {
  1512.     NewRendition (GlobalAttr, newattr);
  1513.     NewCharset (GlobalCharset, ASCII);
  1514.     if (curr->insert)
  1515.     InsertMode (0);
  1516. }
  1517.  
  1518. static RestoreAttr (oldattr) {
  1519.     NewRendition (oldattr, GlobalAttr);
  1520.     NewCharset (ASCII, GlobalCharset);
  1521.     if (curr->insert)
  1522.     InsertMode (1);
  1523. }
  1524.  
  1525. static FillWithEs () {
  1526.     register i;
  1527.     register char *p, *ep;
  1528.  
  1529.     curr->y = curr->x = 0;
  1530.     SaveAttr (0);
  1531.     for (i = 0; i < rows; ++i) {
  1532.     bzero (curr->attr[i], cols);
  1533.     bzero (curr->font[i], cols);
  1534.     p = curr->image[i];
  1535.     ep = p + cols;
  1536.     for ( ; p < ep; ++p)
  1537.         *p = 'E';
  1538.     }
  1539.     RestoreAttr (0);
  1540.     Redisplay ();
  1541. }
  1542.  
  1543. static Redisplay () {
  1544.     register i;
  1545.  
  1546.     PutStr (CL);
  1547.     TmpAttr = GlobalAttr;
  1548.     TmpCharset = GlobalCharset;
  1549.     InsertMode (0);
  1550.     last_x = last_y = 0;
  1551.     for (i = 0; i < rows; ++i)
  1552.     DisplayLine (blank, null, null, curr->image[i], curr->attr[i],
  1553.         curr->font[i], i, 0, cols-1);
  1554.     if (curr->insert)
  1555.     InsertMode (1);
  1556.     NewRendition (TmpAttr, GlobalAttr);
  1557.     NewCharset (TmpCharset, GlobalCharset);
  1558.     Goto (last_y, last_x, curr->y, curr->x);
  1559. }
  1560.  
  1561. static DisplayLine (os, oa, of, s, as, fs, y, from, to)
  1562.     register char *os, *oa, *of, *s, *as, *fs; {
  1563.     register i, x, a, f;
  1564.  
  1565.     if (to == cols)
  1566.     --to;
  1567.     if (AM && y == rows-1 && to == cols-1)
  1568.     --to;
  1569.     a = TmpAttr;
  1570.     f = TmpCharset;
  1571.     for (x = i = from; i <= to; ++i, ++x) {
  1572.     if (s[i] == os[i] && as[i] == oa[i] && as[i] == a
  1573.                   && of[i] == fs[i] && fs[i] == f)
  1574.         continue;
  1575.     Goto (last_y, last_x, y, x);
  1576.     last_y = y;
  1577.     last_x = x;
  1578.     if ((a = as[i]) != TmpAttr) {
  1579.         NewRendition (TmpAttr, a);
  1580.         TmpAttr = a;
  1581.     }
  1582.     if ((f = fs[i]) != TmpCharset) {
  1583.         NewCharset (TmpCharset, f);
  1584.         TmpCharset = f;
  1585.     }
  1586.     putchar (s[i]);
  1587.     last_x++;
  1588.     }
  1589. }
  1590.  
  1591. static RedisplayLine (os, oa, of, y, from, to) char *os, *oa, *of; {
  1592.     if (curr->insert)
  1593.     InsertMode (0);
  1594.     NewRendition (GlobalAttr, 0);
  1595.     TmpAttr = 0;
  1596.     NewCharset (GlobalCharset, ASCII);
  1597.     TmpCharset = ASCII;
  1598.     last_y = y;
  1599.     last_x = from;
  1600.     DisplayLine (os, oa, of, curr->image[y], curr->attr[y],
  1601.     curr->font[y], y, from, to);
  1602.     NewRendition (TmpAttr, GlobalAttr);
  1603.     NewCharset (TmpCharset, GlobalCharset);
  1604.     if (curr->insert)
  1605.     InsertMode (1);
  1606. }
  1607.  
  1608. static MakeBlankLine (p, n) register char *p; register n; {
  1609.     do *p++ = ' ';
  1610.     while (--n);
  1611. }
  1612.  
  1613. MakeStatus (msg, wp) char *msg; struct win *wp; {
  1614.     struct win *ocurr = curr;
  1615.     int odisplay = display;
  1616.     register char *s, *t;
  1617.     register max = AM ? cols-1 : cols;
  1618.  
  1619.     for (s = t = msg; *s && t - msg < max; ++s)
  1620.     if (*s >= ' ' && *s <= '~')
  1621.         *t++ = *s;
  1622.     *t = '\0';
  1623.     curr = wp;
  1624.     display = 1;
  1625.     if (status) {
  1626.     if (time ((time_t *)0) - TimeDisplayed < 2)
  1627.         sleep (1);
  1628.     RemoveStatus (wp);
  1629.     }
  1630.     if (t > msg) {
  1631.     status = 1;
  1632.     StatLen = t - msg;
  1633.     Goto (curr->y, curr->x, rows-1, 0);
  1634.     SaveAttr (A_SO);
  1635.     printf ("%s", msg);
  1636.     RestoreAttr (A_SO);
  1637.     (void) fflush (stdout);
  1638.     time (&TimeDisplayed);
  1639.     }
  1640.     curr = ocurr;
  1641.     display = odisplay;
  1642. }
  1643.  
  1644. RemoveStatus (p) struct win *p; {
  1645.     struct win *ocurr = curr;
  1646.     int odisplay = display;
  1647.  
  1648.     if (!status)
  1649.     return;
  1650.     status = 0;
  1651.     curr = p;
  1652.     display = 1;
  1653.     Goto (-1, -1, rows-1, 0);
  1654.     RedisplayLine (null, null, null, rows-1, 0, StatLen);
  1655.     Goto (rows-1, last_x, curr->y, curr->x);
  1656.     curr = ocurr;
  1657.     display = odisplay;
  1658. }
  1659.