$TITLE( 'TERMINAL - A DUMB TERMINAL EMULATOR' )

terminal: DO;

$INCLUDE( /RMX386/INC/RMXPLM.EXT )
$INCLUDE( /RMX386/INC/RMXPLM.LIT )
$INCLUDE( /RMX386/INC/COMMON.LIT )
$INCLUDE( /RMX386/INC/ERROR.LIT )
$INCLUDE( /RMX386/INC/IO.LIT )
$INCLUDE( /RMX386/INC/TSCRN.LIT )

DECLARE INIT                LITERALLY '0';
DECLARE RUN                 LITERALLY '1';

DECLARE area                BYTE;
DECLARE remote              TOKEN;
DECLARE local               TOKEN;
DECLARE tmp          (1024) BYTE;
DECLARE status              WORD_16;
DECLARE count               WORD_32;
DECLARE escapes             BYTE;
DECLARE attribs             TERM_ATTRIB;
DECLARE signal              SIGNAL_PAIR;
DECLARE excep               EXCEPTION;

check: PROCEDURE;

    DECLARE xstatus WORD;

    IF ( status <> E$OK ) THEN DO;
        IF ( area = INIT ) THEN
            CALL RQ$C$SEND$CO$RESPONSE( NIL, 0, @( 45, CR, LF,
                'Initialisation Failure, TERMINAL aborting', CR, LF ),
                @xstatus );
        ELSE
            CALL RQ$C$SEND$CO$RESPONSE( NIL, 0, @( 45, CR, LF,
                'Communications Failure, TERMINAL aborting', CR, LF ),
                @xstatus );

        CALL RQ$EXIT$IO$JOB( status, NIL, @xstatus );
    END;

END check;

handle_remote_bytes: PROCEDURE WORD_32;

    DECLARE (read, write) WORD_32;

    read = RQ$S$READ$MOVE( remote, @tmp, SIZE(tmp), @status );
    CALL check;

    IF ( read <> 0 ) THEN DO;
        write = RQ$S$WRITE$MOVE( local, @tmp, read, @status );
        CALL check;
    END;

    RETURN( read );

END handle_remote_bytes;

handle_local_bytes: PROCEDURE WORD_32;

    DECLARE (read, write) WORD_32, (index1, index2) WORD;

    read = RQ$S$READ$MOVE( local, @tmp, SIZE(tmp), @status );
    CALL check;

    IF ( read <> 0 ) THEN DO;
        DO index1 = 0 to (read-1);
            IF ( tmp(index1) = ESC ) THEN
                DO;
                    escapes = escapes + 1;

                    IF ( escapes = 3 ) THEN DO;
                        write = RQ$S$WRITE$MOVE( local, @( CR, LF ),
                                                 2, @status             );
                        CALL RQ$EXIT$IO$JOB( status, NIL, @status );
                    END;
                END;
            ELSE
                escapes = 0;
        END;

        write = RQ$S$WRITE$MOVE( remote, @tmp, read, @status );
        CALL check;
    END;

    RETURN( read );

END handle_local_bytes;

main: DO;

    area = INIT;

    CALL RQ$C$SEND$CO$RESPONSE( NIL, 0, @( 32, CR, LF, LF,
        'iRMX Terminal Emulator V1.0', CR, LF ), @status );

    excep.exception_handler_ptr = NIL;
    excep.exception_mode = 0;

    CALL RQ$SETEXCEPTION$HANDLER( @excep, @status );
    CALL RQ$C$GET$INPUT$PATHNAME( @tmp, 255, @status );

    IF ( tmp(0) = 0 ) THEN
        CALL MOVB( @( 6, ':COM1:' ), @tmp, 7 );
    ELSE
        IF ( tmp(1) <> ':' ) THEN DO;
            CALL MOVRB( @tmp(1), @tmp(2), tmp(0) );
            tmp(1) = ':';
            tmp(0) = tmp(0) + 2;
            tmp(tmp(0)) = ':';
        END;

    remote = RQ$S$ATTACH$FILE( @tmp, @status );
    CALL check;

    CALL RQ$S$OPEN( remote, READ$WRITE, 0, @status );
    CALL check;

    attribs.num_words = 1;
    attribs.num_used = 1;
    attribs.connection_flags = 0ffh;        /*   FLUSH$MODE
                                               + DO$NOT$ECHO$INPUT
                                               + PASS$INPUT$PARITY$BIT
                                               + PASS$OUTPUT$PARITY$BIT
                                               + IGNORE$OSC$IN$INPUT
                                               + DO$NOT$ACT$ON$OSC       */

    CALL RQ$S$SPECIAL( remote, SPECIAL$SET$TERM$DATA, @attribs, NIL, @status );
    CALL check;

    local = RQ$S$ATTACH$FILE( @( 4, ':CO:' ), @status );
    CALL check;

    CALL RQ$S$OPEN( local, READ$WRITE, 0, @status );
    CALL check;

    attribs.num_words = 1;
    attribs.num_used = 1;
    attribs.connection_flags = 0ffh;        /*   FLUSH$MODE
                                               + DO$NOT$ECHO$INPUT
                                               + PASS$INPUT$PARITY$BIT
                                               + PASS$OUTPUT$PARITY$BIT
                                               + IGNORE$OSC$IN$INPUT
                                               + DO$NOT$ACT$ON$OSC       */

    CALL RQ$S$SPECIAL( local, SPECIAL$SET$TERM$DATA, @attribs, NIL, @status );
    CALL check;

    signal.semaphore = SELECTOR$OF(NIL);
    signal.character = ETX;

    CALL RQ$S$SPECIAL( local, SPECIAL$SET$SIGNAL, @signal, NIL, @status );
    CALL check;

    area = RUN;
    escapes = 0;

    DO FOREVER;
        IF ( (handle_local_bytes + handle_remote_bytes) = 0 ) THEN
            CALL RQ$SLEEP( 1, @status );
    END;

END main;

END terminal;
