MODULE editor;

(* based on the kilo editor building course*)

(* Step 19 *)

(******************** INCLUDES ******************)

IMPORT FIO, SYSTEM, termios, STextIO, NumberIO;
IMPORT CharClass, STextIO, libc;

(******************** DATA ******************)

VAR 
    c           : CHAR;
    p           : POINTER TO CHAR;
    thetermios  : termios.TERMIOS;
    raw         : termios.TERMIOS;
    result      : INTEGER;
    number : CARDINAL;

(******************** TERMINAL ******************)

    PROCEDURE die (s : ARRAY OF CHAR);
    BEGIN
        libc.perror(s);
        HALT
    END die;

    PROCEDURE disableRawMode(): INTEGER;
        VAR
            TCSAFLUSH : INTEGER;
            result    : INTEGER; 
        
    BEGIN
        TCSAFLUSH := termios.tcsflush ();
        IF termios.tcsetattr(FIO.StdIn, TCSAFLUSH, thetermios) = -1 THEN
            die("tcsetattr")
        END;
        RETURN result;
    END disableRawMode;

    PROCEDURE enableRawMode;

        VAR
            TCSAFLUSH   : INTEGER;
            result      : INTEGER;
            bresult     : BOOLEAN;
    BEGIN
        TCSAFLUSH := termios.tcsflush (); 
        libc.atexit(disableRawMode);
        bresult := termios.SetFlag(raw,termios.icrnl, FALSE);
        bresult := termios.SetFlag(raw,termios.ixon, FALSE);
        bresult := termios.SetFlag(raw,termios.lecho, FALSE);
        bresult := termios.SetFlag(raw,termios.opost, FALSE);
        bresult := termios.SetFlag(raw,termios.licanon, FALSE);
        bresult := termios.SetFlag(raw,termios.liexten, FALSE);
        bresult := termios.SetFlag(raw,termios.lisig, FALSE);

        bresult := termios.SetFlag(raw,termios.ibrkint, FALSE);
        bresult := termios.SetFlag(raw,termios.inpck, FALSE);
        bresult := termios.SetFlag(raw,termios.istrip, FALSE);

        bresult := termios.SetFlag(raw,termios.cs8, TRUE);
        IF termios.tcsetattr(FIO.StdIn, TCSAFLUSH, raw) = -1 THEN
            die("tcsetattr")
        END;

        (* PROCEDURE SetChar (t: TERMIOS; c: ControlChar; ch: CHAR) : BOOLEAN ; *)
        (* termios.vmin := 0;
        termios.vtime := 1; *)
        bresult := termios.SetChar(raw,termios.vmin,CHR(0));
        bresult := termios.SetChar(raw,termios.vtime,CHR(1));
    END enableRawMode;

(******************** INIT ******************)

BEGIN
    thetermios := termios.InitTermios();
    raw := termios.InitTermios();
    IF termios.tcgetattr(FIO.StdIn, thetermios) = -1 THEN
        die("tcgetattr")
    END;
    IF termios.tcgetattr(FIO.StdIn, raw) = -1 THEN
        die("tcgetattr")
    END;

    enableRawMode;
    p := SYSTEM.ADR(c);

    LOOP
        c := CHR(0);
        number := (FIO.ReadNBytes(FIO.StdIn,1,p));
        IF ORD(c) < 32 THEN
             NumberIO.WriteCard(ORD(c),5);
            STextIO.WriteLn;
            STextIO.WriteChar(CHR(13));
        ELSE
            NumberIO.WriteCard(ORD(c),5);
            STextIO.WriteString(" ('");
            STextIO.WriteChar(c);
            STextIO.WriteString(" ')");
            STextIO.WriteLn;
            STextIO.WriteChar(CHR(13));
        END;
        IF c = "q" THEN
            EXIT
        END;
    END;
END editor.