Document revision date: 30 March 2001

## OpenVMS RTL Screen Management (SMG$) Manual

Previous | Contents | Index

Because string capability fields often include nonprinting characters, the following substitutions are used to make it easy to insert these characters in a capability string. Use the special character to represent the nonprinting character.

Special Character | Nonprinting Character | Meaning
--- | --- | ---
$ | ESCAPE | ASCII decimal value 27
^ | CONTROL | Control
& | CSI | ASCII decimal value 155
@ | SS3 | ASCII decimal value 143

Thus to create a capability string that contains an escape character, you insert a dollar sign at that position. To create a capability string that contains a control character, prefix the character with a circumflex (^). For example:

    NAME = "VT300_series"

       .
       .
       .

        STRING
            begin_alternate_char = "^N",
            end_alternate_char = "^O",
            erase_whole_display = "$[2J"

       .
       .
       .

    END

If you want to use a character in a capability string with its normal ASCII value, place an underscore in front of it. (For example, "_$" results in a single dollar sign rather than an underscore followed by an escape character). The following characters must be preceded by an underscore in order to be treated as normal ASCII text:

Ampersand | &
Apostrophe | '
At sign | @
Quotation marks | "
Circumflex | ^
Dollar sign | $
Exclamation point | !
Left parenthesis | (
Underscore | _

The Screen Management Facility automatically invokes the graphics mode needed to display the line-drawing character set (for example, the bottom_t_char, top_t_char, and so on). However, if you call the foreign terminal routines directly, you are responsible for invoking the required graphics mode.

Padding (for example, with null characters) must sometimes be added to a terminal command to allow the terminal sufficient time to execute the command. The amount of padding needed depends on the terminal and the baud rate. The pad character capability field is included only for future expansion and has no function in this release; padding is the responsibility of the user.

When the foreign terminal support routines are called directly, many of the string capability fields use arguments whose values must be specified at run time. Further, some arguments also require that arithmetic operations be performed when values are substituted for arguments. The following sections describe argument substitution and arithmetic operations.

### 5.2.4 Argument Substitution

It is frequently necessary to substitute values in a terminal command string. For example, setting a scrolling region or moving the cursor ten columns to the right requires the run-time substitution of a value; these values cannot be stored in the TERMTABLE terminal definition. TERMTABLE provides for string substitution by accepting !UL, an $FAO style directive. The !UL directive signifies that a value is to be inserted at that point: the TERMTABLE interface routine is to accept an unsigned longword and convert it to ASCII digits before substituting it in the capability field string (and thus in the returned command string). For example:

    NAME = "VT300_series"

       .
       .
       .

        STRING
        set_cursor_abs = "$[!UL;!ULH"

       .
       .
       .

    END

The string defined for the SET_CURSOR_ABS function must have values substituted for the two !UL directives; these values specify the row and column number at which to set the cursor. You specify these run-time arguments as an optional longword vector argument to the SMG$GET_TERM_DATA routine. The first entry in the vector contains the number of arguments that follow. Thus, the first entry is 2, the second entry is the desired row number, and the third entry is the desired column number. The SMG$GET_TERM_DATA routine converts the first optional data item (the second item in the vector) to ASCII digits and substitutes an ASCII value for the first !UL directive; it converts the second optional data item and substitutes it for the second !UL directive, and so on.

### 5.2.5 Arithmetic Operations

In addition to argument substitution, terminal command sequences may also require arithmetic operations. To perform an argument substitution and arithmetic operation, the TERMTABLE entry requires a different scheme than for argument conversion and substitution.

To perform both argument substitution and arithmetic operations, you use an opening parenthesis, a percent sign (to indicate the point of substitution), an arithmetic operator, an operand, and a closing parenthesis. For example:

    NAME = "VT52"

       .
       .
       .

        STRING
        set_cursor_abs = "$Y(%1+31)(%2+31)"

       .
       .
       .

    END

This example shows the string that directly positions the cursor on a VT52, where a bias must be added to the row and column numbers. Values to be substituted in the expression are passed with the SMG$GET_TERM_DATA routine, in the same way as for argument substitution alone. The percent sign is always followed by an integer that indicates the order in which arguments should be substituted.

The following table summarizes the characters used in arithmetic operations:

Character | Meaning
--- | ---
( | Beginning of arithmetic expression
% n | Substitute nth user argument
+ | Arithmetic addition operator
- | Arithmetic subtraction operator
* | Arithmetic multiplication operator
/ | Arithmetic division operator
) | End of arithmetic expression

Longword integers are sufficient to express screen coordinates. Expressions are evaluated from left to right; there is no operator precedence.

Spaces between items are not significant; they may be used wherever desired to improve readability. Capability strings are limited to 128 bytes in length.

## 5.3 Creating an OpenVMS Terminal Capabilities File

The source code for the database is an ASCII file named TERMTABLE.TXT. This file contains an entry for each type of terminal. Each entry lists a terminal's capabilities and other device-specific information, such as initialization sequences and screen size; a TERMTABLE entry can span more than one record in the file. A terminal definition can be added by editing the TERMTABLE.TXT file; TERMTABLE.TXT must then be reprocessed by running SYS$SYSTEM:SMGBLDTRM.EXE.

TERMTABLE.TXT can be created with any text editor. A TERMTABLE entry consists of a terminal name, followed by any number of capability fields and their values (see Section 5.2 for more information about capability fields). Although TERMTABLE.TXT must be formatted for compilation, capability names are descriptive and can be easily understood. Terminal names must be unique; for example, if more than one definition is needed for a foreign terminal, then a second name must be used.

When a TERMTABLE routine first searches for a terminal entry, it tries to find TERMTABLE.EXE in the area logically named TERM$TABLOC. If the specified terminal entry is not found there, the routine then searches for TERMTABLE.EXE in SYS$SYSTEM. If you want to use a terminal definition that differs from the system definition for that terminal, you can create a private copy of TERMTABLE.TXT and TERMTABLE.EXE. You can then define a single terminal with a definition that is different from the one in SYS$SYSTEM:TERMTABLE.EXE and still use the rest of the standard system definitions.

The format of a TERMTABLE entry is as follows:

`NAME = "terminal-name" capability-field [,...] END`

The TERMTABLE.TXT file allows you to include REQUIRE directives. The REQUIRE directive lets you include separate source files in the TERMTABLE.TXT file. Its format is as follows:

`REQUIRE "filespec"`

In the above format, "filespec" is a valid OpenVMS file specification.

## 5.4 Examples

The following example contains sample terminal definitions for the TERMTABLE.TXTfile; these entries contain device-specific information for a VT300 terminal and a VT52 terminal.

    !
    !       Private versions of Compaq terminal definitions
    !
    NAME = 'myvt300'

            BOOLEAN
            ansi_crt = 1,           dec_crt = 1

            NUMERIC
            rows = 24,              columns = 80,
            wide_screen_columns = 132

            STRING
            begin_alternate_char = "^N",
            end_alternate_char = "^O",
            erase_whole_display = "$[2J",
            init_string = "$_(B",
            set_cursor_abs = "$[!UL;!ULH"
    END

    NAME = "MYVT52"

            BOOLEAN
            ansi_crt = 0,           dec_crt = 1

            NUMERIC
            rows = 24,              columns = 80,
            wide_screen_columns = 80

            STRING
            begin_alternate_char = "$F"
            end_alternate_char = "$G",
            erase_whole_display = "$Y(32)(32)$J",  !position to 1,1; then erase
            set_cursor_abs = "$Y(%1+31)(%2+31)"

    END

For the set cursor sequence listed for a VT300 series (MYVT300), the string returned depends on the values provided in the argument vector supplied with the call to the SMG$GET_TERM_DATA routine. For example, to position the cursor to row 3 and column 12, you supply these longword values as the second and third entries in the vector (the first entry is the number of values that follow). The SMG$GET_TERM_DATA routine converts these longword values into their ASCII values and inserts the converted values into the string returned at the point of the respective !UL directives.

For the set cursor sequence listed for a VT52 (MYVT52), the string returned depends not on argument substitution, but on an arithmetic operation (because the VT52 requires biasing). The arithmetic operator is used to add 31 (decimal) to the row and column numbers supplied in entries 2 and 3 of the argument vector for the SMG$GET_TERM_DATA routine.

The INIT_STRING field in MYVT300 is included to point out that the parenthesis is normally treated as a special character indicating an arithmetic expression. A parenthesis must be preceded by an underscore in order to be interpreted as a normal text character. Thus the string "$_(B" yields ESC(B, a command that designates the ASCII character set into G0.

The ERASE_WHOLE_DISPLAY sequence for MYVT52 shows that it may be necessary to combine sequences in order to provide a certain function. The VT52 does not have a command that erases the entire screen. However, you can erase the entire screen by homing the cursor and then using the command that erases from the current position to the end of the screen.

The following BASIC example program uses the LIB$GETDVI routine to ascertain the type of terminal associated with SYS$OUTPUT. The program then uses the foreign terminal routines to place the cursor at the twelfth screen line and to erase to the end of the screen. The program detects whether these capabilities are available for the terminal and displays an error message if they are not.

    10  ! Program to call the Termtable interface routines
        !
        ! This program sets the cursor to row 12 column 1,
        ! and erase to the bottom of the screen.  If the cursor
        ! positioning or erasing to the end of the screen
        ! capabilities are not defined, a message is output.

        %INCLUDE "$SMGTRMPTR" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET"
        OPTION TYPE = EXPLICIT, SIZE = INTEGER LONG

        EXTERNAL INTEGER FUNCTION SYS$ASSIGN, SYS$DASSGN, SYS$QIOW
        EXTERNAL INTEGER FUNCTION LIB$GETDVI, LIB$GET_EF, LIB$FREE_EF
        EXTERNAL INTEGER FUNCTION SMG$INIT_TERM_TABLE_BY_TYPE, SMG$GET_TERM_DATA

        EXTERNAL INTEGER CONSTANT IO$_WRITEVBLK, DVI$_DEVTYPE

        COMMON (buf) STRING Data_buffer = 20         ! buffer to hold terminal data

        DECLARE INTEGER Sys_status,                   &
                        Chan,                         &
                        Term_type,                    &
                        Term_table_addr,              &
                        Arg_vector (2),               &
                        Ret_len,                      &
                        Event_flag

        ! Assign a channel for LIB$GETDVI and SYS$QIOW.

        Sys_status = SYS$ASSIGN ('SYS$OUTPUT', Chan, , , )

        IF (Sys_status AND 1%) = 0%
        THEN
          PRINT "Error from SYS$ASSIGN : ";Sys_status
          GOTO Done
        END IF

        ! Get the terminal type.

        Sys_status = LIB$GETDVI (DVI$_DEVTYPE   ! request item code              &
                                 ,Chan          ! channel assigned to SYS$OUTPUT &
                                 ,              ! omit device name               &
                                 ,Term_type)    ! place to return type

        IF (Sys_status AND 1%) = 0%
        THEN
          PRINT "Error from LIB$GETDVI : ";Sys_status
          GOTO Done
        END IF

        ! Get the definition for the type of terminal we are running on.

        Sys_status =  SMG$INIT_TERM_TABLE_BY_TYPE (Term_type, Term_table_addr)

        IF (Sys_status AND 1%) = 0%
        THEN
          PRINT "Error getting terminal definition : ";Sys_status
          GOTO Done
        END IF

        ! Get the sequence to position the cursor to 12,1

        Arg_vector (0) = 2%             ! number of args to follow
        Arg_vector (1) = 12%            ! row number
        Arg_vector (2) = 1%             ! column number

        Sys_status = SMG$GET_TERM_DATA                                        &
                        ( Term_table_addr       ! addr of terminal definition &
                          ,SMG$K_SET_CURSOR_ABS ! request code                &
                          ,20%                  ! max buffer length           &
                          ,Ret_len              ! length of sequence returned &
                          ,Data_buffer BY REF   ! buffer to hold sequence     &
                          ,Arg_vector (0) )     ! optional vector with
                                                ! row and column numbers

        IF (Sys_status AND 1%) = 0%
        THEN
          PRINT "Error getting cursor sequence : ";Sys_status
          GOTO Done
        END IF

        IF Ret_len = 0%
        THEN
          PRINT "Cursor sequence not available"
          GOTO Done
        END IF

        ! Get a unique event flag number

        Sys_status = LIB$GET_EF (Event_flag)

        IF (Sys_status AND 1%) = 0%
        THEN
          PRINT "Unable to allocate an event flag"
          GOTO Done
        END IF

        ! Output the cursor sequence to the terminal.

        Sys_status = SYS$QIOW ( Event_flag BY VALUE     ! event flag number  &
                                ,Chan BY VALUE          ! channel number     &
                                ,IO$_WRITEVBLK BY VALUE ! function code      &
                                , , ,                   ! no iosb,           &
                                                        ! ast routine,       &
                                                        ! or  argument       &
                                ,Data_buffer BY REF     ! buffer to output   &
                                ,Ret_len BY VALUE       ! bytes returned     &
                                , , , , )               ! null arguments

        IF (Sys_status AND 1%) = 0%
        THEN
          PRINT "Error from SYS$QIOW : ";Sys_status
          GOTO Done
        END IF

        ! Get the sequence to erase from current cursor to end of screen.

        Sys_status = SMG$GET_TERM_DATA                                           &
                             ( Term_table_addr ! addr of terminal definition     &
                               ,SMG$K_ERASE_TO_END_DISPLAY ! request code        &
                               ,20%                        ! max buffer length   &
                               ,Ret_len                    ! bytes returned      &
                               ,Data_buffer BY REF)        ! buffer for sequence

        IF (Sys_status AND 1%) = 0%
        THEN
          PRINT "Error getting erase sequence : ";Sys_status
          GOTO Done
        END IF

        IF Ret_len = 0%
        THEN
          PRINT "Erase sequence not available"
          GOTO Done
        END IF

        ! Output the erase sequence to the terminal.

        Sys_status = SYS$QIOW (Event_flag BY VALUE          ! event flag number    &
                                    ,Chan BY VALUE          ! channel number       &
                                    ,IO$_WRITEVBLK BY VALUE ! function code value  &
                                    , , ,                   ! no iosb,             &
                                                            ! ast routine,         &
                                                            ! or  argument         &
                                    ,Data_buffer BY REF     ! buffer to output     &
                                    ,Ret_len BY VALUE       ! bytes in buffer      &
                                    , , , , )               ! null arguments

        IF (Sys_status AND 1%) = 0%
        THEN
          PRINT "Error from SYS$QIOW : ";Sys_status
          GOTO Done
        END IF

        ! Deassign the channel.

        Sys_status = SYS$DASSGN (Chan BY VALUE)

        IF (Sys_status AND 1%) = 0%
        THEN
          PRINT "Error from SYS$DASSGN : ";Sys_status
          GOTO Done
        END IF

        ! Deallocate event flag so other programs can use it.

        Sys_status = LIB$FREE_EF (Event_flag)

        IF (Sys_status AND 1%) = 0%
        THEN
          PRINT "Unable to deallocate event flag"
          GOTO Done
        END IF

    32767  Done: END

## 5.5 Creating TERMTABLE.EXE

Accessing an ASCII file for each screen program is inefficient because the ASCII text must be processed as binary information before it can be returned as a string ready for the terminal. To avoid paying the price of this processing at the start of every image, TERMTABLE.TXT is "precompiled" into the required binary format. A screen application then gets its terminal sequences from the precompiled binary capabilities file.

Compile TERMTABLE.TXT by running the SYS$SYSTEM:SMGBLDTRM.EXE program. This utility accepts TERMTABLE.TXT as an input file and creates TERMTABLE.EXE as an output file on the device and directory pointed to by the logical TERM$TABLOC.

The compiled terminal capabilities are stored as a table in a file which is mapped as a permanent global section. Thus, user programs map to the global section rather than having their own copies of the capabilities data.

If a user compiles a private TERMTABLE.TXT from his or her own directory, the interface routines access it by mapping it as a temporary section. TERMTABLE interface routines look for a definition in the temporary section before looking in the system's permanent global section.

Note that system managers may want to coordinate terminal definitions so that nonstandard definitions are confined to a user's private area.

Most users do not have the privilege to create a permanent global section. A short program, SYS$SYSTEM:SMGMAPTRM.EXE, that maps the compiled TERMTABLE as a global section, is part of the standard OpenVMS startup procedure. In order to map an updated TERMTABLE.EXE as the global section, the existing global section must first be deleted. Deleting the global section while the system is active may cause a user's program to fail; therefore the system must be rebooted in order to make an updated TERMTABLE.EXE the default.

To reduce compiling time and the size of the resulting global section, the terminal definitions in SYS$SYSTEM:TERMTABLE.TXT should be kept to a minimum. Only the types of terminals that are actually attached to the computer system should be defined.

## 5.6 Capability Fields Used by Screen Management

The tables in Section 5.2 show whether or not the Screen Management Facility can request a particular capability string. Some functions, such as wide characters or line drawing, are requested only if the user calls the screen management routines that output wide text or draw lines. If all you want to do is write normal text to the screen, only the following set of fields needs to be defined.

Essential Capabilities

- NAME
- SET_CURSOR_ABS

If SET_CURSOR_ABS is omitted, the Screen Management Facility treats the terminal as a hardcopy device. (For more information on using the Screen Management Facility with a hardcopy device, refer to SMG$SNAPSHOT

Operation of the Screen Management Facility is more efficient if the following optional capabilities are also provided:

- ERASE_TO_END_DISPLAY
- ERASE_TO_END_LINE
- SET_SCROLLING_REGION

If you do not include ERASE_TO_END_DISPLAY, ERASE_TO_END_LINE, or SET_SCROLLING_REGION, the Screen Management Facility inserts blanks to perform these functions. However, inserting blanks is a slower operation. Similarly, hardware scrolling also improves output speed; if scrolling is not available, the Screen Management Facility must rewrite the entire screen.

The Screen Management Facility uses the ASCII character set. If your terminal has a line-drawing character set, you should define the line drawing characters (bottom_t_char, horizontal_bar, and so forth). If line-drawing characters are not defined, the Screen Management Facility uses normal ASCII characters to draw borders.

The Screen Management Facility also relies on the terminal characteristics maintained by the terminal driver. You can change these characteristics with the DCL command SET TERMINAL. For example, if you type SET TERMINAL/NOTAB, then the Screen Management Facility does not send tabs to the terminal.

Previous | Next | Contents | Index

| privacy and legal statement |
5935PRO_006.HTML