{PASCAL PROGRAM TO MAKE CONCEPT LOOK LIKE A TERMINAL :
        IT READS FROM THE KEYBOARD (USER INPUT)
                AND WRITES TO THE DATACOM2 PORT
        IT READS FROM THE DATACOM2 PORT
                AND WRITES TO THE CONSOLE
}
{ who          date            mod                             }
{ rpk          11/1            initial release
  ?            11/4            mod for baud
  rpk          11/9            mod to only listen to control c from kbrd
  rpk           1/16           major renovation for vt100 lookalike
                                   CURRENT VERSION ONLY EMULATES THE HOST TO TERMINAL DIRECTION. NEXT VERSION
                                   WILL ALSO PROVIDE TERMINAL TO HOST EMULATION.
  rpk           2/7            modified to new(1.1) display driver - also handles perverse echo
                               problem(does not xmit char if incoming escape is pendingcompletion)
}
{NOTES:     The concept obviously treats a "CR" like a "CR" "LF" hence anybody thinking its talking to a
normal terminal will send a cr lf and get  effectively cr lf lf!!  Hence there is code to search for a
cr and mark it so that an immediately following lf can e dealt with in one of a number of ways depending on
the mode selected(usually ignored).  The most usual interpretation of cr lf sent to a trerminal is as a nl
hence only the cr will be issued to the console. SOMEBODY please find a way to defeat this.


vt100 emulation is incoming only -outgoing is pending based on what corvus' desires are.




}
PROGRAM TTY;
{                      NB:  many of the variables are world global because of the hassle of
                            initialization - you only want to do it once.

}


CONST

        KBRD  =   35;   {KEYBOARD UNIT }
        DCOM  =   32;   {DATACOMM UNIT }
        CONS  =   1;    {CONSOLE  CRT }

        CMAX  =   30;   {MAX NUMBER OF CHARACTERS ALLOWED IN ESCAPE SEQUENCE}

        UNDR = 72;    {UNDERSCORE BIT ENCODED FOR ESC e}
        BOLD = 65;    {BOLD FACE BIT ENCODED}
        ATOFF = 64;   {ATTRIBUTES OFF}
        BLNK =  64;   {NO BLINK}
        INVRS= 68;   {REVERSE VIDEO}


        CR = '\0D';            CAN = '\18';            SUB = '\1A';
        ESC = '\1B';           CTRMON = '\1D';   {SET MONITOR MODE CTRL ]}
        LF = '\0A';            LBRK = '\5B';           OH = '\4F';
        NBS = '\23';           DOT = '\2E';
        LPRN = '\28';          RPRN = '\29';           CTRLC = '\03';
        EQU = '\3D';           US = '\1F';
        SEMI = '\3B';          SMLE  = '\65';

                                          {NOTE VT52 INTERFACE is fairly trivial -hence does not
                                          have all the hoo hah as for vt100 -see look52}
