IMPLEMENTATION MODULE IO ;


FROM StrLib IMPORT StrCopy ;
FROM SYSTEM IMPORT ADR ;
FROM M2RTS IMPORT InstallTerminationProcedure ;
FROM libc IMPORT read, write, system, isatty ;
FROM ASCII IMPORT cr, eof, nl;

(* %%%FORWARD%%%
PROCEDURE Read (VAR ch: CHAR) ; FORWARD ;
PROCEDURE Write (ch: CHAR) ; FORWARD ;
PROCEDURE Error (ch: CHAR) ; FORWARD ;
PROCEDURE Flush ; FORWARD ;
PROCEDURE InitRaw ; FORWARD ;
PROCEDURE CleanUp ; FORWARD ;
   %%%FORWARD%%% *)

CONST
   MaxBuffer = 65536 ;

VAR
   IsInRawMode: BOOLEAN ;
   Eof        : BOOLEAN ;
   Buffer     : ARRAY [0..MaxBuffer] OF CHAR ;
   BufferLimit: CARDINAL ;



PROCEDURE Read (VAR ch: CHAR) ;
BEGIN
   Flush ;
   IF Eof OR (read(0, ADR(ch), 1)#1)
   THEN
      Eof := TRUE ;
      ch := eof
   END ;
   IF ch=nl
   THEN
      ch := cr
   END
END Read ;


PROCEDURE Write (ch: CHAR) ;
BEGIN
   IF (ch#cr) OR IsInRawMode
   THEN
      Buffer[BufferLimit] := ch ;
      INC(BufferLimit) ;
      IF (BufferLimit=MaxBuffer) OR (ch=nl)
      THEN
         Flush
      END
   END
END Write ;


PROCEDURE Error (ch: CHAR) ;
VAR
   res: INTEGER ;
BEGIN
   res := write(2, ADR(ch), 1)
END Error ;


(*
   Flush - flushes any outstanding characters to file descriptor 1.
*)

PROCEDURE Flush ;
VAR
   res: INTEGER ;
BEGIN
   IF BufferLimit>0
   THEN
      res := write(1, ADR(Buffer), INTEGER(BufferLimit)) ;
      BufferLimit := 0
   END
END Flush ;

PROCEDURE IOInRawMode ;
VAR
   Command: ARRAY [0..30] OF CHAR ;
   res    : INTEGER ;
BEGIN
   IF isatty()
   THEN
      IsInRawMode := TRUE ;
      StrCopy("stty raw -echo", Command) ;
      res := system(ADR(Command))
   END
END IOInRawMode ;


PROCEDURE IOInBufferedMode ;
VAR
   Command: ARRAY [0..30] OF CHAR ;
   res: INTEGER ;
BEGIN
   IF IsInRawMode
   THEN
      StrCopy("stty sane", Command) ;
      res := system(ADR(Command))
   END ;
   Flush
END IOInBufferedMode ;


BEGIN
   IsInRawMode := FALSE ;
   BufferLimit := 0 ;
   Eof := FALSE ;
   InstallTerminationProcedure(IOInBufferedMode)
END IO.