IMPLEMENTATION MODULE Term ; (* termios-based raw keyboard + ANSI screen output. *) FROM Posix IMPORT read, write, tcgetattr, tcsetattr, cfmakeraw, poll ; FROM SYSTEM IMPORT ADR, ADDRESS, BYTE ; CONST TCSANOW = 0 ; STDIN = 0 ; STDOUT = 1 ; VAR saved : ARRAY [0..127] OF BYTE ; rawstate : ARRAY [0..127] OF BYTE ; haveSaved : BOOLEAN ; PROCEDURE Out (s : ARRAY OF CHAR) ; VAR i : CARDINAL ; n : LONGINT ; BEGIN i := 0 ; WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO n := write (STDOUT, ADR (s [i]), 1) ; INC (i) END END Out ; PROCEDURE Open ; VAR r : INTEGER ; BEGIN r := tcgetattr (STDIN, ADR (saved)) ; rawstate := saved ; cfmakeraw (ADR (rawstate)) ; r := tcsetattr (STDIN, TCSANOW, ADR (rawstate)) ; haveSaved := TRUE ; Out ("") (* clear screen, home *) END Open ; PROCEDURE Close ; VAR r : INTEGER ; BEGIN IF haveSaved THEN r := tcsetattr (STDIN, TCSANOW, ADR (saved)) ; haveSaved := FALSE END ; Out ("") (* normal attribute *) END Close ; PROCEDURE ClrScr ; BEGIN Out ("") END ClrScr ; PROCEDURE GotoXY (row, col : CARDINAL) ; BEGIN Out ("[") ; PutCard (row) ; Out (";") ; PutCard (col) ; Out ("H") END GotoXY ; PROCEDURE PutCh (ch : CHAR) ; VAR n : LONGINT ; BEGIN n := write (STDOUT, ADR (ch), 1) END PutCh ; PROCEDURE PutStr (s : ARRAY OF CHAR) ; VAR i : CARDINAL ; n : LONGINT ; BEGIN i := 0 ; WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO n := write (STDOUT, ADR (s [i]), 1) ; INC (i) END END PutStr ; PROCEDURE PutCard (n : CARDINAL) ; VAR dig : ARRAY [0..9] OF CHAR ; i : CARDINAL ; BEGIN IF n = 0 THEN PutCh ("0") ELSE i := 0 ; WHILE n > 0 DO dig [i] := CHR (ORD ("0") + (n MOD 10)) ; n := n DIV 10 ; INC (i) END ; WHILE i > 0 DO DEC (i) ; PutCh (dig [i]) END END END PutCard ; PROCEDURE PutLongCard (n : LONGCARD) ; VAR dig : ARRAY [0..19] OF CHAR ; i, m : CARDINAL ; BEGIN IF n = 0 THEN PutCh ("0") ELSE i := 0 ; WHILE n > 0 DO m := n MOD 10 ; dig [i] := CHR (ORD ("0") + m) ; n := n DIV 10 ; INC (i) END ; WHILE i > 0 DO DEC (i) ; PutCh (dig [i]) END END END PutLongCard ; PROCEDURE ScrnWide (n : CARDINAL) ; VAR i : CARDINAL ; BEGIN i := 0 ; WHILE i < n DO PutCh (" ") ; INC (i) END END ScrnWide ; PROCEDURE Marked ; BEGIN Out ("") (* bold + reverse video *); END Marked ; PROCEDURE Normal ; BEGIN Out ("") END Normal ; PROCEDURE GetCh (VAR ch : CHAR) ; VAR n : LONGINT ; BEGIN n := read (STDIN, ADR (ch), 1) ; IF n # 1 THEN ch := 0C END END GetCh ; PROCEDURE Avail () : BOOLEAN ; TYPE PollFd = RECORD fd : CARDINAL ; events : SHORTCARD ; revents : SHORTCARD ; END ; VAR pfd : PollFd ; n : INTEGER ; BEGIN (* struct pollfd { int fd; short events; short revents; } *) pfd.fd := STDIN ; pfd.events := 1 ; (* POLLIN *) pfd.revents := 0 ; n := poll (ADR (pfd), 1, 0) ; RETURN n > 0 END Avail ; PROCEDURE GetKey (VAR ch : CHAR) ; VAR n : LONGINT ; BEGIN IF Avail () THEN n := read (STDIN, ADR (ch), 1) ; IF n # 1 THEN ch := 0C END ELSE ch := 0C END END GetKey ; PROCEDURE Beep ; VAR n : LONGINT ; b : CHAR ; BEGIN b := CHR (7) ; n := write (STDOUT, ADR (b), 1) END Beep ; BEGIN haveSaved := FALSE END Term.