TYPE

       SEQ = (CSI,AUX,DECP,G0C,G1C,SMPL,NULL);   {The type of escape sequence found :
                                                       csi =  standard control seq initialiser esc[
                                                       aux = auxiliary keypad mode             escO
                                                       decp = dec private mode                 esc#
                                                       g0c = character select mode             esc(
                                                       g1c = character select mode             esc)
                                                       smpl = simple escape sequence           esc
                                                       null = no escape sequence found
                                                       }
       EMUL = (VT52,VT100,NONE);  {TYPE OF EMULATION BEING PROVIDED}
       TRM = SET OF CHAR;
       BFR = PACKED ARRAY [0..CMAX] OF CHAR;
       SMLBF = PACKED ARRAY [0..1] OF CHAR;
VAR

        RTRN :BOOLEAN;  {SET IF LAST CHARACTER WAS A CARRIAGE RETURN}

        MON : BOOLEAN; {SIMPLISTIC MONITOR MODE}
        CSITRM,AUXTRM,DECTRM,G0CTRM,G1CTRM,SMPTRM,NULTRM,STRTUP : TRM;
        TERMINAL : EMUL;
        C: CHAR;
        FESC : BOOLEAN;  {TRUE IF AN ESCAPE CODE IS FOUND IN STREAM FROM HOST}
        ASEQ : SEQ;      { A GIANT SWITCH VARIABLE}

        CH:SMLBF;        {CHARACTER THAT IS  WRIT}
        CH1:SMLBF;        {CHARACTER THAT IS READ }
        mm:SMLBF;        {debugger}
        CHOLD:BFR;   {HOLDS RAW HOST TO TERMINAL ESCAPE SEQUENCE}
        CSCR:BFR;    {HOLDS TRANSLATED ESCAPE SEQUENCE -HOST TO TERMINAL}
        CKEY:BFR;    {HOLDS RAW KEYBOARD TO HOST ESCAPE SEQUENCES}
        CHST:BFR;   {HOLDS TRANSLATED SEQUENCE -CORVUS TO EMULATED TERMINAL TO HOST}

        XHOLD,XSCR,XKEY,XHST: 0..CMAX;    {INDEX INTO RESPECTIVER BUFFERS}


{************************************************************************************************************}

{PROCEDURES NOW DEFINED}


PROCEDURE PUTSCREEN(C:CHAR);   { PUTS A CHARACTER OUT TO SCREEN AFTER REVIEWING CR/LF STATUS}
forward;
PROCEDURE LOOK100(C:CHAR);     {LOOK FOR A VT100 ESCAPE SEQUENCE}
forward;
PROCEDURE LOOK52(C:CHAR);      {look for a vt52 escape sequence}
forward;
PROCEDURE FLUSHOLD;            {FLUSH THE ESCAPE STREAM TO SCREEN BECUZ OF ERROR IN TRANSLATION}
forward;
PROCEDURE CSIPROC(C:CHAR);     {PROCESS A CSI ESCAPE SEQUENCE}
forward;
PROCEDURE AUXPROC(C:CHAR);     {PROCESS AN AUX ESCAPE SEQUENCE}
forward;
PROCEDURE DECPROC(C:CHAR);     {PROCESS A DEC ESCAPE SEQUENCE}
forward;
PROCEDURE G0CPROC(C:CHAR);     {PROCESS A G0C ESCAPE SEQUENCE}
forward;
PROCEDURE G1CPROC(C:CHAR);     {PROCESS A G1C ESCAPE SEQUENCE}
forward;
PROCEDURE SMPPROC(C:CHAR);     {PROCESS A SMP ESCAPE SEQUENCE}
forward;
procedure cursmov(c:char); {set up escape buffer for cursor moving and mopve cursor}
forward;
PROCEDURE PUTESC(C:CHAR);  {PUT ESCAPE "SEQUENCE" INTO HOLDING PEN UNTIL SEQUENCE IS COMPLETE}
forward;
PROCEDURE CANESC;   {CANCELS A HOST TO TERMINAL  ESCAPE SEQUENCE }
forward;
FUNCTION FINDNXT(VAR QQ:BFR; CC:CHAR;IBEG,IEND:INTEGER):INTEGER; {starting at ibeg search for cc in qq until
                                                                 iend is reached and return position }
forward;
FUNCTION CONVSTR(IBEG,IEND:INTEGER;QQ:BFR):INTEGER;
forward;                      {convert a character string in qq between ibeg and iend to an integer --eg.
                               6260 are two characters representing 20 -which is the desired decimal output}

FUNCTION CHARENHANCE(X:INTEGER):CHAR; {CONVERTS A CHARACTER AT POSITION X IN CHOLD TO CONCEPT CHAR
                                       ENHANCEMENT}

forward;
{****************************************************************************************************}

FUNCTION CHARENHANCE;
 BEGIN
  CASE CHOLD[X] OF
    '0':
       CHARENHANCE := CHR(ATOFF);
    '1':
       CHARENHANCE := CHR(BOLD);
    '4':
       CHARENHANCE := CHR(UNDR);
    '5':
       CHARENHANCE := CHR(BLNK);
    '7':
       CHARENHANCE := CHR(INVRS);
    OTHERWISE:
       CHARENHANCE := CHR(ATOFF);
  END
END;



FUNCTION FINDNXT;  {FIND OCCURRENCE OD CHARACTER IN STRING}
 LABEL

 10;

 VAR
   I,J:INTEGER;

 BEGIN
   FINDNXT := -1;
   FOR I := IBEG  TO IEND DO
    BEGIN
     IF QQ[I] = CC
       THEN
        BEGIN
         FINDNXT := I;
         GOTO 10
        END;
    END;
10:
END;


FUNCTION CONVSTR; {COVERT A STRING OF 3 CHARS OR LESS TO DECIMAL EQUIVALENT}
LABEL
 10;

VAR
 I,J,K:INTEGER;

BEGIN
I := IEND -IBEG;
K := 100;

 IF I > 2
  THEN
   BEGIN
    WRITELN('BAD CONVERSION',I);
    CONVSTR := -1;
    GOTO 10
   END
  ELSE IF I = 1
    THEN K := 10
  ELSE IF I = 0
    THEN K := 1 ;

I := 0;
FOR J := IBEG TO IEND  DO
 BEGIN

  I := I + ((ord(QQ[J]) - ord('0')) * K);
  K := K DIV 10;
 END;       {FOR}
{write('conv--',I);}
CONVSTR := I;
10:
 END; {FINISH CONVSTR}


PROCEDURE PUTSCREEN;   { PUTS A CHARACTER OUT TO SCREEN AFTER REVIEWING CR/LF STATUS}
 BEGIN
   IF C = CR
     THEN
       BEGIN
        RTRN := TRUE;
        UNITWRITE(CONS,CH1,1);      {WRITE TO SCREEN}
       END
     ELSE IF (C = LF) AND (RTRN = TRUE)
      THEN RTRN := FALSE
     ELSE
       BEGIN
        RTRN := FALSE;
        UNITWRITE(CONS,CH1,1);      {WRITE TO SCREEN}
       END
  END;


{-------------------------------------------------------------------}

PROCEDURE LOOK100;     {LOOK FOR A VT100 ESCAPE SEQUENCE}

VAR

 CC:CHAR;


BEGIN
 CASE ASEQ OF

   NULL:    {USUALLY ONLY ENTERED THE VERY FIRST TIME IN ANB ESCAPE SEQUENCE}
    BEGIN
     CC := CHOLD[1];   {IN AN ESCAPE SEQUENCE THIS CHARACTER IS THE DISCRIMINATOR --EG.  CHOLD[0]
                         IS "ESC" AND CC IS WHAT MAKES A UNIQUE DISCRIMINATOR}

     CASE CC OF
      LBRK:            {CSI ESCAPE SEQUENCE}
       ASEQ := CSI;
      OH:              {AUXILIARY KEYPAD ESCAPE SEQUENCE}
       ASEQ := AUX;
      NBS:             {DEC PRIVATE ESCAPE SEQUENCE}
       ASEQ := DECP;
      LPRN:            {CHANGE CHARACTER SET MODE 0}
       ASEQ := G0C;
      RPRN:            {CHANGE CHARACTER SET MODE 1}
       ASEQ := G1C;
      OTHERWISE:       {ASSUME A SIMPLKE ESCAPE SEQUENCE}
       ASEQ := SMPL;
     END   {CASE CC OF}
    END;

   CSI:              {WE HAVE CSI SEQ -SEE IF IT IS COMPLETELY INPUT YET}
     begin
{     write('lookcsi',c);     }
     IF C IN CSITRM
       THEN  CSIPROC(C)
       ELSE IF XHOLD >= CMAX
        THEN FLUSHOLD;        {SOMETHING IS WRONG -SIMPLY DUMP ESCAPE STREAM TO SCREEN!!!}
     end;

   AUX:              {WE HAVE AUX SEQ -SEE IF IT IS COMPLETELY INPUT YET}
     IF C IN AUXTRM
       THEN  AUXPROC(C)
       ELSE IF XHOLD >= CMAX
        THEN FLUSHOLD;        {SOMETHING IS WRONG -SIMPLY DUMP ESCAPE STREAM TO SCREEN!!!}



   DECP:             {WE HAVE DECP SEQ -SEE IF IT IS COMPLETELY INPUT YET}
     IF C IN DECTRM
       THEN  DECPROC(C)
       ELSE IF XHOLD >= CMAX
        THEN FLUSHOLD;        {SOMETHING IS WRONG -SIMPLY DUMP ESCAPE STREAM TO SCREEN!!!}



   G0C:              {WE HAVE G0C SEQ -SEE IF IT IS COMPLETELY INPUT YET}
     IF C IN G0CTRM
       THEN  G0CPROC(C)
       ELSE IF XHOLD >= CMAX
        THEN FLUSHOLD;        {SOMETHING IS WRONG -SIMPLY DUMP ESCAPE STREAM TO SCREEN!!!}



   G1C:              {WE HAVE G1C SEQ -SEE IF IT IS COMPLETELY INPUT YET}
     IF C IN G1CTRM
       THEN  G1CPROC(C)
       ELSE IF XHOLD >= CMAX
        THEN FLUSHOLD;        {SOMETHING IS WRONG -SIMPLY DUMP ESCAPE STREAM TO SCREEN!!!}



   SMPL:             {WE HAVE SMPL SEQ -SEE IF IT IS COMPLETELY INPUT YET}
     IF C IN SMPTRM
       THEN  SMPPROC(C)
       ELSE IF XHOLD >= CMAX
        THEN FLUSHOLD;        {SOMETHING IS WRONG -SIMPLY DUMP ESCAPE STREAM TO SCREEN!!!}

 END    {CASE}
END;    {LOOK100}


{=========================================================================================================
             BELOW ARE THE VARIOUS ESCAPE SEQUENCE PROCESSING ROUTINES
}

PROCEDURE AUXPROC;
 BEGIN
  FLUSHOLD;
 END;

PROCEDURE DECPROC;
 BEGIN
  FLUSHOLD;
 END;

PROCEDURE G0CPROC;
 BEGIN
  FLUSHOLD;
 END;

PROCEDURE G1CPROC;
 BEGIN
  FLUSHOLD;
 END;

PROCEDURE SMPPROC;
 BEGIN
  FLUSHOLD;
 END;

{******************************************************************************************************}

PROCEDURE LOOK52;
 LABEL
  10;

 var
  cc:char;

 BEGIN
  IF XHOLD < 2         {IF SO THEN AN ESC SEQ NOT HAD}
   THEN GOTO 10
   ELSE
    BEGIN
    CC := CHOLD[1];
    CASE CC OF

   'A':   {CURSOR UP}
     BEGIN
      CSCR[0] := ESC;
      CSCR[1] := CC;
      UNITWRITE(CONS,CSCR,2);
     END;

   'B':   {CURSOR DOWN}
     BEGIN
      CSCR[0] := ESC;
      CSCR[1] := CC;
      UNITWRITE(CONS,CSCR,2);
     END;

   'C':   {CURSOR RIGHT}
     BEGIN
      CSCR[0] := ESC;
      CSCR[1] := CC;
      UNITWRITE(CONS,CSCR,2);
     END;

   'D':   {CURSOR LEFT}
     BEGIN
      CSCR[0] := ESC;
      CSCR[1] := CC;
      UNITWRITE(CONS,CSCR,2);
     END;

   'F':   {ENTER GRAPHICS MODE -TO BE DONE}
     BEGIN
      FLUSHOLD;
     END;

   'G':   {EXIT GRAPHICS MODE - TO BE  DONE}
     BEGIN
      FLUSHOLD;
     END;

   'H':   {CURSOR TO HOME}
     BEGIN
      CSCR[0] := ESC;
      CSCR[1] := CC;
      UNITWRITE(CONS,CSCR,2);
     END;

   'I':   {REVERSE LINE FEED -TEMPORARILY LIKE ESC A}
     BEGIN
      CSCR[0] := ESC;
      CSCR[1] := 'A';
      UNITWRITE(CONS,CSCR,2);
     END;

   'J':   {CLEAR TO END OF SCREEN}
     BEGIN
      CSCR[0] := ESC;
      CSCR[1] := 'Y';
      UNITWRITE(CONS,CSCR,2);
     END;

   'K':   {ERASE TO END OF LINE}
     BEGIN
      CSCR[0] := ESC;
      CSCR[1] := CC;
      UNITWRITE(CONS,CSCR,2);
     END;

   'Z':   {SEND ID SEQUENCE}
     BEGIN
      CSCR[0] := ESC;
      CSCR[1] := '/';
      CSCR[2] := 'Z';
      UNITWRITE(DCOM,CSCR,3);
      CANESC;
     END;

   '=':   {ENTER ALTERNATE KEYPAD MODE -- TO BE DONE}
     BEGIN
      FLUSHOLD;
     END;

   '>':   {EXITR ALTERNATE KEYPAD MODE -TO BE DONE}
     BEGIN
      FLUSHOLD;
     END;

   '<':   {ENTER VT100 MODE}
     BEGIN
      TERMINAL := VT100;
      CANESC;
     END;

   'Y':   {CURSOR ADDRESSING INPUT IS ROW COL -CONCEPT OUT IS COL ROW}
     BEGIN
     {write('aty',xhold,fesc); }
      IF XHOLD < 4
        THEN GOTO 10
        ELSE
         BEGIN
          CSCR[0] := ESC;
          CSCR[1] := EQU;
          CSCR[2] := CHR(ORD(CHOLD[3]) - ORD(US)); {COLUMN}
          CSCR[3] := CHR(ORD(CHOLD[2]) - ORD(US)); {ROW}
          UNITWRITE(CONS,CSCR,4);
         END
     END;
   OTHERWISE:
      ;

   END    {CASE}
  END; {ELSE}
    CANESC;
 10:

 END;

PROCEDURE CSIPROC;  {PROCESS CSI ESCAPE SEQUENCES}
 label

10;


 var

   i,j,k,l,m : integer;

 begin
  {write('csiproc ',c,xhold); }
   case c of  {based on last character of escape sequence}

    'A':                        {cursor up -  esc [ # A}
      cursmov('A');
    'B':                        {cursor down - esc [ # B}
      cursmov('B');
    'C':                        {cursor forward - esc [ # C}
      cursmov('C');
    'D':                        {cursor backward - esc [ # D}
      cursmov('D');
    'H':
    10:                    {position cursor - esc [ row ; col H -corvus is - esc = col row}
      BEGIN
      cscr[0] := esc;  {set up output escape buffer}
      cscr[1] := equ;
      i := findnxt(chold,semi,2,5);
      if (i <= 2) or (xhold <= 4) {then simplistic origin}
       then
        begin
         cscr[2] := '\01';    {reset to origin???}
         cscr[3] := '\01'
        end
       else
        begin
         j := i -1;  {preparte to convert row}
         k := convstr(2,j,chold);
         cscr[3] := chr(k);
        {write('row--',k);}
           {now convert from other side of semi colon to end}
         k := 0;
         j := i+1;
         i := xhold - 2; {last position of number}
         k := convstr(j,i,chold);
         cscr[2] := chr(k);
        {write('col--',k); }
        end;
        unitwrite(cons,cscr,4);
        canesc;
      END;
   'J':                         {erase IN WINDOW      - esc [ * J   for * =0 erase to eos
                                                                            1 erase from bos
                                                                            2 erase display}
       BEGIN
        cscr[0] := esc;
        case chold[2] of
        '1':             {ERASE FROM BEGINNING OF SCREEN TO CURRENT POSITION -LEAVE CURSOR}
           ;      {to be done}
        '2':             {ERASE entire SCREEN }
          BEGIN
           cscr[1] := 'J';
           unitwrite(cons,cscr,2);
          END;
         OTHERWISE:
                     {ERASE FROM HERE TO END OF SCREEN  -LEAVE CURSOR}
          BEGIN
           cscr[1] := 'Y';
           unitwrite(cons,cscr,2);
          END;
        END;     {case}
        canesc;
      END; {J}

     'K':              {erase in line  - esc { * K          ----- * = 0   erase to end of line
                                                                    = 1   erase from beginning of line
                                                                    = 2   erase line}

       BEGIN
        cscr[0] := esc;
        CASE chold[2] OF
        '1':             {ERASE FROM BEGINNING OF line TO CURRENT POSITION -LEAVE CURSOR}
           ;      {to be done}
        '2':             {ERASE entire line}
           ;      {to be done}
         OTHERWISE:   {default  erase from cursor to end of line}
          BEGIN
           cscr[1] := 'K';
           unitwrite(cons,cscr,2);
          END;
        END;     {case}
        canesc;
      END; {K}

     'c':                 {report device attributes  --currently not implemented}
        flushold;

     'f':                 {for current purposes, same as H above}
        goto 10;

     'g':                 {tab clear modes ---eventually have to simulate}
        flushold;

     'h':                 {set internal modes}
        flushold;         {to be done}

     'l':                 {reset internal modes --- to be done}
        flushold;

     'm':                 {select graphic rendition  -  esc [ #;..;# m   or esc [ # m}
       BEGIN
        CSCR[0] := ESC;   {SET UP OUTPUT BUFFER}
        CSCR[1] := SMLE;
        J := 2;
        WHILE J < XHOLD DO
         BEGIN
          CSCR[2] := CHARENHANCE(J);
          UNITWRITE(CONS,CSCR,3);
          J := J+2;
         END
       END;

     'n':                 {device   status report -to be done  esc [ * n  * = 5 then report status as either
                                                                       esc [ 0 n or esc [ 3 n
                                                                          * = 6 then report status as
                                                                          esc [ row; col R

        flushold;

     'q':                 {load led displays - not implemented }
        flushold;

     'x':                 {request to sent terminal parameters --- to be done}
        flushold;

     'y':                 {invoke confidence tests??? - not implemented}
        flushold;
  end;          { case }
  canesc;
END;  {procedure}

procedure cursmov; {set up escape buffer for cursor moving and mopve cursor}
const
 n = 2;
var
 i,j,k:integer;

begin
  cscr[0] := esc;
  cscr[1] := c;

  k := xhold - 2;  {position of last char of parameter if any}
  if xhold <= 3
    then i := 1    {only one position moved}
    else i := convstr(2,k,chold);

  for j := 1 to i do
    unitwrite(cons,cscr,2)
end; {cursmov}



PROCEDURE PUTESC;  {PUT ESCAPE "SEQUENCE" INTO HOLDING PEN UNTIL SEQUENCE IS COMPLETE}
 BEGIN
   {WRITE('PUTESC ',C);  }
   CHOLD[XHOLD] := C;
   XHOLD := XHOLD + 1;


   CASE TERMINAL OF
     VT52:
       LOOK52(C);
     VT100:
       LOOK100(C);
     NONE:
       PUTSCREEN(C);
     OTHERWISE:
       PUTSCREEN('?');
    END;
 END;




PROCEDURE CANESC;   {CANCELS A HOST TO TERMINAL  ESCAPE SEQUENCE }
 BEGIN
   ASEQ := NULL;
   FESC := FALSE;
   XHOLD := 0;
   XSCR  := 0;
 END;

PROCEDURE MONITOR(VAR MC:SMLBF);
 BEGIN
  IF MC[0] = ESC
   THEN MC[0] := DOT
 END;

PROCEDURE FLUSHOLD; {DUMP CHOLD TO SCREEN -RESET PARAMETERS}
 BEGIN
  CANESC;
 END;
{************************************************************************************************************}

BEGIN     {VT52/100 EMULATOR}
                            { first the codes that termiate the various escape sequences }

       CSITRM := ['A','B','C','D','H','J','K','c','f','g','h','l','m','n','q','x','y'];
       AUXTRM := ['M','P','Q','R','S','l','m','n','p','q','r','s','t','u','v','w','x','y','z'];
       DECTRM := ['3','4','5','6','8'];
       G0CTRM := ['A','B','0','1','2'];
       G1CTRM := ['A','B','0','1','2'];
       SMPTRM := ['Z','=','>','8','7','D','E','H','M','c','l'];
       NULTRM := [];

       TERMINAL := VT52;    {DEFAULT}
       STRTUP := [LBRK,OH,NBS,LPRN,RPRN]; {STARTING CHARS FOR ESCAPE SEQ (AFTER ESC)}
       CANESC;                          {CANCEL ALL ESCAPE SEQUENCES}
       RTRN := FALSE;
       MON := FALSE;





        REPEAT
                {HOST TO TERMINAL DIRECTION}


                IF  UNITBUSY(DCOM)
                        THEN
                         BEGIN
                            UNITREAD(DCOM,CH1,1);     {READ A CHAR}
                            C := CH1[0];
                            IF MON
                              THEN MONITOR(CH1);
                            IF (C = CAN) OR (C = SUB)
                             THEN  CANESC
                             ELSE IF FESC                {HAS AN ESCAPE BEEN FOUND}
                              THEN PUTESC(C)
                             ELSE IF C = ESC             {IS THIS THE FIRST INSTANCE OF ESC CODE?}
                              THEN
                               BEGIN
                                FESC := TRUE;
                                PUTESC(C)
                               END
                             ELSE                          {HERE SIMPLY OUTPUT CHAR TO SCREEN}
                              PUTSCREEN(C)
                           END;   {HOST TO TERMINAL DIRECTION}



                 {_________________________________________________________________________________}
                 {TERMINAL TO HOST DIRECTION}


                IF  UNITBUSY(KBRD)
                        THEN BEGIN
                                UNITREAD(KBRD,CH,1);
                                IF CH[0] = CTRMON  {USE AS A TOGGLE}
                                  THEN MON := NOT MON
                                  ELSE IF NOT FESC
                                  THEN UNITWRITE(DCOM,CH,1);
                        END;
        UNTIL  CH[0] = CTRLC
END.

