MAINSAIL STREAMS User's Guide, Chapter 11

previous   next   top   contents   index   framed top   this page unframed


11. TTY Streams: TTYSTR

TTY streams communicate with TTY-like devices, including the controlling terminal, serial lines, and a parent process that is communicating with the current (child) process through a pseudoterminal. TTY streams have special characteristics that often must be taken into account by the programmer, including keyboard interrupts, echo, and line editing.

Every implementation of the STREAMS package guarantees at least one TTY stream connected to the controlling terminal. This stream is always available in the STREAMS system variable $tty. In some cases, $tty may be a half-duplex TTY, that is, $isHalfDuplex(tty) is TRUE. Half-duplex TTYs have restricted functionality (see Section 11.8).

Some systems support the ability to open an auxiliary serial port with terminal-like characteristics. On such systems, TTY streams to serial lines other than the controlling terminal may be opened using a name of the form ttystr>xxx, where xxx is the (operating-system- and installation-dependent) name of the terminal line.

11.1. $tty

The controlling terminal is opened automatically by the STREAMS package and is available through the STREAMS system variable $tty. Input from the initial $tty stream comes from the keyboard and output usually goes to the screen, unless the primary input and output of the MAINSAIL process were somehow redirected by some external means.

File I/O done on files opened with the NTTY device MODULE always goes through the current $tty stream. When cmdFile and logFile are opened through NTTY, they also go through the $tty stream.

If programs using $tty open or access the controlling terminal through non-STREAMS means, the mode setting logic for the controlling terminal may be confused and the redirection of $tty subverted. Such access therefore has undefined effects.

On systems that support the stream MODULEs PTYPRO and PROCESS, these may be used to start external processes in which $tty is not the physical terminal. The processes that may be run may possibly be restricted to MAINSAIL and specially written non-MAINSAIL processes on some systems.

11.2. Meaning of $eos on TTY Streams

On input, the $eos error return means that there is no more input available. This condition might be due to the user typing a special control character (such as CTRL-D under UNIX). In that case, a subsequent input may get more data. Alternatively, the $eos return might indicate a permanent condition, such as the end of a batch job input file.

On output, $eos means that no more data can be written.

11.3. TTY-Specific I/O Bits

TTY streams have some additional characteristics not present in other stream types. They are also unable to send or receive certain octet values (i.e., special control characters) unless some special bits are specified to the stream I/O PROCEDUREs. The characteristics of TTY streams include:

When $text is read from a TTY stream in $line mode, and no special TTY-specific bits are set, reading occurs in units of lines, line editing characters are available to the user at the keyboard to correct mistakes on input, and the characters read are echoed to the output end of the stream.

When any of the buffering bits other than $line is used for TTY input, both line editing and the echoing of input to the output are disabled until a read is done from the TTY stream in which $line is specified.

When text is written to a TTY stream in $line mode, eol characters are modified as necessary to cause the cursor to move to the beginning of the next line. Typically it is necessary to supply both a carriage return character and a linefeed character to the actual physical terminal. When output is done in a buffering mode other than $line, e.g., $unbuffered, no such manipulation of eol characters takes place. It is then the program's responsibility to ensure that the desired sequence of characters is sent. That sequence is available as the $stream field $unbufferedEol.

For example, under UNIX, the STRING eol contains the single character linefeed. If this alone were output to most terminals, the cursor would not move back to the first column of the screen; i.e.:

$writeStream($tty,"Hi" & eol & "Hi")

would produce:

Hi
  
Hi

while either:

$writeStream($tty,"Hi" & eol & "Hi",$line)

or:

$writeStream($tty,"Hi" & $tty.$unbufferedEol & "Hi")

would produce:

Hi
Hi

Aside from the side effects of echoing and eol manipulation associated with $line, the $line and $unbuffered bits work for TTYs as they do for all other streams. The $fillBuffer and $packet buffering modes are of little use for TTY streams because such streams are unreliable when connected to a physical terminal line. However, these modes might be useful over a TTY stream that is connected to a parent process instead of a physical terminal.

System-specific interrupt characters and flow control characters introduce a slight complication into programming a TTY stream. By default, interrupt characters have a special effect and are not passed to the program. The flow control characters are not available to the program, either for reading or writing.

Unless some special bits are set for TTY stream I/O, the programmer must be careful not to expect to read octets that correspond to interrupt or flow control characters or to write flow control characters and have them received at the other end of a TTY stream. Since these characters are usually nonprinting characters, normal applications do not need to worry about this limitation. However, special applications such as screen editors and terminal emulators must take special action.

To vary these characteristics from the default, additional ctrlBits bits are provided for the stream input functions. The additional bits are:

These bits are ignored for non-TTY streams or in implementations where they cannot be supported.

For example, to read a character without echo and without waiting for an eol, $cReadStream($tty,$text!$unbuffered) could be used, provided that $tty is not a half-duplex terminal. The program may want to echo the character it read. If it does not do so explicitly, the user does not see any echo.

