Document revision date: 30 March 2001

## OpenVMS I/O User's Reference Manual

Previous | Contents | Index

The VAX MACRO program READ_VERIFY.MAR (Example 5-3) shows the read verify function. The program shows a typical build of itemlists (both the right and left fields), channel assignment, a right- and left-justified read verify operation, and then the read QIO operation.

Example 5-3 READ_VERIFY.MAR Terminal Driver Programming Example

            .TITLE READ_VERIFY - Read Verify Coding Example
            .IDENT  'V05-000'

            .SBTTL  DECLARATIONS
            .DISABLE        GLOBAL

    ;
    ; Declare the external system routines and MACRO libraries.
    ;
            .EXTERNAL       LIB$GET_EF
            .EXTERNAL       SCR$ERASE_PAGE

            .LIBRARY        'SYS$LIBRARY:LIB.MLB'
            .LIBRARY        'SYS$LIBRARY:STARLET.MLB'
    ;
    ; Include files:
    ;
            $IODEF
            $TRMDEF
    ;
    ; Macros:
    ;
    .MACRO ITEM LEN=0,CODE,VALUE
            .WORD   LEN
            .WORD   TRM$_'CODE'
            .LONG   VALUE
            .LONG   0
    .ENDM ITEM

    ;
    ; Equated symbols:
    ;
    INBUF_LEN = 20
    ESC = ^X1B

    ;
    ; Own storage:
    ;
    ; Build item lists for the read verify QIO
    ;

    ;
    ; Right-justified field
    ;
    R_ITEM_LIST:
            ITEM    CODE    = MODIFIERS, -
                    VALUE   = TRM$M_TM_R_JUST       ; Right justify

            ITEM    CODE    = EDITMODE, -
                    VALUE   = TRM$K_EM_RDVERIFY     ; Enable read verify

            ITEM    CODE    = PROMPT, -
                    VALUE   = R_PROMPT_ADDR, -
                    LEN     = R_PROMPT_LEN          ; Set up prompt

            ITEM    CODE    = INISTRNG, -
                    VALUE   = R_INISTR_ADDR, -
                    LEN     = R_INISTR_LEN          ; Set up initial string

            ITEM    CODE    = INIOFFSET, -
                    VALUE   = R_INISTR_LEN

            ITEM    CODE    = PICSTRNG, -
                    VALUE   = R_PICSTR_ADDR, -
                    LEN     = R_PICSTR_LEN          ; Set up picture string

            ITEM    CODE    = FILLCHR, -
                    VALUE   = <^A/* />            ; clear = *, fill = space

    R_ITEM_LIST_LEN = .-R_ITEM_LIST

    R_PROMPT_ADDR:
            .ASCII  <ESC>  /[12;12H$/
    R_PROMPT_LEN = .-R_PROMPT_ADDR

    R_INISTR_ADDR:
            .ASCII  /   ,   /
    R_INISTR_LEN = .-R_INISTR_ADDR

    MASK = TRM$M_CV_NUMERIC!TRM$M_CV_NUMPUNC

    R_PICSTR_ADDR:
            .BYTE   MASK
            .BYTE   MASK
            .BYTE   MASK
            .BYTE   0               ; Marker character
            .BYTE   MASK
            .BYTE   MASK
            .BYTE   MASK
    R_PICSTR_LEN = .-R_PICSTR_ADDR
    ;
    ; Left-justified field
    ;
    L_ITEM_LIST:
            ITEM    CODE    = MODIFIERS, -
                    VALUE   = TRM$M_TM_CVTLOW!TRM$M_TM_AUTO_TAB
                                                    ; Upcase input and
                                                    ; complete on field full

            ITEM    CODE    = EDITMODE, -
                    VALUE   = TRM$K_EM_RDVERIFY     ; Enable read verify

            ITEM    CODE    = PROMPT, -
                    VALUE   = L_PROMPT_ADDR, -
                    LEN     = L_PROMPT_LEN          ; Set up prompt

            ITEM    CODE    = INISTRNG, -
                    VALUE   = L_INISTR_ADDR, -
                    LEN     = L_INISTR_LEN          ; Set up initial string

            ITEM    CODE    = INIOFFSET, -
                    VALUE   = 0

            ITEM    CODE    = PICSTRNG, -
                    VALUE   = L_PICSTR_ADDR, -
                    LEN     = L_PICSTR_LEN          ; Set up picture string

            ITEM    CODE    = FILLCHR, -
                    VALUE   = <^A/* />              ; clear = *, fill = space

    L_ITEM_LIST_LEN = .-L_ITEM_LIST

    L_PROMPT_ADDR:
            .ASCII  <ESC>/[13;12H Enter Date: /
    L_PROMPT_LEN = .-L_PROMPT_ADDR

    L_INISTR_ADDR:
            .ASCII  /  -   -  /
    L_INISTR_LEN = .-L_INISTR_ADDR

    MASK1 = TRM$M_CV_NUMERIC
    MASK2 = TRM$M_CV_UPPER!TRM$M_CV_LOWER

    L_PICSTR_ADDR:
            .BYTE   MASK1
            .BYTE   MASK1
            .BYTE   0               ; Marker character
            .BYTE   MASK2
            .BYTE   MASK2
            .BYTE   MASK2
            .BYTE   0               ; marker character
            .BYTE   MASK1
            .BYTE   MASK1
    L_PICSTR_LEN = .-L_PICSTR_ADDR

    IN_IOSB:        .BLKL   2
    TT_CHAN:        .BLKW   1
    INBUF:          .BLKB   INBUF_LEN
    SYSINPUT:       .ASCID  /SYS$INPUT/
    SYNC_EFN:       .BLKL   1

            .PAGE

            .ENTRY  READ_VERIFY     ^M < >

    ;
    ; Get the required event flags.
    ;

            PUSHAL  SYNC_EFN
            CALLS   # 1, G^ LIB$GET_EF
            BLBC    R0, ERROR                       ; Error - branch
    ;
    ; Assign the channel to SYS$INPUT
    ;

            $ASSIGN_S -
                    CHAN = TT_CHAN -
                    DEVNAM = SYSINPUT               ; SYS$INPUT
            BLBC    R0, ERROR                       ; Branch on error

    ;
    ; Clear the screen
    ;

            CLRQ    -(SP)
            CALLS   #2, G^ SCR$ERASE_PAGE
            BLBC    R0, ERROR

    ;
    ; Do the right-justified read operation
    ;

            PUSHL   #R_ITEM_LIST_LEN
            PUSHAB  R_ITEM_LIST
            CALLS   #2, DO_READ
            BLBC    R0, ERROR

    ;
    ; Do the left-justified read operation
    ;

            PUSHL   #L_ITEM_LIST_LEN
            PUSHAB  L_ITEM_LIST
            CALLS   #2, DO_READ
            BLBC    R0, ERROR

    ERROR:
            RET

            .PAGE
    ;++
    ;
    ; DO_READ - do the actual QIO
    ;
    ; Inputs:
    ;
    ;       4(AP)   the address of the itemlist
    ;       8(AP)   the length of the itemlist
    ;
    ;--

            .ENTRY  DO_READ, ^M<>

            $QIOW_S EFN=SYNC_EFN, -
                    CHAN = TT_CHAN, -
                    FUNC = #<IO$_READVBLK!IO$M_EXTEND>, -
                    IOSB = IN_IOSB, -
                    p1 = inbuf, -
                    p2 = #inbuf_len, -
                    p5 = 4(AP), -
                    P6 = 8(AP)
            BLBC    R0, 10$                 ; QIO error - branch
            MOVZWL  IN_IOSB, R0             ; Get the terminal driver status.
            BLBC    R0, 10$                 ; Terminal driver error - branch

    ;  Handle the input...

    10$:
            RET
            .END READ_VERIFY

## Chapter 6
Pseudoterminal Driver

This chapter describes the use of the pseudoterminal driver (FTDRIVER) and the pseudoterminal software.

A pseudoterminal is a software device that appears as a real terminal to an application communicating with it, but does not require the existence of a physical terminal. A pseudoterminal consists of two components: the pseudoterminal device and a control program. The control program acts like a keyboard; that is, anything written to the control program appears on the pseudoterminal device as if the keystrokes had been typed in at a physical terminal. The control program also acts like a viewport to the pseudoterminal device; that is, the control program reads anything that is written by the system to the pseudoterminal device.

A pseudoterminal allows an application to be set up on the control side of the link to communicate with another application that is on the pseudoterminal side. This arrangement allows development of applications that either simulate users or monitor the communication between a real user (at a physical terminal) and an application. As with other devices, the work of the pseudoterminal is performed by a device driver and is tightly coupled to the operating system.

The pseudoterminal driver software includes a set of control connection routines. Applications can use these routines to perform pseudoterminal operations and functions. Appendix D provides the calling conventions for these routines.

## 6.1 Pseudoterminal Operations

This section contains information on the following pseudoterminal operations:

- Creating a pseudoterminal
- Canceling a request
- Deleting a pseudoterminal

### 6.1.1 Creating a Pseudoterminal

To create a pseudoterminal, use the PTD$CREATE routine described in Appendix D. When a pseudoterminal is created, it inherits the current system terminal default attributes unless you specify an alternate set of characteristics. In either case, you cannot use PTD$CREATE to alter the following startup attributes:

- TT$M_CRFILL is cleared. To change this attribute, issue the SET MODE $QIO function.
- TT$M_LFFILL is cleared. To change this attribute, issue the SET MODE $QIO function.
- TT$M_MODEM is cleared. This attribute cannot be changed.
- TT$M_REMOTE is cleared. This attribute cannot be changed.
- TT$M_HOSTSYNC is set. To change this attribute, issue the SET MODE $QIO function.
- TT$M_TTSYNC is set. To change this attribute, issue the SET MODE $QIO function.
- TT2$M_DMA is cleared. To change this attribute, issue the SET MODE $QIO function. Changing it does not alter the behavior of TTDRIVER or the pseudoterminal.
- TT2$M_AUTOBAUD is cleared. To change this attribute, issue the SET MODE $QIO function. Changing it does not alter the behavior of TTDRIVER or the pseudoterminal.
- TT2$M_FALLBACK is cleared. To change this attribute, issue the SET MODE $QIO function.
- TT2$M_HANGUP is cleared. To change this attribute, issue the SET MODE $QIO function.
- TT2$M_DCL_MAILBX is cleared. This attribute cannot be changed.

When you create a pseudoterminal, you can specify a repeating asynchronous system trap (AST) to be delivered when the terminal connection is freed. This AST can be supplied only when the pseudoterminal is created, and it cannot be deleted. A terminal is freed when a process logs out or deassigns the last channel to the device. The AST allows the control program to determine whether or not a user of a pseudoterminal is using it. At this point, the control program can reuse or delete the pseudoterminal by deassigning the control channel.

### 6.1.2 Canceling a Request

To cancel a queued control connection request, the control program uses the PTD$CANCEL routine. This routine enables the pseudoterminal driver to differentiate between control requests and terminal requests that are being canceled. This routine cannot be used to flush event notification ASTs.

### 6.1.3 Deleting a Pseudoterminal

To delete the pseudoterminal, the control program uses the PTD$DELETE routine. When a pseudoterminal is deleted, any process that is using the pseudoterminal (except the control process) is disconnected. If you have the TT2$M_DISCONNECT bit set in the default terminal characteristics parameter (TTY_DEFCHAR2) and virtual terminals have been enabled (see Section 5.2.2.3), you get a virtual terminal upon logging in to a pseudoterminal. In this case, the process is not logged out, but the virtual terminal is disconnected from the pseudoterminal.

The PTD$DELETE request causes any pending I/O for the control program to be aborted. It deletes any queued event notification ASTs and returns the I/O buffers to the application. It also causes the pseudoterminal unit control block (UCB) to be deleted once the reference count returns to zero.

Note If an application exits without calling PTD$DELETE, the pseudoterminal is still deleted.

## 6.2 Pseudoterminal Driver Features

The terminal portion of a pseudoterminal is similar to a regular terminal. The pseudoterminal driver provides the following features:

- Type-ahead buffer
- Specifiable or default line terminators
- Special operating modes, such as NOECHO and PASTHRU
- Escape sequence detection
- Terminal/mailbox interaction
- Terminal control characters, such as Ctrl/S and Ctrl/Q for starting and stopping output, Ctrl/O for discarding output, and all other special characters that are handled by the standard terminal driver
- Limited full-duplex operation (simultaneously active read and write requests)

For more information on these features, see Section 5.2.

## 6.3 Pseudoterminal Driver Device Information

The pseudoterminal inherits its device characteristics from the system default parameters, with the following exceptions:

- The device inherits initial device characteristics from the SYSGEN-supplied default values. You can modify the device characteristics during device creation by supplying new characteristics.
- The HOSTSYNC terminal characteristic is always set.
- The device is set to NOMODEM and cannot be set to MODEM.
- The device is set not to time output character transmission. Hardware controllers time output character transmission to determine whether the controller is broken.

You can obtain information on pseudoterminal characteristics by using the Get Device/Volume Information ($GETDVI) system service, as described in Section 5.3 and the OpenVMS System Services Reference Manual.

Applications should assign a channel other than the control channel in order to read data from, write data to, read, or alter the pseudoterminal characteristics. An attempt to perform such I/O with the control channel, or any other attempt to queue an illegal or unsafe I/O request, results in an SS$_CHANINTLK error.

## 6.4 I/O Buffers

When you create a pseudoterminal, you must provide at least one page to be used as an I/O buffer.

On Alpha systems, you can allocate one page and divide it into I/O buffers as needed.

On VAX systems, each page becomes one I/O buffer. You should allocate no more than six I/O buffers for each pseudoterminal.

No read or write request should reference more than one I/O buffer at a time. The I/O buffers must be page aligned; therefore, you should create these pages with the $EXPREG system service or the LIB$GET_VM_PAGE routine. The pages are owned by the driver until you delete the pseudoterminal. The application is responsible for managing the pages and cannot use buffers that are owned by another pseudoterminal. The application must decide whether to delete the buffers when they are freed by the driver or to reuse them.

The I/O buffers must be valid pages in virtual address space. Creating or deleting an I/O buffer does not alter the contents of the pages.

The low-order word of the status information longword contains the status of the request. The high-order word of the status information longword contains the actual number of bytes that are read or written.

Assume that an I/O buffer starting at 200 hexadecimal is available for use. If you want to read 20 bytes from the pseudoterminal, the readbuf address would be 200, and the readbuf_len would be 20. An application can use the rest of this buffer for other purposes, including reading or writing to the pseudoterminal. Figure 6-1 shows how the buffer would look.

Figure 6-1 Buffer Layout

## 6.5 Pseudoterminal Functions

This section discusses the following pseudoterminal functions:

- Reading data
- Writing data
- Using write with echo
- Flow control
- Event notification

### 6.5.1 Reading Data

To read data from the pseudoterminal, the control program uses the PTD$READ routine. The read request completes with a minimum of one character and a maximum of the number of characters requested. The read operation completes when the pseudoterminal has characters to output. If a read request is issued and no data is available, the read request is queued and then completed at a later time.

An application that issues an asynchronous pseudoterminal read can use the $SYNCH system service to find out when the read completed. The efn argument for the $SYNCH service must be the same as the efn specified in the original PTD$READ call, and the iosb for the $SYNCH service must match the readbuf of the PTD$READ call.

### 6.5.2 Writing Data

To write data to the pseudoterminal, the control program uses the PTD$WRITE routine. The write request allows you to specify a buffer to receive any output that the write request generates; you do not need to issue a separate read request to read this data. When you use an echo buffer, the control application can significantly reduce the number of I/O requests required.

An application can issue only one write request at a time. Once the write request completes, the application must check the write buffer status longword to see whether all the data supplied was written. If not, the application must issue additional write requests until all the data has been accepted.

### 6.5.3 Using Write with Echo

If a read request is pending when a write-with-echo request is issued, the echo data is placed in the echo buffer. If more data is echoed than can fit in the echo buffer, the remaining data is placed in the pending read requests buffer. If no pending read exists, the data is held by the driver until another request that can take the data is issued. Both the read and the write with echo must use completion ASTs to allow the driver to report request completions to the application in the correct order.

If an application is not using the write-with-echo capability, the application should avoid using completion ASTs if possible. Unnecessary use of completion ASTs significantly increases the number of instructions needed to complete a read or write operation.

When using write with echo, both the wrtbuf and echobuf arguments contain I/O status information. An application must check both of these status longwords if the PTD$WRITE completes successfully. If a write operation wrote no characters, characters might still be in the echo buffer. If no data was echoed, the status in the echobuf is SS$_NORMAL with zero bytes transferred.

### 6.5.4 Flow Control

By default, the driver attempts to notify the control program of data overrun or loss. The pseudoterminal sends an XOFF AST when the type-ahead buffer is getting full. Once the pseudoterminal delivers an XOFF AST, the pseudoterminal also returns a status of SS$_DATAOVERUN with the actual number of characters input. This prevents a single request from flooding the type-ahead buffer. If a control program makes repeated attempts to insert data after receiving the SS$_DATAOVERUN message, it can flood the terminal type-ahead buffer. When the type-ahead buffer has filled, the pseudoterminal returns the status of SS$_DATALOST.

If the control program is writing to the terminal or terminal driver, it should let the terminal and terminal driver handle flow control. To do this, the application should enable all three input flow control notification ASTs. The control program should write a DC1 to the terminal if an XON AST is delivered. It should write a DC3 to a terminal if an XOFF AST is delivered, and write a BELL character to the terminal if the BELL AST is delivered. These signals allow the terminal to decide what to do with the flow control data. The application should ignore the SS$_DATAOVERUN and SS$_DATALOST return status and continue writing data to the pseudoterminal.

### 6.5.5 Event Notification

This section describes how the pseudoterminal driver provides notification of important driver events.

#### 6.5.5.1 Input Flow Control

The driver provides three ways to indicate when the class driver wants to stop input and one way to signal when it is safe to resume output:

- The driver returns a status of SS$_DATAOVERUN and the number of characters input for the control program write.
- The control program can enable a BELL attention AST to be delivered when the class driver calls the PTD$SET_TERMINAL_NOTIFICATION routine. This AST is delivered if the pseudoterminal does not have the HOSTSYNC attribute set. If only a BELL or only an XOFF AST event is enabled and an XOFF or a BELL AST needs to be delivered, the AST that is available is delivered.
- The control program can enable an XOFF attention AST to be delivered when the class driver calls the PTD$SET_TERMINAL_NOTIFICATION routine. This AST is delivered if the pseudoterminal has the HOSTSYNC attribute set.
- The control program can enable an XON attention AST to be delivered when the class driver calls the PTD$SET_TERMINAL_NOTIFICATION routine. This AST is delivered only if the pseudoterminal has the HOSTSYNC attribute set.

#### 6.5.5.2 Output Stop

The Output Stop AST tells the control program that the terminal driver is stopping output. This keeps the control program from having to determine whether an XOFF written to the control side is being treated by the terminal driver as flow control or data.

#### 6.5.5.3 Output Resume

The Output Resume AST tells the control program that the terminal driver wants to resume output. This AST can be delivered at any time, even if output is active or has previously been stopped. The control program should always restart output processing when it receives this AST.

#### 6.5.5.4 Characteristics Changed

The Characteristics Changed AST tells the control program that the terminal driver has called the pseudoterminal CHANGE CHARACTERISTICS routine. This routine is called whenever the terminal driver has changed the device characteristics. The control program should then read the pseudoterminal characteristics to determine what has changed.

#### 6.5.5.5 Output Abort

The Output Abort AST tells the control program that the terminal driver has called the pseudoterminal ABORT OUTPUT routine. This routine is called when the terminal driver wants to flush any outstanding output data. The control program should flush any internally buffered data when this AST is received.

#### 6.5.5.6 Terminal Driver Read Events

Three special event types notify the control program when a terminal read request starts and finishes. By default, the pseudoterminal does not deliver the read notification ASTs associated with these events. The PTD$SET_EVENT_NOTIFICATION routine must be used explicitly to enable or disable their delivery.

- Start Read---Tells the control program that the terminal driver is starting a read request. Some applications require this in order to know when to start inputting a logged session script.
- Middle Read---Tells the control program that the terminal driver has finished writing the prompt string if one was supplied.
- End Read---Tells the control program that the terminal driver has finished a read request.

Once an event notification AST is enabled, it continues to be delivered until it is canceled, or until the device is deleted. This characteristic allows the control program to enable the AST once, which greatly reduces the risk of missing multiple rapid occurrences of an event. If the driver cannot get sufficient resources to deliver the notification AST, that report is lost. Only one AST per event is allowed, and attempts to specify multiple ASTs result in use of the last one specified.

To enable or disable event notification, the control program uses the PTD$SET_EVENT_NOTIFICATION routine, which is described in Appendix D.

## 6.6 Pseudoterminal Driver Programming Example

Example 6-1 shows how to use the pseudoterminal. (The example is also included in the SYS$EXAMPLES directory.) This section begins with a brief overview of the example. The example itself briefly discusses each module; the pseudocode for that module follows its discussion.

The scenario chosen for this example is a simple terminal session logging utility that uses most of the pseudoterminal capabilities. This example also shows how to use the write-with-echo capability, which provides a significant gain in performance.

Previous | Next | Contents | Index

| privacy and legal statement |
6136PRO_025.HTML