home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume10 / screen / part01 / ansi.c next >
C/C++ Source or Header  |  1987-08-06  |  30KB  |  1,447 lines

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