The system PROCEDURE ttycWrite(char) functions similarly to $cWriteStream($tty,char,$text!$line). To cause char to be displayed immediately rather than waiting for an eol (full-duplex systems only), $cWriteStream($tty,char,$text!$unbuffered) could be used instead. However, when $unbuffered is set, it is the responsibility of the program to make sure that the sequence of characters $tty.unbufferedEol is output at the end of a line. This character sequence is not necessarily the same as the STRING constant eol.

11.4. TTY-Specific PROCEDUREs

Figure 11–1. TTY-Specific PROCEDUREs
LONG INTEGER
PROCEDURE   $getBaudRate
                        (
POINTER($streamst;
                         
OPTIONAL BITS ctrlBits);

BOOLEAN
PROCEDURE   $setBaudRate
                        (
POINTER($streamst;
                         
LONG INTEGER baud;
                         
OPTIONAL BITS ctrlBits);

LONG INTEGER
PROCEDURE   $writeStreamBreak
                        (
POINTER($streamst;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

The PROCEDURE $getBaudRate returns the baud rate of the TTY stream st, 0L if the rate is unknown, and negative failure values if st is not a valid stream or some other error occurs.

The PROCEDURE $setBaudRate sets the baud rate of the TTY stream st to baud, returning TRUE if it was successful and FALSE otherwise.

Setting errorOK in ctrlBits for these procedures suppresses a fatal error message; the error text is then put in st.$lastInputError.

The PROCEDURE $writeStreamBreak sends a BREAK on a TTY stream, returning a nonnegative value if the function is implemented and succeeds, or a negative failure value otherwise. Breaks are typically read as one or more null characters (i.e., $nulChar). Setting errorOK in ctrlBits suppresses a fatal error message; the error text is then put in st.$lastOutputError.

$writeStreamBreak is implemented for PTY streams as well as TTY streams; see Section 11.9.1.

11.5. TTY-Specific Fields of $stream

The TTY-specific fields of $stream give the character sequences corresponding to specially interpreted characters (normally these are control characters) that may be typed by the user to cause special actions.

Figure 11–2. TTY-Specific Fields of $stream
STRING
    
$unbufferedEol; # How to write eol in $unbuffered
                    # 
modeThis is typically a two-
                    # 
character STRINGeven though
                    # 
length(eol) = 1.

INTEGER
    # 
Characters received in $unbuffered mode when:
    
$returnKey,     # A return key is pressed
    
$linefeedKey,   # A linefeed key is pressed
    
$eofIndicator,  # An end-of-file character is typed

    # 
Line editing characters for this TTY:
    
$erase,         # Erase the most recent character sent
    
$altErase,      # Erase the most recent character sent
    
$wordErase,     # Erase the most recent word sent
    
$lineErase,     # Erase the entire line
    
$reprint,       # Reprint the current line being input
    
$quoteNext,     # quote the next character

    # 
Flow control characters for this TTY:
    
$startOutput,   # An XON (e.g., CTRL-Q)
    
$stopOutput,    # An XOFF (e.g., CTRL-S)

    # 
Interrupt characters for this TTY:
    
$interrupt,     # The interrupt character
    
$discardOutput; # Clear (discardpending output

If any of the functions implied by these fields is not supported by a given system, the corresponding characters are -1. The only fields that are guaranteed to be defined are $unbufferedEol, $returnKey, and $erase.

Using these character field definitions, a program that wishes to read characters in a mode other than $line may intelligently interpret the special incoming character sequences according to the host system conventions to achieve each of these functions.

The $startOutput and $stopOutput characters tell a program what characters are reserved for flow control (unless $noFlow mode is in effect).

The complete set of characters reserved for interrupts may not be determined. The character $interrupt is the standard interrupt character (the one that may possibly be trapped by the STREAMS package and that otherwise causes program termination) if such a character is available for this system and TTY. The character $discardOutput is the character the user may type to discard the pending output to the terminal. Neither of these characters may be read from the TTY unless $noInterrupt is set.

11.6. Is My $tty Interactive?

A program may determine whether its $tty has the characteristics of a true terminal or not. If not, it should not expect interaction with a real user.

IF $isaTty($ttyTHEN # I am interactive or PTYPRO
EL                    # I am batch or PROCESS

On UNIX, a program for which $isaTty($tty) is FALSE might also be running with its standard input coming from a pipe or file set up by the shell.

This test works if the system supports a means to determine the difference between an interactive and “batch” terminal. Otherwise, $isaTty(st) always returns TRUE.

11.7. Am I a Cooperative Child?

A program may determine whether its parent expects to talk to it through the $parent stream by checking whether $parent is NULLPOINTER, e.g.:

IF $parent THEN # I am a cooperative child

Cooperative children may or may not have an interactive TTY.

11.8. Half-Duplex TTY Streams

On half-duplex TTY streams, the only allowed buffering bit for input is $line. For output, both the $unbuffered (default) and $line bits are supported, but $unbuffered text output may not behave differently from $line output. The programmer must use adaptive programming tests in a portable program to find alternative methods if the program would normally perform $unbuffered, $packet, or $fillBuffer I/O and it is to be run on a half-duplex system, e.g.:

IF NOT $isHalfDuplex(stTHEN
    # 
Full-Duplex Case
    
$readStream(st,...,$unbuffered);
EB # Half-Duplex CaseCannot turn off echo
    
positionCursorToTopOfScreen(st); # user-supplied function
    
$readStream(st,...,$line);
    
repositionCursor(stEND;        # user-supplied function

11.9. PTY Streams

When PTYPRO is used to start a child coroutine (see Chapter 7), the child's $tty is set up to communicate directly with the parent's PTY stream. As far as the child is concerned, its $tty has all of the characteristics of an interactive terminal, including echo, interrupts, and flow control. However, in fact, what it reads is supplied by the parent coroutine that opens the PTY, and what it writes is supplied to the parent on the PTY.

PTY is an acronym for “pseudo-TTY”. The interaction of the parent program with the PTY is much like the interaction of a user with a terminal keyboard and screen. It is the “other end” of the child process's $tty.

Interaction Between PTY and $tty
In the Parent Coroutine   In the Child Coroutine
$writeStream(pty,...); sends its output to $readStream($tty,...);
$readStream(pty,...); gets its input from $writeStream($tty,...);

The coroutine that opens the PTY stream is responsible for simulating a person sitting at a terminal. It must write characters to the PTY to simulate typing at the keyboard and read characters from the PTY that would normally appear on the screen (including echo of the characters it wrote).

On systems that support process creation and control, PTY streams may be used to create and talk to an independent program running in a separate (child) process external to the creating (parent) process. On systems that support transparent pseudoterminals, any program may be run through the PTY without restriction, not just MAINSAIL programs. On such systems, the standard system “shell” (command interpreter) may be run.

To the child process that is running through the PTY, everything appears as if it were connected to a true interactive terminal. The child process may turn echo on and off, read characters in $line or $unbuffered mode, interpret interrupt characters specially or not, and interpret flow control specially or not as it chooses. The parent process itself does not use these modes when reading from or writing to the PTY.

PTY streams are used to communicate with child processes when the details of the interaction are unknown to the program that opens the PTY. Typically, the program that opens a PTY serves merely as an intermediary that accepts keystrokes from a user (passing them on to the child process) and displays the resultant input from the PTY on the screen. For example, a window manager can use PTYs to implement a window that talks to a separate job.

The only buffering mode that makes sense in general for both input and output on PTYs is $unbuffered. The output is made available to the child process immediately. The child process may or may not choose to buffer when it does its input, but that is entirely separate. PTY input should be done in $unbuffered mode since it is based on the available characters written by the child. Because the exact interaction expected by the child is generally unknown, it is not generally useful to perform input from the PTY in $line mode (doing so could cause the parent to fail to display, e.g., a prompt not terminated by eol, until after the text responding to the prompt had been set, an undesirable interaction).

The use of PTY streams to control child processes is described in Section 7.4.

On both input and output, $eos means that the process controlled by the PTY is no longer alive.

There are no PTY-specific I/O bits. The only buffering mode supported is $unbuffered.

11.9.1. PTY-Specific PROCEDUREs

Figure 11–3. PTY-Specific PROCEDUREs
LONG INTEGER
PROCEDURE   $writeStreamBreak
                        (
POINTER($streampty;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

LONG INTEGER
PROCEDURE   $writeStreamInterrupt
                        (
POINTER($streampty;
                         
OPTIONAL BITS ctrlBits;
                         
OPTIONAL LONG INTEGER timeout);

The PROCEDURE $writeStreamBreak sends a BREAK on a PTY stream, returning a nonnegative value if the function is implemented, or a negative failure value otherwise. Breaks are typically read on the other end as one or more null characters (i.e., $nulChar). Setting errorOK in ctrlBits suppresses a fatal error message; the error text is then put in pty.$lastOutputError.

The PROCEDURE $writeStreamInterrupt signals an interrupt to the child process. If the child has not enabled itself to catch the interrupt or if interrupt catching is not implemented, the child will probably be killed. The bit errorOK suppresses error messages. An OPTIONAL timeout may be given to return early if the PROCEDURE blocks.

In addition, a PTY stream pty has an associated character pty.$interrupt. If this character is nonnegative, it causes an interrupt if it is written to the PTY using $cWriteStream or as part of a $writeStream, e.g., $cWriteStream(pty,pty.$interrupt).

11.9.2. PTY-Specific Fields of $stream

The PTY-specific fields give the character sequences corresponding to specially interpreted characters (normally these are control characters) that may be typed by the user to cause special actions. These are the same as the TTY-specific fields (see Figure 11–2).

If any of the fields is not supported by a given system, the corresponding character is -1. The only fields that are guaranteed to be defined are $unbufferedEol, $returnKey, and $erase.


previous   next   top   contents   index   framed top   this page unframed

MAINSAIL STREAMS User's Guide, Chapter 11