MODULE editor;

(* based on the kilo editor building course*)

(* Step 18 *)


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

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

    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;
(* 
    static void setControlLines(int port, int dtr, int rts)
{
    struct termios tty;

    tcgetattr(port, &tty);

    cfmakeraw(&tty); // Sets raw mode, 8N1, etc.

    tty.c_cflag &= ~CRTSCTS; // Disable hardware flow control
    tty.c_cflag |= CLOCAL;  // Ignore modem control lines

    tcsetattr(port, TCSANOW, &tty);

    int flags = TIOCM_DTR | TIOCM_RTS;
    ioctl(port, TIOCMBIS, &flags); // Set bits
} *)

(* termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB);
termios_p->c_cflag |= CS8; *)

        VAR
            TCSAFLUSH   : INTEGER;
            result      : INTEGER;
            bresult     : BOOLEAN;
    BEGIN
        TCSAFLUSH := termios.tcsflush (); 
        libc.atexit(disableRawMode);
        termios.cfmakeraw(raw);
        bresult := termios.SetFlag(raw,termios.crtscts, FALSE);
        bresult := termios.SetFlag(raw,termios.clocal, TRUE);
        result := termios.tcsnow();
        (* STextIO.WriteChar(CHR(13)) *)
        bresult := termios.SetChar(raw,termios.vmin,CHR(0));
        bresult := termios.SetChar(raw,termios.vtime,CHR(1));
    END enableRawMode;

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.