MODULE KERTRM (IDENT = '1.0.000' ) = BEGIN !++ ! FACILITY: ! ! KERMIT-32 terminal processing. ! ! ABSTRACT: ! ! This module will do all of the terminal processing for KERMIT-32. ! It contains the output routines for the terminal to send and ! receive messages as well as the routines to output text for debugging. ! ! ENVIRONMENT: ! ! VAX/VMS user mode. ! ! AUTHOR: Robert C. McQueen, CREATION DATE: 25-March-1983 !-- %SBTTL 'Table of Contents' ! ! TABLE OF CONTENTS: ! %SBTTL 'Revision History' !++ ! ! Start of version 1. 25-March-1983 ! ! 1.0.000 By: Robert C. McQueen On: 25-March-1983 ! Create this module. ! !-- %SBTTL 'Forward routine definitions' FORWARD ROUTINE TT_CHAR : NOVALUE, ! Process a single character TT_OUTPUT : NOVALUE; ! Output the buffer to SYS$OUTPUT %SBTTL 'Library files' ! ! INCLUDE FILES: ! ! ! System definitions ! LIBRARY 'SYS$LIBRARY:STARLET'; ! ! KERMIT common definitions ! REQUIRE 'KERCOM'; REQUIRE 'KERERR'; %SBTTL 'Structure definitions -- $GETDVI arguments' ! ! $GETDVI interface fields and structure definition ! LITERAL DVI_SIZE = 3; ! Length of a DVI item list entry ! ! Fields for accessing the items in a DVI item list ! FIELD DVI_FIELDS = SET DVI_BFR_LENGTH = [0, 0, 16, 0], DVI_ITEM_CODE = [0, 16, 16, 0], DVI_BFR_ADDRESS = [1, 0, 32, 0], DVI_RTN_LENGTH = [2, 0, 32, 0] TES; ! ! Structure definition for item list STRUCTURE DVI_ITEM_LIST [I, O, P, S, E; N] = [(N + 1)*DVI_SIZE*4] (DVI_ITEM_LIST + ((I*DVI_SIZE) + O)*4); %SBTTL 'Structures definitions -- Terminal characteristics' ! ! Terminal characteristics words ! LITERAL TC$_CHAR_LENGTH = 12; ! ! Fields for accessing the items in a characteristic block ! FIELD TC$_FIELDS = SET TC$_CLASS = [0, 0, 8, 0], TC$_TYPE = [0, 8, 8, 0], TC$_BFR_SIZE = [0, 16, 16, 0], TC$_PAGE_LEN = [1, 24, 8, 0], TC$_CHAR = [1, 0, 24, 0], TC$_CHAR_2 = [2, 0, 32, 0] TES; ! ! Structure definition for item list ! STRUCTURE TC$_CHAR_STR [O, P, S, E; N] = [TC$_CHAR_LENGTH] (TC$_CHAR_STR + O*4); %SBTTL 'Macro definitions' ! ! MACROS: ! %(/*macro-decl*/)% %SBTTL 'Symbol definitions' ! ! EQUATED SYMBOLS: ! LITERAL TEXT_BFR_LENGTH = 256; ! Length of the text buffer %SBTTL 'Storage' ! ! OWN STORAGE: ! ! ! TT_xxxxx routine storage ! OWN TEXT_POINTER, ! Pointer to store characters TEXT_BUFFER : VECTOR [CH$ALLOCATION (TEXT_BFR_LENGTH)], ! Buffer of characters TEXT_DESC : BLOCK [8, BYTE]; ! ! Communications routines storage ! OWN TERM_CHAN, ! Channel the terminal is opened on OLD_PARITY : BLOCK [8, BYTE], ! Old IOSB information OLD_TERM_CHAR : TC$_CHAR_STR FIELD (TC$_FIELDS), ! Old terminal chars NEW_TERM_CHAR : TC$_CHAR_STR FIELD (TC$_FIELDS); ! New terminal chars GLOBAL TERM_FLAG; ! Terminal open flag %SBTTL 'External routines' ! ! EXTERNAL REFERENCES: ! ! ! System library routines ! EXTERNAL ROUTINE LIB$SIGNAL : ADDRESSING_MODE (GENERAL), LIB$PUT_OUTPUT : ADDRESSING_MODE (GENERAL); %SBTTL 'External storage' !++ ! The following is the various external storage locations that are ! referenced from this module. !-- ! ! KERMSG storage ! EXTERNAL RCV_EOL, ! Receive EOL character RCV_TIMEOUT, ! Receive time out counter CONNECT_FLAG; ! Flag if communications line is TT: ! ! KERMIT storage ! EXTERNAL TERM_NAME, ! Terminal name TERM_DESC : BLOCK [8, BYTE]; ! Descriptor for terminal name %SBTTL 'Terminal routines -- TT_INIT - Initialize this module' GLOBAL ROUTINE TT_INIT : NOVALUE = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will initialize the terminal processing module. It will ! initialize the various data locations in this module. ! ! CALLING SEQUENCE: ! ! TT_INIT(); ! ! INPUT PARAMETERS: ! ! None. ! ! IMPLICIT INPUTS: ! ! None. ! ! OUPTUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION CODES: ! ! None. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN ! ! Initialize the text descriptor ! TEXT_DESC [DSC$B_CLASS] = DSC$K_CLASS_S; TEXT_DESC [DSC$B_DTYPE] = DSC$K_DTYPE_T; TEXT_DESC [DSC$A_POINTER] = TEXT_BUFFER; TEXT_DESC [DSC$W_LENGTH] = 0; ! ! Now initialize the various pointers ! TEXT_POINTER = CH$PTR (TEXT_BUFFER); ! ! Set up the terminal name descriptor TERM_DESC [DSC$B_CLASS] = DSC$K_CLASS_S; TERM_DESC [DSC$B_DTYPE] = DSC$K_DTYPE_T; TERM_DESC [DSC$A_POINTER] = TERM_NAME; TERM_DESC [DSC$W_LENGTH] = 12; CH$COPY (10, CH$PTR (UPLIT ('SYS$INPUT:')), 0, 11, CH$PTR (TERM_NAME)); ! ! Initialize the flags ! TERM_FLAG = FALSE; END; ! End of TT_INIT %SBTTL 'Terminal routines -- TT_TEXT - Output a text string' GLOBAL ROUTINE TT_TEXT (ADDRESS) : NOVALUE = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will output text on the user's terminal. It will ! assume that it must check to determine if it can output the text ! or not. ! ! CALLING SEQUENCE: ! ! TT_TEXT(TEXT_ADDRESS); ! ! INPUT PARAMETERS: ! ! None. ! ! IMPLICIT INPUTS: ! ! None. ! ! OUPTUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION CODES: ! ! None. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN LOCAL CHARACTER, ! Character being processed ARG_POINTER; ! Pointer to the argument's text ! ! Construct a pointer to the argument. ! ARG_POINTER = CH$PTR (.ADDRESS); ! ! Get the first character that was passed. ! CHARACTER = CH$RCHAR_A (ARG_POINTER); ! ! Loop reading characters and calling the output routine to process ! them ! WHILE .CHARACTER NEQ CHR_NUL DO BEGIN TT_CHAR (.CHARACTER); CHARACTER = CH$RCHAR_A (ARG_POINTER); END; END; ! End of TT_TEXT %SBTTL 'Terminal routines -- TT_NUMBER - Output a three digit number' GLOBAL ROUTINE TT_NUMBER (NUMBER) : NOVALUE = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will store a three digit number into the text buffer. ! It will just return if the number is greater than 999. ! ! CALLING SEQUENCE: ! ! TT_NUMBER(Value); ! ! INPUT PARAMETERS: ! ! Value - Value to output. ! ! IMPLICIT INPUTS: ! ! None. ! ! OUPTUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION CODES: ! ! None. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN IF .NUMBER LEQ 999 THEN BEGIN TT_CHAR ((.NUMBER/100) + %C'0'); TT_CHAR (((.NUMBER/10) MOD 10) + %C'0'); TT_CHAR ((.NUMBER MOD 10) + %C'0'); END; END; ! End of TT_NUMBER %SBTTL 'Terminal routines -- TT_QCHAR - Output a single character' GLOBAL ROUTINE TT_QCHAR (CHARACTER) : NOVALUE = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will output a quoted character to the terminal buffer. ! It will convert control characters to printing characters. ! ! CALLING SEQUENCE: ! ! TT_QCHAR(Character); ! ! INPUT PARAMETERS: ! ! Character - Character to store into the text buffer. ! ! IMPLICIT INPUTS: ! ! None. ! ! OUPTUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION CODES: ! ! None. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN LOCAL TEMP_CHAR; ! Temp holding place for the characters ! ! Copy the character first ! TEMP_CHAR = .CHARACTER; ! ! Determine if this is a control character. If so then convert it to be ! a ^ ! IF .TEMP_CHAR LSS CHR_SP THEN BEGIN TT_CHAR (%C'^'); TEMP_CHAR = %C'A' - 1 + .TEMP_CHAR; END; ! ! Output the character after any conversion ! TT_CHAR (.TEMP_CHAR); ! END; ! End of TT_QCHAR %SBTTL 'Terminal routines -- TT_CHAR - Output a single character' GLOBAL ROUTINE TT_CHAR (CHARACTER) : NOVALUE = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will store a character into the text buffer. It will ! cause the text to be output if the character is a line terminator. ! ! CALLING SEQUENCE: ! ! TT_CHAR(Character); ! ! INPUT PARAMETERS: ! ! Character - Character to store into the text buffer. ! ! IMPLICIT INPUTS: ! ! None. ! ! OUPTUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION CODES: ! ! None. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN ! ! If this is a line feed then just output the text string and return ! IF .CHARACTER EQL CHR_LFD THEN TT_OUTPUT () ELSE BEGIN ! ! Increment the count of the characters ! TEXT_DESC [DSC$W_LENGTH] = .TEXT_DESC [DSC$W_LENGTH] + 1; ! ! And store the character ! CH$WCHAR_A (.CHARACTER, TEXT_POINTER); IF .TEXT_DESC [DSC$W_LENGTH] EQL TEXT_BFR_LENGTH THEN TT_OUTPUT (); END; ! END; ! End of TT_CHAR %SBTTL 'Terminal routines -- TT_CRLF - Output a CRLF' GLOBAL ROUTINE TT_CRLF : NOVALUE = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will cause the contents of the terminal buffer to be ! output to SYS$OUTPUT:. ! ! CALLING SEQUENCE: ! ! TT_CRLF(); ! ! INPUT PARAMETERS: ! ! None. ! ! IMPLICIT INPUTS: ! ! None. ! ! OUPTUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION CODES: ! ! None. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN TT_CHAR (CHR_LFD); END; ! End of TT_CRLF %SBTTL 'Terminal routines -- TT_OUTPUT - Output the buffer' ROUTINE TT_OUTPUT : NOVALUE = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will dump the text buffer on the output device. ! ! CALLING SEQUENCE: ! ! TT_OUTPUT(); ! ! INPUT PARAMETERS: ! ! None. ! ! IMPLICIT INPUTS: ! ! None. ! ! OUPTUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION CODES: ! ! None. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN LOCAL STATUS; ! Status returned by the library routine ! ! Output the text ! STATUS = LIB$PUT_OUTPUT (TEXT_DESC); ! ! Now reset the descriptor and the pointer to a virgin state ! TEXT_DESC [DSC$W_LENGTH] = 0; TEXT_POINTER = CH$PTR (TEXT_BUFFER); ! END; ! End of TT_OUTPUT %SBTTL 'Communcations line -- TERM_OPEN' GLOBAL ROUTINE TERM_OPEN = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will assign a channel that is used in the CONNECT ! processing and to send/receive a file from. ! ! CALLING SEQUENCE: ! ! TERM_OPEN(); ! ! INPUT PARAMETERS: ! ! None. ! ! IMPLICIT INPUTS: ! ! TERM_NAME - Vector of ASCII characters that represent the name of ! the terminal to use. ! ! OUTPUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! TERM_CHAN - Channel number of the terminal line we are using. ! ! COMPLETION CODES: ! ! SS$_NORMAL or error condition. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN BIND SYS_OUTPUT = %ASCID'TT:'; LOCAL STATUS, OUTPUT_ITM : DVI_ITEM_LIST [2] FIELD (DVI_FIELDS), OUTPUT_NAME : VECTOR [65, BYTE], OUTPUT_LENGTH, OUTPUT_CLASS, OUTPUT_STATUS, TERM_ITM : DVI_ITEM_LIST [2] FIELD (DVI_FIELDS), TERM_NAME : VECTOR [65, BYTE], TERM_LENGTH, TERM_CLASS, TERM_STATUS; ! ! Initialize the first character to be an underscore, incase we have a ! concealed device name ! OUTPUT_NAME [0] = %C'_'; TERM_NAME [0] = %C'_'; ! ! Initialize the GETDVI call for the TT: ! OUTPUT_ITM [0, DVI_ITEM_CODE] = DVI$_DEVCLASS; OUTPUT_ITM [0, DVI_BFR_LENGTH] = 4; OUTPUT_ITM [0, DVI_BFR_ADDRESS] = OUTPUT_CLASS; OUTPUT_ITM [0, DVI_RTN_LENGTH] = 0; ! OUTPUT_ITM [1, DVI_ITEM_CODE] = DVI$_DEVNAM; OUTPUT_ITM [1, DVI_BFR_LENGTH] = 64; OUTPUT_ITM [1, DVI_BFR_ADDRESS] = OUTPUT_NAME [1]; OUTPUT_ITM [1, DVI_RTN_LENGTH] = OUTPUT_LENGTH; ! OUTPUT_ITM [2, DVI_ITEM_CODE] = 0; OUTPUT_ITM [2, DVI_BFR_LENGTH] = 0; ! ! Initialize the GETDVI call for the terminal name given ! TERM_ITM [0, DVI_ITEM_CODE] = DVI$_DEVCLASS; TERM_ITM [0, DVI_BFR_LENGTH] = 4; TERM_ITM [0, DVI_BFR_ADDRESS] = TERM_CLASS; TERM_ITM [0, DVI_RTN_LENGTH] = 0; ! TERM_ITM [1, DVI_ITEM_CODE] = DVI$_DEVNAM; TERM_ITM [1, DVI_BFR_LENGTH] = 64; TERM_ITM [1, DVI_BFR_ADDRESS] = TERM_NAME [1]; TERM_ITM [1, DVI_RTN_LENGTH] = TERM_LENGTH; ! TERM_ITM [2, DVI_ITEM_CODE] = 0; TERM_ITM [2, DVI_BFR_LENGTH] = 0; ! ! Get the device information ! OUTPUT_STATUS = $GETDVI (EFN = 2, DEVNAM = SYS_OUTPUT, ITMLST = OUTPUT_ITM); IF NOT .OUTPUT_STATUS THEN BEGIN LIB$SIGNAL (.OUTPUT_STATUS); RETURN .OUTPUT_STATUS; END; STATUS = $WAITFR (EFN = 2); IF NOT .STATUS THEN BEGIN LIB$SIGNAL (.STATUS); RETURN .STATUS; END; ! ! For both of the device names ! TERM_STATUS = $GETDVI (EFN = 2, DEVNAM = TERM_DESC, ITMLST = TERM_ITM); IF NOT .TERM_STATUS THEN BEGIN LIB$SIGNAL (.TERM_STATUS); RETURN .STATUS; END; STATUS = $WAITFR (EFN = 2); IF NOT .STATUS THEN BEGIN LIB$SIGNAL (.STATUS); RETURN .STATUS; END; ! ! Make sure that they are terminals ! IF .TERM_CLASS EQL DC$_TERM AND .OUTPUT_CLASS EQL DC$_TERM THEN BEGIN IF .OUTPUT_STATUS EQL SS$_CONCEALED THEN BEGIN OUTPUT_LENGTH = .OUTPUT_LENGTH + 1; OUTPUT_ITM [1, DVI_BFR_ADDRESS] = .OUTPUT_ITM [1, DVI_BFR_ADDRESS] - 1; END; IF .TERM_STATUS EQL SS$_CONCEALED THEN BEGIN TERM_LENGTH = .TERM_LENGTH + 1; TERM_ITM [1, DVI_BFR_ADDRESS] = .TERM_ITM [1, DVI_BFR_ADDRESS] - 1; END; IF CH$NEQ (.OUTPUT_LENGTH, CH$PTR (.OUTPUT_ITM [1, DVI_BFR_ADDRESS]), .TERM_LENGTH, CH$PTR (.TERM_ITM [1, DVI_BFR_ADDRESS]), CHR_NUL) THEN CONNECT_FLAG = FALSE ELSE CONNECT_FLAG = TRUE; END ELSE BEGIN RETURN KER_LINTERM; END; STATUS = $ASSIGN (DEVNAM = TERM_DESC, CHAN = TERM_CHAN); IF NOT .STATUS THEN BEGIN LIB$SIGNAL (.STATUS); RETURN .STATUS; END; STATUS = $QIOW (CHAN = .TERM_CHAN, FUNC = IO$_SENSEMODE, P1 = OLD_TERM_CHAR, P2 = TC$_CHAR_LENGTH, IOSB = OLD_PARITY); IF NOT .STATUS THEN BEGIN LIB$SIGNAL (.STATUS); RETURN .STATUS; END; NEW_TERM_CHAR [TC$_BFR_SIZE] = .OLD_TERM_CHAR [TC$_BFR_SIZE]; NEW_TERM_CHAR [TC$_TYPE] = .OLD_TERM_CHAR [TC$_TYPE]; NEW_TERM_CHAR [TC$_CLASS] = .OLD_TERM_CHAR [TC$_CLASS]; NEW_TERM_CHAR [TC$_PAGE_LEN] = .OLD_TERM_CHAR [TC$_PAGE_LEN]; NEW_TERM_CHAR [TC$_CHAR] = (.OLD_TERM_CHAR [TC$_CHAR] OR TT$M_EIGHTBIT OR TT$M_NOBRDCST) AND NOT ( TT$M_CRFILL OR TT$M_LFFILL OR TT$M_WRAP); NEW_TERM_CHAR [TC$_CHAR_2] = .OLD_TERM_CHAR [TC$_CHAR_2]; STATUS = $QIOW (CHAN = .TERM_CHAN, FUNC = IO$_SETMODE, P1 = NEW_TERM_CHAR, P2 = TC$_CHAR_LENGTH, P5 = TT$M_ALTRPAR); IF NOT .STATUS THEN BEGIN LIB$SIGNAL (.STATUS); RETURN .STATUS; END; TERM_FLAG = TRUE; ! Terminal now open RETURN KER_NORMAL; END; ! End of TERM_OPEN %SBTTL 'Communications line -- TERM_CLOSE' GLOBAL ROUTINE TERM_CLOSE = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will deassign the channel that was assigned by ! TERM_OPEN. ! ! CALLING SEQUENCE: ! ! TERM_CLOSE(); ! ! INPUT PARAMETERS: ! ! None. ! ! IMPLICIT INPUTS: ! ! TERM_CHAN - Channel number to deassign. ! ! OUTPUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION CODES: ! ! SS$_NORMAL or error condition. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN LOCAL PAR, ! Parity being set STATUS; ! Status returned by system service CONNECT_FLAG = FALSE; PAR = .OLD_PARITY [1, 8, 8, 0] OR TT$M_ALTRPAR; STATUS = $QIOW (CHAN = .TERM_CHAN, FUNC = IO$_SETMODE, P1 = OLD_TERM_CHAR, P2 = TC$_CHAR_LENGTH, P5 = .PAR); IF NOT .STATUS THEN BEGIN LIB$SIGNAL (.STATUS); RETURN .STATUS; END; STATUS = $DASSGN (CHAN = .TERM_CHAN); IF .STATUS THEN BEGIN TERM_FLAG = FALSE; RETURN KER_NORMAL END ELSE BEGIN LIB$SIGNAL (.STATUS); RETURN .STATUS; END; END; ! End of TERM_CLOSE %SBTTL 'Communications line -- SEND' GLOBAL ROUTINE SEND (ADDRESS, LENGTH) = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will send a stream of 8-bit bytes over the terminal ! line to the remote KERMIT. This routine is called from KERMSG. ! ! CALLING SEQUENCE: ! ! SEND(Address-of-msg, Length-of-msg); ! ! INPUT PARAMETERS: ! ! None. ! ! IMPLICIT INPUTS: ! ! TERM_CHAN - Channel number to deassign. ! ! OUTPUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION CODES: ! ! SS$_NORMAL or error condition. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN LOCAL STATUS; ! Status returned by $QIOW STATUS = $QIOW (CHAN = .TERM_CHAN, FUNC = IO$_WRITEVBLK + IO$M_NOFORMAT, P1 = .ADDRESS, P2 = .LENGTH); IF .STATUS EQL SS$_NORMAL THEN RETURN KER_NORMAL ELSE BEGIN LIB$SIGNAL (.STATUS); RETURN .STATUS; END; END; ! End of SEND %SBTTL 'Communications line -- RECEIVE' GLOBAL ROUTINE RECEIVE (ADDRESS, LENGTH) = !++ ! FUNCTIONAL DESCRIPTION: ! ! This routine will receive a stream of 8-bit bytes over the terminal ! line to the remote KERMIT. This routine is called from KERMSG. ! The text that is stored will always contain the control-A as the ! first character. ! ! CALLING SEQUENCE: ! ! RECEIVE(Address-of-msg); ! ! INPUT PARAMETERS: ! ! None. ! ! IMPLICIT INPUTS: ! ! TERM_CHAN - Channel number to deassign. ! ! OUTPUT PARAMETERS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION CODES: ! ! SS$_NORMAL or error condition. ! ! SIDE EFFECTS: ! ! None. ! !-- BEGIN LOCAL TERMINATOR : VECTOR [2, LONG], IO_STATUS : VECTOR [4, WORD], POINTER, ! Pointer into the message STATUS; ! Status returned by $QIO TERMINATOR [0] = 0; TERMINATOR [1] = 1^.RCV_EOL; STATUS = $QIOW (CHAN = .TERM_CHAN, FUNC = IO$_TTYREADALL + IO$M_NOECHO, IOSB = IO_STATUS, P1 = .ADDRESS, P2 = MAX_MSG, P3 = .RCV_TIMEOUT, P4 = TERMINATOR); .LENGTH = .IO_STATUS [1] + 1; POINTER = CH$FIND_CH(.IO_STATUS [1] + 1, CH$PTR(.ADDRESS, 0, CHR_SIZE), CHR_CTL_Y); IF CH$FAIL(POINTER) THEN RETURN KER_ABORTED; IF .STATUS EQL SS$_TIMEOUT THEN RETURN KER_TIMEOUT; IF .STATUS EQL SS$_NORMAL THEN RETURN KER_NORMAL; ! LIB$SIGNAL(KER_RECERR, .STATUS); RETURN KER_RECERR; END; ! End of RECEIVE %SBTTL 'End of KERTRM' END ! End of module ELUDOM