/*
** Main Routine
**
** Function: Intitializes the environment and then hibernates, waiting
** to be awakened. When awakened, the program checks to see whether it
** is exiting, or whether more log data is available. If more data is
** available, the data is appended to the current log record and checked
** to see whether a log record should be written. A log record is written
** either when maxbuf characters are in the log buffer,
** or when it finds a <CR>character pair. The algorithm
** allows an unlimited number of <NULL> fill characters to occur
** between the <CR>and the <LF>. If the program is
** exiting, it closes the log file, deletes the pseudoterminal, resets the
** terminal, and exits.
*/
Initialize environments (This includes creating pseudoterminal, the log file
and starting up the subprocess.)
If (Initialization OK) Then
Do
while (I/O buffer to log)
Data size = number of bytes in I/O buff
For all data in I/O buffer
If (cr_seen) Then
If (current char == <LF>) Then
write current log buffer
reset cr_seen
point to start of log buffer
Else if (current char != <NULL>) Then
insert <CR>and current char into log buffer
move log buffer ptr over 2 characters
reset cr_seen
Endif
Else if (current character != <CR>) Then
insert character into log buffer
move log buffer ptr over 1 character
Else
set cr_seen
Endif
If (log buffer ptr >= IOC$GW_MAX-48) Then
write log buffer
reset log buffer pointer
reset cr_seen
Endif
Endloop
Free I/O buffer call free_io_buffers
Endwhile
If (not exiting) Then
Wait for more to do call SYS$HIBER
Endif
Until ( (exiting) and (no I/O buffers to log) )
close log file
If ( (close failed) and (exit reason is SS$_NORMAL) ) Then
set exit to status to failure reason
Endif
If (subprocess still running) Then
call SYS$FORCEX to run down the subprocess
Endif
call PTD$CANCEL to flush all pending pseudoterminal read requests
call SYS$CANCEL to flush all terminal requests
call PTD$DELETE to delete the pseudoterminal
If ( (delete failed) and (exit reason is SS$_NORMAL) ) Then
set exit to status to failure reason
Endif
reset terminal to startup condition using SYS$QIOW
If ( (terminal reset failed) and (exit reason is SS$_NORMAL) ) Then
exit to status to failure reason
Endif
Endif
call LIB$SIGNAL and report exit reason
Exit
/*
**
** Initialization Code
**
** Function: This routine sets the terminal characteristics, creates the
** pseudoterminal, starts up the subprocess, and opens the log file. If
** any of these steps fail, the program undoes any steps already done and
** returns to the main routine.
**
*/
read the maximum buffer size from IOC$GW_MAXBUF
Assign a channel to SYS$INPUT
If (assign ok) Then
Read the terminal characteristics from the terminal
If (read of terminal characteristics ok) Then
Open log file with maximum record size of IOC$GW_MAXBUF
If (open ok) Then
Create the pseudoterminal with characteristics of terminal
If (create ok) then
Place 4 of the buffers on the queue of free I/O buffers
Copy terminal characteristics and modify them to NOECHO and PASTHRU
Set the terminal characteristics use modified value
If (set ok) Then
Get device name of pseudoterminal use SYS$GETDVI
If (get ok) Then
Create subprocess
If (create ok) Then
Enable XON, XOFF, BELL, SET_LINE event notification ASTs
If (AST setup OK) Then
Call PTD$READ to start reading from the pseudoterminal
ASTADR = ft_read_ast
ASTPRM = buffer address
READBUF = I/O buffer + 8
READBUF_LEN = 500
If (read ok) Then
Call SYS$QIO and read a single character from the
keyboard ASTADR = kbd_read_ast
If (read failed) Then
Call PTD$CANCEL to flush queued pseudoterminal read
Call PTD$DELETE to delete pseudoterminal
Reset terminal to original state
Close log file and delete it
Endif
Else
Call PTD$DELETE to delete pseudoterminal
Reset terminal to original state
Close log file and delete it
Endif
Else
Call PTD$DELETE to delete pseudoterminal
Reset terminal to original state
Close log file and delete it
Endif
Else
Call PTD$DELETE to delete pseudoterminal
Reset terminal to original state
Close log file and delete it
Endif
Else
Call PTD$DELETE to delete pseudoterminal
Reset terminal to original state
Close log file and delete it
Endif
Else
Call PTD$DELETE to delete pseudoterminal
Close log file and delete it
Endif
Else
Close log file and delete it
Endif
Endif
Endif
Endif
/*
** kbd_read_ast
**
** Function: This routine is called every time data is read from the terminal.
** If the program is exiting, then the routine exits without restarting the
** read. The character read is checked to see if the terminate processing
** character Ctrl\ was entered. If the terminate processing character was
** entered, the exiting state is set and a SYS$WAKE is issued to start the
** main routine. Now an attempt is made to obtain an I/O buffer in which
** to store echoed output. If an I/O buffer is unavailable, a simple
** PTD$WRITE is issued; a PTD$WRITE with echo is issued if a buffer is
** available. If the write completes successfully, another read is issued
** to the keyboard.
**
*/
If (not exiting) Then
If (read ok) Then
Search input data for Ctrl\
Allocate a read buffer call allocate_io_buffer
If (got a buffer) Then
Call PTD$WRITE to write characters to pseudoterminal
ASTADR = ft_echo_ast
ASTPRM = allocated I/O buffer
WRTBUF = read I/O buffer
WRTBUF_LEN = number of characters read
ECHOBUF = allocated I/O buffer
ECHOBUF_LEN = 500
Else
Call PTD$WRITE to write characters to pseudoterminal
WRTBUF = read I/O buffer
WRTBUF_LEN = number of characters read
Endif
If (write setup ok)
If ( (write status is ok) or (write status is SS$_DATALOST) )
Issue another single character read to terminal with
ASTADR = kbd_read_ast, with data going to read I/O buffer
If (read setup failed) Then
Set exit flag
Set exiting reason to SS$_NORMAL
Endif
Else
Set exit flag
Set exiting reason to SS$_NORMAL
Endif
Else
Set exit flag
Set exiting reason to SS$_NORMAL
Endif
Else
Set exit flag
Set exiting reason to read failure status
Endif
If (exiting) Then
Wake the mainline call SYS$WAKE
Endif
Endif
/*
** terminal_output_ast
**
** Function: This routine is called every time an I/O buffer is written
** to the terminal. If the terminal write request completes successfully,
** it inserts the I/O buffer into the queue of I/O buffers to be logged.
** If the I/O buffer is the only entry on the queue, it issues a SYS$WAKE
** to start the main routine. To prevent spurious wake requests,
** SYS$WAKE is not issued if multiple entries are already on
** the queue. If a terminal write error occurs, the routine sets the
** exit flag and wakes the main routine.
**
*/
If (terminal write completed ok) Then
insert I/O buffer onto logging queue
If (this is only entry on queue) Then
wake the mainline call SYS$WAKE
Endif
Else
set exit flag
set exiting reason to terminal write error reason
wake the mainline call SYS$WAKE
Endif
/*
**
** ft_read_ast
**
** Function: This routine is called when a pseudoterminal read request
** completes. It writes the buffer to the terminal and attempts to start
** another read from the pseudoterminal. If the program is not exiting,
** this routine writes the buffer to the terminal and does not start another
** pseudoterminal read.
**
*/
If (not exiting)
If (Pseudoterminal read ok) Then
write buffer to the terminal ASTADR = terminal_output_ast
If (write setup ok) Then
Allocate another read buffer call allocate_io_buffer
If (got a buffer) Then
Call PTD$READ to restart reads from the pseudoterminal.
ASTADR = ft_read_ast
ASTPRM = buffer address
READBUF = I/O buffer + 8
READBUF_LEN = 500
If (read setup failed) Then
Set exit flag
Set exiting reason to read failure reason
Wake the mainline call SYS$WAKE
Endif
Else
Set read stopped flag
Endif
Else
Set exit flag
Set exiting reason to terminal write failure reason
Wake the mainline call SYS$WAKE
Endif
Else
Set exit flag
Set exiting reason to terminal read failure reason
Wake the mainline call SYS$WAKE
Endif
Endif
/*
**
** ft_echo_ast
**
** Function: This routine is called if a write to the pseudoterminal used
** an ECHO buffer. If any data was echoed, the output is written to the
** terminal. If no data was echoed, the I/O buffer is freed so it can be
** used later. If the program is exiting, this routine exits.
**
*/
If (not exiting) Then
If (ECHO buffer has data) Then
Write the buffer to the terminal with ASTADR = terminal_output_ast
If (error setting up write) Then
Set exit flag
Set exiting reason to write failure reason
Wake mainline call SYS$WAKE
Endif
Else
Free I/O buffer call free_io_buffers
Endif
Endif
/*
** free_io_buffers
**
** Function: This routine places a free I/O buffer on the queue of available
** I/O buffers. It also restarts any stopped read operations from the
** pseudoterminals. This routine disables AST delivery while it is running
** in order to synchronize reading and resetting the read stopped flag.
**
*/
If (not exiting) Then
Disable AST deliver using SYS$SETAST
If (Pseudoterminal reads not stopped) Then
Insert I/O buffer on the interlocked queue of free I/O buffers
Else
Call PTD$READ to restart reads from the pseudoterminal.
ASTADR = ft_read_ast
ASTPRM = buffer address
READBUF = I/O buffer + 8
READBUF_LEN = 500
If (no error starting read) Then
Clear read stopped flag
Else
Set exit flag
Set exit reason to read setup reason
Endif
Endif
Enable AST delivery using SYS$SETAST
Endif
/*
**
** allocate_io_buffer
**
** Function: This routine obtains a free I/O buffer from the queue of
** available I/O buffers. If the program is exiting, this routine
** returns an SS$_FORCEDEXIT error.
**
*/
If (not exiting) Then
remove a I/O buffer from the interlocked queue of I/O buffers
If (queue empty) Then
exit with reason LIB$_QUEWASEMP
else
exit with reason SS$_FORCEDEXIT
Endif
/*
** subprocess_exit
**
** Function: This routine is called when the subprocess has completed
** and exited. This routine checks whether the program is already exiting.
** If not, then the routine indicates that the program is exiting and wakes
** up the main program.
**
*/
If (not exiting) Then
indicate subprocess no longer running
set exit status to SS$_NORMAL
indicate exiting
call SYS$WAKE to start up main loop
Endif
/*
** xon_ast
**
** Function: This routine is called for the pseudoterminal driver to signal
** that it is ready to accept keyboard input. The routine attempts to send
** an XON character to the terminal by sending XON DC1 using SYS$QIO.
** If the attempt fails, it is not retried.
**
*/
If (not exiting) Then
call SYS$QIO to send a <DC1>character to the terminal
Endif
/*
** bell_ast
**
** Function: This routine is called when the pseudoterminal driver wants
** to warn the user to stop sending keyboard data. The routine attempts
** to ring the terminal bell by sending the BELL character to the terminal
** using SYS$QIO. If the attempt fails, it is not retried.
**
*/
If (not exiting) Then
call SYS$QIO to send a <BELL>character to the terminal
Endif
/*
** xoff_ast
**
** Function: This routine is called when the pseudoterminal driver wants to
** signal that it will stop accepting keyboard input. The routine attempts
** to send an XOFF character to the terminal by sending XOFF DC3 to the
** terminal using SYS$QIO. If the attempt fails, it is not retried.
**
*/
If (not exiting) Then
call SYS$QIO to send a <DC3>character to the terminal
Endif
/*
** set_line_ast
**
** Function: This routine is called when the pseudoterminal device
** characteristics change. The routine reads the current pseudoterminal
** characteristics, changes the characteristics to set PASTHRU and NOECHO,
** and applies the characteristics to the input terminal. If the attempt
** to alter the terminal characteristics fails, it is not retried.
**
*/
If (not exiting) Then
call SYS$QIOW to read the pseudoterminals characteristics
If (not error) Then
Set the alter the just read characteristics to have PASTHRU and NOECHO
attributes
call SYS$QIO to set the terminal characteristics.
Endif
Endif |