term/src/Term.m3


 $Id: Term.m3,v 1.4 2010-05-09 09:12:35 jkrell Exp $ 

UNSAFE MODULE Term;
IMPORT Stdio;
IMPORT Wr AS Wrr;
IMPORT Rd;
IMPORT Termios;
IMPORT Text;
IMPORT Thread;
IMPORT TermC;

<* FATAL Thread.Alerted, Wrr.Failure, Rd.Failure, Rd.EndOfFile *>

VAR
  Endl: TEXT := "\n";
  Raw: BOOLEAN := FALSE;

PROCEDURE MakeRaw(flag: BOOLEAN) =
  VAR
    termNew: Termios.T;
  BEGIN
    IF flag # Raw THEN
      Raw := flag;
      Wrr.Flush(Stdio.stdout);
      IF Raw THEN
          termNew := TermC.GetTermRaw();
          Endl := "\015\012";
        ELSE
          termNew := TermC.GetTermCooked();
          Endl := "\n";
        END;
      Termios.tcsetattr(Termios.Stdin, Termios.Tcsanow, termNew);
      END;
  END MakeRaw;

PROCEDURE GetCharDR(): CHAR RAISES {SpecialChar} =
  BEGIN
    TRY
      RETURN GetCharE(RawSpecial);
    EXCEPT
      SpecialChar =>
    END;
    MakeRaw(FALSE);
    RAISE SpecialChar;
  END GetCharDR;

PROCEDURE GetCharD(): CHAR =
  <* FATAL SpecialChar *>
  BEGIN
    IF Raw THEN
      RETURN GetCharDR()
    ELSE
      RETURN GetChar();
    END;
  END GetCharD;

PROCEDURE GetCharE(special: TEXT): CHAR RAISES {SpecialChar} =
  VAR
    cin: CHAR;
  BEGIN
    cin := GetChar();
    IF Text.FindChar(special, cin) = -1 THEN
      RETURN cin;
    ELSE
      RAISE SpecialChar;
    END;
  END GetCharE;

PROCEDURE GetChar(): CHAR =
  BEGIN
    Wrr.Flush(Stdio.stdout);
    RETURN Rd.GetChar(Stdio.stdin);
  END GetChar;

PROCEDURE Wr(s: TEXT) =
  BEGIN
    IF Raw THEN
      VAR
        i,j: INTEGER := 0;
      BEGIN
        REPEAT
          j := Text.FindChar(s, '\n', i);
          IF j # -1 THEN
            Wrr.PutText(Stdio.stdout, Text.Sub(s, i, j - i));
            Wrr.PutText(Stdio.stdout, Endl);
            i := j + 1;
          END;
        UNTIL j = -1;
        IF i # Text.Length(s) THEN
          Wrr.PutText(Stdio.stdout, Text.Sub(s, i, LAST(CARDINAL)));
        END;
      END;
    ELSE
      Wrr.PutText(Stdio.stdout, s);
    END;
  END Wr;

PROCEDURE WrLn(s: TEXT; flush := FALSE) =
  BEGIN
    Wrr.PutText(Stdio.stdout, s);
    Wrr.PutText(Stdio.stdout, Endl);
    IF flush THEN
      Wrr.Flush(Stdio.stdout);
    END;
  END WrLn;

BEGIN
  TermC.Init();
END Term.