Programming Concepts Manual, Volume II
- Operating System and Version:
- VSI OpenVMS IA-64 Version 8.4-1H1 or higher
VSI OpenVMS Alpha Version 8.4-2L1 or higher
VSI OpenVMS x86-64 Version 9.2-1 or higher
Preface
1. About VSI
VMS Software, Inc. (VSI) is an independent software company licensed by Hewlett Packard Enterprise to develop and support the OpenVMS operating system.
2. Intended Audience
This manual is intended for system and application programmers. It presumes that its readers have some familiarity with the VSI OpenVMS programming environment, derived from the OpenVMS Programming Environment Manual and OpenVMS high-level language documentation.
3. Document Structure
Part I, “OpenVMS Programming Interfaces: Calling a System Routine”, OpenVMS Programming Interfaces: Calling a System Routine
Part II, “I/O, System, and Programming Routines”, I/O, System, and Programming Routines
Part III, “Appendixes and Glossary”, Appendixes and Glossary
Chapter 1, Call Format to OpenVMS Routines describes the format used to document system routine calls and explains where to find and how to interpret information about routine calls.
Chapter 2, Basic Calling Standard Conventions describes the concepts and conventions used by common languages to invoke routines and pass data between them.
Chapter 3, Calling Run-Time Library Routines describes a set of language-independent routines that establishes a common run-time environment for user programs.
Chapter 4, Calling System Services describes the system services available to application and system programs for use at run-time.
Chapter 5, STARLET Structures and Definitions for C Programmers describes the libraries that contain C header files for routines.
Chapter 6, Run-Time Library Input/Output Operations describes the different I/O programming capabilities provided by the run-time library.
Chapter 7, System Service Input/Output Operations describes how to use system services to perform input and output operations.
Chapter 8, Using Run-Time Library Routines to Access Operating System Components describes the run-time library (RTL) routines that allow access to various operating system components.
Chapter 9, Using Cross-Reference Routines describes how cross-reference routines that are contained in a separate, shareable image are capable of creating across-reference analysis of symbols.
Chapter 10, Shareable Resources describes the techniques available for sharing data and program code among programs.
Chapter 11, System Time Operations describes the system time format, and the manipulation of date/time and time conversion. It further describes how to obtain and set the current date and time, how to set and cancel timer requests, and how to schedule and cancel wakeups. The Coordinated Universal Time (UTC) system is also described.
Chapter 12, File Operations describes file attributes, strategies to access files, and file protection techniques.
Chapter 13, Overview of Extended File Specifications (Alpha and I64 Only) presents an overview of Extended File Specifications (for the OpenVMS Alpha and I64 platforms only).
Chapter 14, Distributed Transaction Manager (DECdtm) describes the DECdtm programming interfaces, and the DECdtm X/Open Distributed Transaction Processing XA interface.
Chapter 15, Creating User-Written System Services describes how to create user-written system services with privileged shareable images for VAX, Alpha, and I64 systems.
Chapter 16, System Security Services describes the system services that establish protection by using identifiers, rights databases, and access control entries. This chapter also describes how to modify a rights list as well as check access protection.
Chapter 17, Authentication and Credential Management (ACM) System Service (Alpha and I64 Only) describes how to write an authentication and credential management (ACM) client program or update existing programs to be an ACM client program.
Chapter 18, Logical Name and Logical Name Tables describes how to create and use logical name services, how to use logical and equivalence names, and how to add and delete entries to a logical name table.
Chapter 19, Image Initialization describes how to use the LIB$INITIALIZE routine to initialize an image.
Appendix A, Generic Macros for Calling System Services describes the use of generic macros to specify argument lists with appropriate symbols and conventions in the system services interface to MACRO assembles.
Appendix B, OpenVMS Data Types describes the data types that provide compatibility between procedure calls that support many different high-level languages.
Appendix C, Distributed Name Service Clerk (VAX Only) describes the DIGITAL Distributed Name Service (DECdns) Clerk by introducing the functions of the DECdns (SYS$DNS) system service and various run-time library routines.
Authentication Glossary contains definitions for terms used in Chapter 17, Authentication and Credential Management (ACM) System Service (Alpha and I64 Only).
4. Related Documents
For a detailed description of each run-time library and system service routine mentioned in this manual, see the OpenVMS Run-Time Library documentation and the VSI OpenVMS System Services Reference Manual.
VSI OpenVMS DCL Dictionary
VSI OpenVMS User's Manual
VSI OpenVMS Guide to OpenVMS File Applications
VSI OpenVMS Guide to System Security
VSI OpenVMS DECnet Networking Manual
OpenVMS Record Management Services documentation
VSI OpenVMS Utility Routines Manual
VSI OpenVMS I/O User's Reference Manual
5. VSI Encourages Your Comments
You may send comments or suggestions regarding this manual or any VSI document by sending electronic mail to the following Internet address: <docinfo@vmssoftware.com>
. Users who have VSI OpenVMS support contracts through VSI can contact <support@vmssoftware.com>
for help with this product.
6. OpenVMS Documentation
The full VSI OpenVMS documentation set can be found on the VMS Software Documentation webpage at https://docs.vmssoftware.com.
7. Typographical Conventions
The following conventions are used in this manual:
Convention | Meaning |
---|---|
Ctrl/x | A sequence such as
Ctrl/x
indicates that you must hold down the key labeled Ctrl while you
press another key or a pointing device button. |
PF1
x | A sequence such as PF1
x indicates that you
must first press and release the key labeled PF1 and then press and
release another key (x )
or a pointing device button. |
Enter | In examples, a key name in bold indicates that you press that key. |
… |
A horizontal ellipsis in examples indicates one of the
following possibilities:
|
. . . | A vertical ellipsis indicates the omission of items from a code example or command format; the items are omitted because they are not important to the topic being discussed. |
( ) | In command format descriptions, parentheses indicate that you must enclose choices in parentheses if you specify more than one. |
[ ] | In command format descriptions, brackets indicate optional choices. You can choose one or more items or no items. Do not type the brackets on the command line. However, you must include the brackets in the syntax for directory specifications and for a substring specification in an assignment statement. |
| | In command format descriptions, vertical bars separate choices within brackets or braces. Within brackets, the choices are optional; within braces, at least one choice is required. Do not type the vertical bars on the command line. |
{ } | In command format descriptions, braces indicate required choices; you must choose at least one of the items listed. Do not type the braces on the command line. |
bold type | Bold type represents the name of an argument, an attribute, or a reason. In command and script examples, bold indicates user input. Bold type also represents the introduction of a new term. |
italic type | Italic type indicates important information, complete titles of manuals, or variables. Variables include information that varies in system output (Internal error number), in command lines (/PRODUCER=name), and in command parameters in text (where dd represents the predefined code for the device type). |
UPPERCASE TYPE | Uppercase type indicates a command, the name of a routine, the name of a file, or the abbreviation for a system privilege. |
Example |
This typeface indicates code examples, command examples, and interactive screen displays. In text, this type also identifies website addresses, UNIX commands and pathnames, PC-based commands and folders, and certain elements of the C programming language. |
– | A hyphen at the end of a command format description, command line, or code line indicates that the command or statement continues on the following line. |
numbers | All numbers in text are assumed to be decimal unless otherwise noted. Nondecimal radixes—binary, octal, or hexadecimal—are explicitly indicated. |
Part I. OpenVMS Programming Interfaces: Calling a System Routine
This part of this second volume describes the basic calling format for OpenVMS routines and system services. It also describes the STARLET structures and definitions for C programmers.
Chapter 1. Call Format to OpenVMS Routines
Note
- VSI OpenVMS System Services Reference Manual: A-GETUAI
- VSI OpenVMS System Services Reference Manual: GETUTC-Z
- OpenVMS Run-Time Library manuals
- VSI OpenVMS Utility Routines Manual
- VSI OpenVMS Record Management Services Reference Manual
1.1. Overview
Format
Returns
Arguments
Condition values returned
Main Heading | Description |
---|---|
Routine Name |
Always present. The routine entry point name appears at the top of the first page. It is usually followed by the English text name of the routine. |
Routine Overview |
Always present. Appears directly below the routine name and briefly explains what the routine does. |
Format |
Always present. Follows the routine overview and gives the routine entry point name and the routine argument list. |
Returns |
Always present. Follows the routine format and explains what information is returned by the routine. |
Arguments |
Always present. Follows the Returns heading and gives detailed information about each argument. If a routine takes no arguments, the word None appears. |
Description |
Optional. Follows the Arguments heading and contains information about specifications taken by the routine: interaction between routine arguments, if any; operation of the routine within the context of OpenVMS; user privileges needed to call the routine, if any; system resources used by the routine; and user quotas that might affect the operation of the routine. Note that any restrictions on the use of the routine are always discussed first in the Description section. For example, any required user privileges or necessary system resources are explained first. For some simple routines, a Description section is not necessary because the routine overview provides the needed information. |
Condition Values Returned |
Always present. Follows the Description section and lists the condition values (typically status or completion codes) that are returned by the routine. |
Example |
Optional. Follows the Condition Values Returned heading and contains one or more programming examples that illustrate how to use the routine, followed by an explanation. All examples under this heading are complete. They have been tested and should run when compiled (or assembled) and linked. Throughout the manuals that document system routines, examples are provided in as many different programming languages as possible. |
1.2. Format Heading
Procedure call format
Explanatory text
Jump to Subroutine (JSB) format (VAX only)
On VAX processors, all system routines have a procedure call format, but few system routines have JSB formats. If a routine has a JSB format, the format always appears after the routine's procedure call format.
1.2.1. Procedure Call Format
Element |
Syntax Rule |
---|---|
Entry point names |
Entry point names are always shown in uppercase characters. |
Argument names |
Argument names are always shown in lowercase characters. |
Spaces |
One or more spaces are used between the entry point name and the first argument, and between each argument. |
Braces ({}) |
Braces surround two or more arguments. You must choose one of the arguments. |
Brackets ([]) |
Brackets surround optional arguments. Note that commas can also be optional (see the comma element). Note that programming language syntax for optional arguments differs between languages. Refer to your language user's guide for more information. |
Commas (,) |
Between arguments, the comma always follows the space. If the argument is optional, the comma might appear either inside or outside the brackets, depending on the position of the argument in the list and on whether surrounding arguments are optional or required. |
Null arguments |
A null argument is a placeholding argument. It is used for
one of the following reasons: (1) to hold a place
in the argument list for an argument that has not yet been
implemented by VSI but might be in the future; or
(2) to mark the position of an argument that was
used in earlier versions of the routine but is not used in
the latest version (upward compatibility is thereby ensured
because arguments that follow the null argument in the
argument list keep their original positions). A null
argument is always given the name
In the argument list constructed when a procedure is called, both null arguments and omitted optional arguments are represented by argument list entries containing the value 0. The programming language syntax required to produce argument list entries containing 0 differs from language to language. See your language user's guide for language-specific syntax. |
Format 1
This format illustrates the standard representation of optional arguments and best describes the use of commas as delimiters. Arguments enclosed within square brackets are optional. In most languages, if an optional argument other than a trailing optional argument is omitted, you must include a comma as a delimiter for the omitted argument.
ROUTINE_NAME arg1[, [arg2][, arg3]]
Typically, OpenVMS RMS system routines use this format when a maximum of three arguments appear in the argument list.
Format 2
When the argument list contains three or more optional arguments, the syntax does
not provide enough information. If you omit the optional arguments
arg3
and arg4
and specify the
trailing argument arg5
, you must use commas to delimit the
positions of the omitted arguments.
ROUTINE_NAME arg1, [arg2], nullarg, [arg3],[arg4], arg5
Typically, system services, utility routines, and run-time library routines contain call formats with more than three arguments.
Format 3
In the following call format, the trailing four arguments are optional as a group;
that is, you specify either arg2
,
arg3
, arg4
, and
arg5
, or none of them. Therefore, if you do not specify
the optional arguments, you need not use commas to delimit unoccupied
positions.
However, if you specify a required argument or a separate optional argument after
arg5
, you must use commas when
arg2
, arg3
,
arg4
, and arg5
are omitted.
ROUTINE_NAME arg1[, arg2, arg3, arg4, arg5]
Format 4
In the following example, you can specify arg2
and omit
arg3
. However, whenever you specify
arg3
, you must specify
arg2
.
ROUTINE_NAME arg1[, arg2[, arg3]]
1.2.2. JSB Call Format (VAX only)
The JSB call format indicates that the named routine is called using the VAX JSB instruction. The routine returns using Return from Subroutine (RSB). You can use the JSB call format with only the VAX MACRO and VAX BLISS languages.
Explanatory Text
Explanatory text might follow the procedure call format or the JSB call format, or both. This text is present only when needed to clarify the format. For example, in the call format, you indicate that arguments are optional by enclosing them in brackets ([]). However, brackets alone cannot convey all the important information that might apply to optional arguments. For example, in some routines that have many optional arguments, if you select one optional argument, you must also select another optional argument. In such cases, text following the format clarifies this.
1.3. Returns Heading
The Returns heading contains a description of any information returned by the routine to the caller. A routine can return information to the caller in various ways. The following subsections discuss each possibility and then describe how this returned information is presented.
1.3.1. Condition Values Returned in a Register
Most routines return a condition value in register R0. This condition value contains various kinds of information, the most important for the caller (in bits <3:0>) being the completion status of the operation. You test the condition value to determine whether the routine completed successfully. On OpenVMS I64, the calling standard specifies that return status is returned in R8. As an aid to portable code, the MACRO complier automatically maps R0 to R8. See the VSI OpenVMS MACRO Compiler Porting and User's Guide for additional information.
On Alpha and I64 processors, a 32-bit condition value is represented in the Alpha register sign-extended to 64 bits.
If you program in high-level languages for OpenVMS environments, the fact that status information is returned by means of a condition value and that it is returned in a hardware register is of little importance because you receive this status information in the return (or status) variable. The run-time environment established for the high-level language program allows the status information in R0 (R8, R9 for I64) to be moved automatically to the user's return variable.
OpenVMS usage: cond_value type: longword (unsigned) access: write only mechanism: by value
The OpenVMS usage entry specifies the OpenVMS data type of the information returned. Because a condition value in any OpenVMS operating system environment is returned in a specific condition value structure, the OpenVMS usage entry is cond_value.
The type entry specifies the standard data type of the information returned. Because the condition value structure is 32 bits, the type heading is longword (unsigned).
The access entry specifies the way in which the called routine accesses the object. Because the called routine is returning the condition value, the routine writes the value into R0 (R8, R9 for I64), so the access heading is write only.
The mechanism heading specifies the passing mechanism used by the called routine in returning the condition value. Because the called routine is writing the condition value directly into R0 (R8, R9 for I64), the mechanism heading is by value. (If the called routine had written the address of the condition value into R0 (R8, R9 for I64), the passing mechanism would have been by reference).
Note that if a routine returns a condition value, another main heading in the documentation format (Condition Values Returned) describes the possible condition values that the routine can return.
1.3.2. Other Returned Values
OpenVMS usage: floating_point type: G_floating access: write only mechanism: by value
In this mathematics routine notation, the OpenVMS data type is floating_point and the standard data type is G_floating point. The meaning of the contents of the access and mechanism headings is discussed in Sections 1.4.3 and 1.4.4.
The registers used to return values vary with the type of the result and the specific hardware environment. For more information, see the VSI OpenVMS Calling Standard.
In addition, under the Returns heading, some text can be provided after the information about the type, access, and mechanism. This text explains other relevant information about what the routine is returning.
For example, because the routine is returning actual data in the VAX, Alpha, or I64 registers, the registers cannot be used to convey completion status information. All routines that return actual data in VAX, Alpha, or I64 registers must signal the condition value, which contains the completion status. Thus, the text under the Returns heading points out that the routine signals its completion status.
1.3.3. Condition Values Signaled
Although most routines return condition values, some routines choose to signal their condition values using the OpenVMS signaling mechanism. Routines can signal their completion status whether or not they are returning actual data in the hardware registers, but all routines that return actual data in the hardware registers must signal their completion status if they are to return this status information at all.
If a routine signals its completion status, text under the Returns heading explains this, and the Condition Values Signaled heading in the documentation format describes the possible condition values that the routine can signal.
VSI's system routines never signal condition values indicating success. Only error condition values are signaled.
1.4. Arguments Heading
Detailed information about each argument is listed in the call format under the Arguments heading. Arguments are described in the order in which they appear in the call format. If the routine has no arguments, the word None appears.
argument-name OpenVMS usage: OpenVMS data type type: argument data type access: argument access mechanism: argument passing mechanism
A paragraph of structured text describing the arguments follows the argument format along with additional information, if needed.
1.4.1. OpenVMS Usage Entry
The purpose of the OpenVMS usage entry is to facilitate the coding of source-language data type declarations in application programs. Ordinarily, the standard data type, discussed in Section 1.4.2, “Type Entry”, is sufficient to describe the type of data passed by an argument. However, within the OpenVMS operating system environment, many system routines contain arguments whose conceptual nature or complexity requires additional explanation. For instance, when an argument passes the name of an event flag, the type entry longword (unsigned) alone does not indicate the nature of the value. In this instance, an accompanying OpenVMS usage entry, denoting the OpenVMS data type ef_number, further explains the actual usage.
See Table B.1, “OpenVMS Usage Data Type Entries” for a list of the possible OpenVMS usage entries and their definitions. Refer to the appropriate language implementation table in Appendix B, OpenVMS Data Types to determine the correct syntax of the type declaration in the language you are using.
Note that the OpenVMS usage entry is not a traditional data type (such as the standard data types of byte, word, longword, and so on). It is significant only within the context of the OpenVMS operating system and is intended solely to expedite data declarations within application programs.
1.4.2. Type Entry
In actuality, an argument does not have a data type; rather, the data specified by an argument has a data type. The argument is merely the vehicle for passing data to the called routine. Nevertheless, the phrase argument data type is used to describe the standard data type of the data specified by the argument.
Procedure calls result in the construction of an argument list. (This process is described in the VSI OpenVMS Calling Standard). An argument list is a sequence of entries together with a count of the number of entries.
On VAX systems, an argument list is represented as a vector of longwords, where the first longword contains the count and each remaining longword contains one argument.
On Alpha systems, an argument list is represented as quadword entities that comprise an argument item sequence, partly in hardware registers and (when there are more than six arguments for Alpha) partly on the stack. The argument information (AI) register contains the argument count that specifies the number of 64-bit argument items.
For I64 systems, parameters are passed in a combination of general registers, floating-point registers, and memory, as described in Chapter 2, Basic Calling Standard Conventions and as illustrated in Figure 2.12, “Parameter Passing in Registers and Memory”. The parameter list is formed by placing each individual parameter into fixed-size elements of the parameter list, referred to as parameter slots. Each parameter slot is 64 bits wide; parameters larger than 64 bits are placed in as many consecutive parameter slots as are needed to contain the entire parameter. The rules for allocation and alignment of parameter slots are described in Section 2.4.3.1, “Allocation of Parameter Slots”. The contents of the first eight parameter slots are always passed in registers, while the remaining parameters are always passed on the memory stack, beginning at the caller's stack pointer plus 16 bytes.
When arguments are passed by descriptors, these standard data types are defined with symbolic codes. Table 1.3, “Standard Data Types and Their Descriptor Field Symbols” lists the standard data types for VAX, Alpha, and I64 systems that can appear for the type entry in an argument description, along with their symbolic code (DTYPE) used in argument descriptors.
Data Type |
Symbolic Code |
---|---|
Absolute date and time |
DSC$K_DTYPE_ADT |
Byte integer (signed) |
DSC$K_DTYPE_B |
Bound label value |
DSC$K_DTYPE_BLV |
Bound procedure value? |
DSC$K_DTYPE_BPV |
Byte (unsigned) |
DSC$K_DTYPE_BU |
COBOL intermediate temporary |
DSC$K_DTYPE_CIT |
D_floating |
DSC$K_DTYPE_D |
D_floating complex |
DSC$K_DTYPE_DC |
Descriptor |
DSC$K_DTYPE_DSC |
F_floating |
DSC$K_DTYPE_F |
F_floating complex |
DSC$K_DTYPE_FC |
G_floating |
DSC$K_DTYPE_G |
G_floating complex |
DSC$K_DTYPE_GC |
H_floating ? |
DSC$K_DTYPE_H |
H_floating complex ? |
DSC$K_DTYPE_HC |
S_floating (32-bit IEEE)? |
DSC$K_DTYPE_FS |
T_floating (64-bit IEEE)? |
DSC$K_DTYPE_FT |
X_floating (128-bit IEEE)? |
DSC$K_DTYPE_FX |
S_floating complex? |
DSC$K_DTYPE_FSC |
T_floating complex? |
DSC$K_DTYPE_FTC |
X_floating complex? |
DSC$K_DTYPE_FXC |
Longword integer (signed) |
DSC$K_DTYPE_L |
Longword (unsigned) |
DSC$K_DTYPE_LU |
Numeric string, left separate sign |
DSC$K_DTYPE_NL |
Numeric string, left overpunched sign |
DSC$K_DTYPE_NLO |
Numeric string, right separate sign |
DSC$K_DTYPE_NR |
Numeric string, right overpunched sign |
DSC$K_DTYPE_NRO |
Numeric string, unsigned |
DSC$K_DTYPE_NU |
Numeric string, zoned sign |
DSC$K_DTYPE_NZ |
Octaword integer (signed) |
DSC$K_DTYPE_O |
Octaword (unsigned) |
DSC$K_DTYPE_OU |
Packed decimal string |
DSC$K_DTYPE_P |
Quadword integer (signed) |
DSC$K_DTYPE_Q |
Quadword (unsigned) |
DSC$K_DTYPE_QU |
Character string |
DSC$K_DTYPE_T |
Aligned bit string |
DSC$K_DTYPE_V |
Varying character string |
DSC$K_DTYPE_VT |
Unaligned bit string |
DSC$K_DTYPE_VU |
Word integer (signed) |
DSC$K_DTYPE_W |
Word (unsigned) |
DSC$K_DTYPE_WU |
Unspecified |
DSC$K_DTYPE_Z |
Procedure entry mask? |
DSC$K_DTYPE_ZEM |
Sequence of instruction? |
DSC$K_DTYPE_ZI |
1.4.3. Access Entry
Read only. Data upon which a routine operates, or data needed by the routine to perform its operation, must be read by the called routine. Such data is also called input data. When an argument specifies input data, the access entry is read only.
The term only is present to indicate that the called routine does not both read and write (that is, modify) the input data. Thus, input data supplied by a variable is preserved when the called routine completes execution.
Write only. Data that the called routine returns to the calling program must be written into a location where the calling program can access it. Such data is also called output data. When an argument specifies output data, the access entry is write only.
In this context, the term only is present to indicate that the called routine does not read the contents of the location either before or after it writes into the location.
Modify. When an argument specifies data that is both read and written by the called routine, the access entry is modify. In this case, the called routine reads the input data, which it uses in its operation, and then overwrites the input data with the results (the output data) of the operation. Thus, when the called routine completes execution, the input data specified by the argument is lost.
Read only
Write only
Modify
Function call (before return)
JMP after unwind
Call after stack unwind
Call without stack unwind
For more information, see the VSI OpenVMS Calling Standard.
1.4.4. Mechanism Entry
By value. When the argument in the argument list contains the actual data to be used by the routine, the actual data is said to be passed to the routine by value. In this case, the argument is the actual data.
By reference. When the argument in the argument list contains the address of the data to be used by the routine, the data is said to be passed by reference. In this case, the argument is a pointer to the data.
By descriptor. When the argument in the argument list contains the address of a descriptor, the data is said to be passed by descriptor. A descriptor consists of two or more longwords (depending on the type of descriptor used) that describe the location, length, and the OpenVMS standard data type of the data to be used by the called routine. In this case, the argument is a pointer to a descriptor that points to the actual data.
There are several kinds of descriptors. Each one contains a value, or class, in the fourth byte of the first longword. The class identifies the type of descriptor it is. Each class has a symbolic code.
Table 1.4, “Descriptor Classes of Passing Mechanisms” lists the types of descriptors and their corresponding code names. See the VSI OpenVMS Calling Standard for a detailed description of each descriptor class.
Passing Mechanism |
Descriptor Symbolic Code |
---|---|
By descriptor, fixed-length (scalar) |
DSC$K_CLASS_S |
By descriptor, dynamic string |
DSC$K_CLASS_D |
By descriptor, array |
DSC$K_CLASS_A |
By descriptor, procedure |
DSC$K_CLASS_P |
By descriptor, decimal string |
DSC$K_CLASS_SD |
By descriptor, noncontiguous array |
DSC$K_CLASS_NCA |
By descriptor, varying string |
DSC$K_CLASS_VS |
By descriptor, varying string array |
DSC$K_CLASS_VSA |
By descriptor, unaligned bit string |
DSC$K_CLASS_UBS |
By descriptor, unaligned bit array |
DSC$K_CLASS_UBA |
By descriptor, string with bounds |
DSC$K_CLASS_SB |
By descriptor, unaligned bit string with bounds |
DSC$K_CLASS_UBSB |
1.4.5. Explanatory Text
A sentence or a sentence fragment that describes (1) the nature of the data specified by the argument, and (2) the way in which the routine uses this data. For example, if an argument were supplying a number, which the routine converts to another data type, the argument description would contain the following sentence fragment:
Integer to be converted to an F_floating point number
- A sentence that expresses the relationship between the argument and the data that it specifies. This relationship is the passing mechanism used to pass the data and, for a given argument, is expressed in one of the following ways:
If the passing mechanism is by value, the sentence should read as follows:
The
attrib
argument is a longword that contains (or is) the bit mask specifying the attributes.If the passing mechanism is by reference, the sentence should read as follows:
The
objtyp
argument is the address of a longword containing a value indicating whether the object is a file or a device.If the passing mechanism is by descriptor, the sentence should read as follows:
The
devnam
argument is the address of a string descriptor of a logical name denoting a device name.
Additional explanatory paragraphs that appear for each argument, as needed. For example, some arguments specify complex data consisting of many discrete fields, each of which has a particular purpose and use. In such cases, additional paragraphs provide detailed descriptions of each such field, symbolic names for the fields, if any, and guidance on their use.
1.5. Condition Values Returned Heading
Indicates the success or failure of a called procedure
Describes an exception condition when an exception is signaled
Identifies system messages
Reports program success or failure to the command level
The VSI OpenVMS Calling Standard explains in detail the uses for the condition value and depicts its format and contents.
The Condition Values Returned heading describes the condition values that are returned by the routine when it completes execution without generating an exception condition. These condition values describe the completion status of the operation.
If a called routine generates an exception condition during execution, the exception condition is signaled; the exception condition is then handled by a condition handler (either user supplied or system supplied). Depending on the nature of the exception condition and on the condition handler, the called routine either continues normal execution or terminates abnormally.
Condition Values Returned
Condition Values Returned in an I/O Status Block
Condition Values Returned in a Mailbox
Condition Values Signaled
The method used to return the condition value is indicated under the Condition Values Returned heading in the documentation of each routine. These methods are discussed individually in the following subsections.
Under these headings, a two-column list shows the symbolic code for each condition value the routine can return and an accompanying description. The description explains whether the condition value indicates success or failure and, if failure, what user action might have caused the failure and what to do to correct it. Condition values that indicate success are listed first.
Symbolic codes for condition values are defined by the system. Though the condition value consists of several fields, each of which can be interpreted individually for specific information, the entire condition value itself can be interpreted as an integer, and this integer has an equivalent symbolic code.
The three sections that follow discuss the ways in which the called routine returns condition values.
1.5.1. Condition Values Returned
The possible condition values that the called routine can return in general register R0 (R8, R9 for I64) are listed under the Condition Values Returned heading in the documentation. Most routines return a condition value in this way.
In the documentation of system services that complete asynchronously, both the Condition Values Returned and Condition Values Returned in the I/O Status Block headings are used. Under the Condition Values Returned heading, the condition values returned by the asynchronous service refer to the success or failure of the system service request—that is, to the status associated with the correctness of the syntax of the call, in contrast to the final status associated with the completion of the service operation. For asynchronous system services, condition values describing the success or failure of the actual service operation—that is, the final completion status—are listed under the Condition Values Returned in the I/O Status Block heading.
1.5.2. Condition Values Returned in an I/O Status Block
The possible condition values that the called routine can return in an I/O status block are listed under the Condition Values Returned in the I/O Status Block heading.
The routines that return condition values in the I/O status block are the system services that are completed asynchronously. Each of these asynchronous system services returns to the caller as soon as the service call is queued. This allows the continued use of the calling program during the execution of the service operations. System services that are completed asynchronously all have arguments that specify an I/O status block. When the system service operation is completed, a condition value specifying the completion status of the operation is written in the first word of this I/O status block.
Representing a condition value in a word-length field is possible for system services because the high-order segment of all system service condition values is 0. See cond_value in Table B.1, “OpenVMS Usage Data Type Entries” or Section 2.8, “Condition Value Return” for the field detail of the condition value structure.
1.5.3. Condition Values Returned in a Mailbox
The possible condition values that the called routine can return in a mailbox are listed under the Condition Values Returned in a Mailbox heading.
Routines such as SYS$SNDOPR that return condition values in a mailbox send information to another process to perform a task. The receiving process performs the action and returns the status of the task to the mailbox of the sending process.
1.5.4. Condition Values Signaled
The possible condition values that the called routine can signal (instead of returning them in R0 (R8, R9 for I64) are listed under the Condition Values Signaled heading.
Routines that signal condition values as a way of indicating the completion status do so because these routines are returning actual data as the value of the routine.
As mentioned, the signaling of condition values occurs whenever a routine generates an exception condition, regardless of how the routine returns its completion status under normal circumstances.
Chapter 2. Basic Calling Standard Conventions
Register usage
Stack usage
Argument list
Argument passing
Returns
Refer to the VSI OpenVMS Calling Standard for more detail on calling conventions and for standards defining argument data types, descriptor formats, and procedures for condition handling and stack unwinding.
2.1. Hardware Registers
Registers in the hardware provide the necessary temporary storage for computation within OpenVMS software procedures. The number of registers available and their usage vary between the OpenVMS VAX, OpenVMS Alpha, OpenVMS I64, and OpenVMS x86-64 systems.
2.1.1. Register Usage for OpenVMS VAX
Register |
Use |
---|---|
PC |
Program counter |
SP |
Stack pointer |
FP |
Current stack frame pointer |
AP |
Argument pointer |
R1 |
Environment value (when necessary) |
R0, R1 |
Function return value registers |
By definition, any called routine can use registers R2 through R11 for computation and the AP register as a temporary register.
2.1.2. Register Usage for OpenVMS Alpha
Integer
Floating-point
The first 32 general-purpose registers support integer processing; the second 32 support floating-point operations.
2.1.2.1. Integer Registers
Register |
Usage |
---|---|
R0 |
Function value register. A standard call that returns a nonfloating-point function must return the function result in this register. The register can be modified by the called procedure without being saved and restored. |
R1 |
Conventional scratch register. In a standard call, this register can be modified by the called procedure without being saved and restored. |
R2–R15 |
Conventional saved registers. If a standard-conforming procedure modifies one of these registers, the procedure must save and restore it. |
R16–R21 |
Argument registers. Up to six nonfloating-point items of the argument list are passed in these registers and the registers can be modified by the called procedure without being saved and restored. |
R22–R24 |
Conventional scratch registers. The registers can be modified by the called procedure without being saved and restored. |
R25 |
Argument information (AI) register. The register describes the argument list (see Section 2.4.2, “Argument Lists on OpenVMS Alpha” for a detailed description) and can be modified by the called procedure without being saved and restored. |
R26 |
Return address (RA) register. The return address must be passed in this register and can be modified by the called procedure without being saved and restored. |
R27 |
Procedure value (PV) register. The procedure value of the procedure being called is passed in this register and can be modified by the called procedure without being saved and restored. |
R28 |
Volatile scratch register. The contents of this register are always unpredictable after any external transfer of control either to or from a procedure. |
R29 |
Frame pointer (FP). This register defines which procedure is the current procedure. |
R30 |
Stack pointer (SP). This register contains a pointer to the top (start) of the current operating stack. |
R31 |
ReadAsZero/Sink (RZ). Hardware defined: binary zero as a source operand, sink (no effect) as a result operand. |
2.1.2.2. Floating-Point Registers
Register |
Usage |
---|---|
F0 |
Floating-point function value register. In a standard call that returns a floating-point result in a register, this register is used to return the real part of the result. The register can be modified by the called procedure without being saved and restored. |
F1 |
Floating-point function value register. In a standard call that returns a complex floating-point result in registers, this register is used to return the imaginary part of the result. This register can be modified by the called procedure without being saved and restored. |
F2–F9 |
Conventional saved registers. If a standard-conforming procedure modifies one of these registers, the procedure must save and restore it. |
F10–F15 |
Conventional scratch registers. The registers can be modified by the called procedure without being saved and restored. |
F16–F21 |
Argument registers. Up to six floating-point arguments can be passed by value in these registers. These registers can be modified by the called procedure without being saved and restored. |
F22–F30 |
Conventional scratch registers. The registers can be modified by the called procedure without being saved and restored. |
F31 |
ReadAsZero/Sink. Hardware defined: binary zero as a source operand, sink (no effect) as a result operand. |
2.1.3. Register Usage for OpenVMS I64
The Intel® Itanium® architecture defines 128 general registers, 128 floating-point registers, 64 predicate registers, 8 branch registers, and up to 128 application registers. The large number of architectural registers enable multiple computations to be performed without having to frequently spill and fill intermediate data to memory.
The instruction pointer is a 64-bit register that points to the currently executing instruction bundle.
This section describes the register conventions for OpenVMS I64.
General
Floating-point
Predicate
Branch
Application
2.1.3.1. I64 Register Classes
Scratch registers—may be modified by a procedure call; the caller must save these registers before a call if needed (caller save).
Preserved registers—must not be modified by a procedure call; the callee must save and restore these registers if used (callee save). A procedure using one of the preserved general registers must save and restore the caller's original contents, including the NaT bits associated with the registers, without generating a NaT consumption fault.
One way to preserve a register is not to use it at all.
Automatic registers—saved and restored automatically by the hardware call/return mechanism.
Constant or Read-only registers—contain a fixed value that cannot be changed by the program.
Special registers—used in the calling standard call/return mechanism.
Global registers—shared across a set of cooperating routines as global static storage that happens to be allocated in a register. (Details regarding the dynamic lifetime of such storage are not addressed here).
Special registers—used in the calling standard call/return mechanism. (These are the same as the set of special registers in the preceding list of registers used within a procedure).
Input registers—may be used to pass information into a procedure (in addition to the normal stacked input registers).
Output registers—may be used to pass information back from a called procedure to its caller (in addition to the normal return value registers).
Volatile registers—may not be used to pass information between procedures, either as input or output.
2.1.3.2. I64 General Register Usage
There are 128, 64-bit general registers (R0—R127) that are used to hold values for integer and multimedia computations. Each of the 128 registers has one additional NaT (Not a Thing) bit that is used to indicate whether the value stored in the register is valid. Execution of I64 speculative instructions can result in a register's NaT bit being set. Register R0 is read only and contains a value of zero (0). Attempting to write to R0 will cause a fault.
Register |
Class |
Usage |
---|---|---|
R0 |
Constant |
Always 0. |
R1 |
Special |
Global data pointer (GP). Designated to hold the
address of the currently addressable global data
segment. Its use is subject to the following conventions:
The effect of these rules is that GP must be treated as a scratch register at a point of call (that is, it must be saved by the caller), and it must be preserved from entry to exit. |
R2 |
Volatile |
May not be used to pass information between procedures, either as inputs or outputs. |
R3 |
Scratch |
May be used within and between procedures in any mutually consistent combination of ways under explicit user control. |
R4—R7 |
Preserved |
General-purpose preserved registers. Used for any value that needs to be preserved across a procedure call. May be used within and between procedures in any mutually consistent combination of ways under explicit user control. |
R8—R9 |
Scratch |
Return value. Can also be used as input (whether or not the procedure has a return value), but not in any additional ways. |
R10—R11 |
Scratch |
May be used within and between procedures in any mutually consistent combination of ways under explicit user control. |
R12 |
Special |
Memory stack pointer (SP). Holds the lowest address of the current stack frame. At a call, the stack pointer must point to a 0 mod 16 aligned area. The stack pointer is also used to access any memory arguments upon entry to a function. Except in the case of dynamic stack allocation, code can use the stack pointer to reference stack items without having to set up a frame pointer for this purpose. |
R13 |
Special |
Reserved as a thread pointer (TP). |
R14—R18 |
Volatile |
May not be used to pass information between procedures, either as inputs or outputs. |
R19—R24 |
Scratch |
May be used within and between procedures in any mutually consistent combination of ways under explicit user control. |
R25 |
Special |
Argument information (see Section 2.4.3.3, “Argument Information (AI) Register”). |
R26—R31 |
Scratch |
May be used within and between procedures in any mutually consistent combination of ways under explicit user control. |
IN0—IN7 |
Automatic |
Stacked input registers. Code may allocate a register stack frame of up to 96 registers with the ALLOC instruction, and partition this frame into three regions: input registers(IN0, IN1, ...), local registers (LOC0, LOC1, ...), and output registers (OUT0, OUT1, ...). R32–R39 (IN0–IN7) are used as incoming argument registers. Arguments beyond these registers appear in memory. |
LOC0—LOC95 |
Automatic |
Stacked local registers. Code may allocate a register stack frame of up to 96 registers with the ALLOC instruction, and partition this frame into three regions: input registers (IN0, IN1, ...), local registers (LOC0, LOC1, ...), and output registers (OUT0, OUT1, ...). LOC0-LOC95 are used for local storage. |
OUT0—OUT7 |
Scratch |
Stacked output registers. Code may allocate a register stack frame of up to eight registers with the ALLOC instruction, and partition this frame into three regions: input registers (IN0, IN1, ...), local registers (LOC0, LOC1, ...), and output registers (OUT0, OUT1, ...). OUT0-OUT7 are used to pass the first eight arguments in calls. |
2.1.3.3. I64 Floating-Point Register Usage
There are 128, 82-bit floating-point registers (F0—F127) that are used for floating-point computations. The first two registers, F0 and F1, are read only and read as +0.0 and +1.0, respectively. Instructions that write to F0 or F1 will fault.
Register |
Class |
Usage |
---|---|---|
F0 |
Constant |
Always 0.0. |
F1 |
Constant |
Always 1.0. |
F2—F5 |
Preserved |
Can be used for any value that needs to be preserved across a procedure call. A procedure using one of the preserved floating-point registers must save and restore the caller's original contents without generating a NaT consumption fault. |
F6—F7 |
Scratch |
May be used within and between procedures in any mutually consistent combination of ways under explicit user control. |
F8—F9 |
Scratch |
Argument/Return values. See Section 2.4.3, “Argument Lists on OpenVMS I64” and Section 2.7.3, “Return Values on OpenVMS I64” for the OpenVMS specifications for use of these registers. |
F10—F15 |
Scratch |
Argument values. See Section 2.4.3, “Argument Lists on OpenVMS I64” for the OpenVMS specifications for use of these registers. |
F16—F31 |
Preserved |
Can be used for any value that needs to be preserved across a procedure call. A procedure using one of the preserved floating-point registers must save and restore the caller's original contents without generating a NaT consumption fault. |
F32—F127 |
Scratch |
Rotating registers or scratch registers. |
Note
VAX floating-point data are never loaded or manipulated in the I64 floating-point registers. However, VAX floating-point values may be converted to IEEE floating-point values, which are then manipulated in the I64 floating-point registers.
2.1.3.4. I64 Predicate Register Usage
Predicate registers are single-bit-wide registers used for controlling the execution of predicated instructions. There are 64 one-bit predicate registers (P0—P63) that control conditional execution of instructions and conditional branches. The first register, P0, is read only and always reads true (1). The results of instructions that write to P0 are discarded.
Register |
Class |
Usage |
---|---|---|
P0 |
Constant |
Always 1. |
P1—P5 |
Preserved |
Can be used for any predicate value that needs to be preserved across a procedure call. A procedure using one of the preserved predicate registers must save and restore the caller's original contents. |
P6—P13 |
Scratch |
Can be used within a procedure as a scratch register. |
P14—P15 |
Volatile |
Cannot be used to pass information between procedures, either as input or output. |
P16—P63 |
Preserved |
Rotating registers. |
2.1.3.5. I64 Branch Register Usage
Branch registers are used for making indirect branches. There are 8 64-bit branch registers (B0—B7) that are used to specify the target addresses of indirect branches.
Register |
Class |
Usage |
---|---|---|
B0 |
Scratch |
Contains the return address on entry to a procedure; otherwise a scratch register. |
B1—B5 |
Preserved |
Can be used for branch target addresses that need to be preserved across a procedure call. |
B6—B7 |
Volatile |
May not be used to pass information between procedures, either as input or output. |
2.1.3.6. I64 Application Register Usage
Register |
Class |
Usage |
---|---|---|
AR.FPSR |
See Usage |
Floating-point status register. This register is
divided into the following fields:
|
AR.RNAT |
Automatic |
RSE NaT collection register. Holds the NaT bits for values stored by the register stack engine. These bits are saved automatically in the register stack backing store. |
AR.UNAT |
Preserved |
User NaT collection register. Holds the NaT bits for values stored by the ST8.SPILL instruction. As a preserved register, it must be saved before a procedure can issue any ST8.SPILL instructions. The saved copy of AR.UNAT in a procedure's frame holds the NaT bits from the registers spilled by its caller; these NaT bits are thus associated with values local to the caller's caller. |
AR.PFS | Special |
Previous function state. Contains information that records the state of the caller's register stack frame and epilogue counter. It is overwritten on a procedure call; therefore, it must be saved before issuing any procedure calls, and restored prior to returning. |
AR.BSP |
Read-only |
Backing store pointer. Contains the address in the backing store corresponding to the base of the current frame. This register may be modified only as a side effect of writing AR.BSPSTORE while the Register Stack Engine (RSE) is in enforced lazy mode. |
AR.BSPSTORE | Special |
Backing store pointer. Contains the address of the next RSE store operation. It may be read or written only while the RSE is in enforced lazy mode. Under normal operation, this register is managed by the RSE, and application code should not write to it, except when performing a stack switching operation. |
AR.RSC |
See Usage |
RSE control; the register stack configuration
register. This register is divided into the following fields:
|
AR.LC |
Preserved |
Loop counter. |
AR.EC |
Automatic |
Epilogue counter (preserved in AR.PFS). |
AR.CCV | Scratch |
Compare and exchange comparison value. |
AR.ITC |
Read-only |
Interval time counter. |
AR.K0—AR.K7 |
Read-only |
Kernel registers. |
AR.CSD | Scratch |
Reserved for use as implicit operand registers in future extensions to the Itanium architecture. To ensure forward compatibility, OpenVMS considers these registers as part of the thread and process state. |
AR.SSD |
Scratch |
Reserved for use as implicit operand registers in future extensions to the Itanium architecture. To ensure forward compatibility, OpenVMS considers these registers as part of the thread and process state. |
2.1.4. Register Usage for OpenVMS x86-64
General-purpose
Floating-point and related control/status
Segment
Legacy pseudo-registers
2.1.4.1. x86-64 Register Classes
Scratch registers—may be modified by a procedure call; the caller must save these registers before a call if needed (caller save).
Preserved registers—must not be modified by a procedure call; the callee must save and restore these registers if used (callee save). A procedure using one of the preserved general-purpose registers must save and restore the original content of the caller.
One way to preserve a register is not to use it at all.
Special registers—used in the calling standard call/return mechanism.
Volatile registers—may be used as scratch registers within a procedure and are not preserved across a call; may not be used to pass information between procedures either as input or output.
2.1.4.2. x86-64 General-Purpose Register Usage
Register | Class | Usage |
---|---|---|
%rax %eax %ax %al %ah | Scratch |
|
%rbx %ebx %bx %bl %bh | Preserved | Callee-saved registers. |
%rcx %ecx %cx %cl %ch | Scratch | Pass the 4th argument to procedures. |
%rdx %edx %dx %dl %dh | Scratch |
|
%rsi %esi %si %sil | Scratch | Pass the 2nd argument to procedure. |
%rdi %edi %di %dil | Scratch | Pass the 1st argument to procedures. |
%rbp %ebp %bp %bpl | Preserved | Used as a frame pointer, if manifested in a register. |
%rsp %esp %sp %spl | Special | Stack pointer. |
%r8 %r8d %r8w %r8l | Scratch | Pass the 5th argument to procedures. |
%r9 %r9d %r9w %r9l | Scratch | Pass the 6th argument to procedures. |
%r10 %r10d %r10w %r10l | Scratch | Pass the environment value when calling a bound procedure. |
%r11 %r11d %r11w %r11l | Volatile | Available for use in call stubs, trampolines, and other constructs. |
| Preserved | Callee-saved registers. |
RFLAGS | Preserved | The Direction Flag (DF) bit must be zero at procedure call and return. |
Scratch | All other bits. | |
%rip | Special | Instruction pointer, not directly addressable by software. |
2.1.4.3. x86-64 Floating-Point Register Usage (SSE)
The base x86-64 architecture provides 16 SSE floating-point registers, each 128 bits wide.
Intel AVX (Advanced Vector Extensions) option provides 16 256-bit wide AVX
registers (%ymm0
—%ymm15
). The lower 128
bits of %ymm0
—%ymm15
are aliased to the
respective 128-bit SSE registers
(%xmm0
—%xmm15
?).
Intel AVX-512 option provides 32 512-bit wide SIMD registers
(%zmm0
—%zmm31
). The lower 128 bits of
%zmm0
—%zmm31
are aliased to the
respective 128-bit SSE registers
(%xmm0
—%xmm-31
). The lower 256 bits of
%zmm0
—%zmm31
are aliased to the
respective 256-bit AVX registers
(%ymm0
—%ymm31
?).
In addition, Intel AVX-512 also provides 8 vector mask registers
(%k0
—%k7
), each 64 bits wide.
For the purposes of parameter passing and function return,
%xmmN
, %ymmN
, and
%zmmN
refer to the same register. Only one of them can be
used at a time.
Vector register is used to refer to either an SSE, AVX, or AVX-512 register (but not a vector mask register). This document often uses the name SSE to refer collectively to the SSE registers together with either the AVX or AVX-512 options.
Register | Class | Usage |
---|---|---|
%xmm0 %ymm0 %zmm0 | Scratch |
|
%xmm1 %ymm1 %zmm1 | Scratch |
|
%xmm2 %ymm2 %zmm2 | Scratch | Pass the 3rd argument to procedures. |
%xmm3 %ymm3 %zmm3 | Scratch | Pass the 4th argument to procedures. |
%xmm4 %ymm4 %zmm4 | Scratch | Pass the 5th argument to procedures. |
%xmm5 %ymm5 %zmm5 | Scratch | Pass the 6th argument to procedures. |
%xmm6 %ymm6 %zmm6 | Scratch | Pass the 7th argument to procedures. |
%xmm7 %ymm7 %zmm7 | Scratch | Pass the 8th argument to procedures. |
| Scratch | Temporary registers. |
MXCSR |
Preserved | The control flags (bits 6-15) are preserved. |
Scratch | The other bits are scratch. |
Register | Class | Usage |
---|---|---|
%k0—%k7 | Scratch | Temporary registers |
2.1.4.4. x86-64 Floating-Point Register Usage (FPU)
OpenVMS x86-64 applications may use the x87 registers though there is little reason to do so. Packed, single- and double-precision floating-point operations are usually performed in the SSE registers, while the 80-bit extended-precision floating-point format is not supported by the OpenVMS compilers or run-times.
Register | Class | Usage |
---|---|---|
%st0 | Scratch | 1st return value register. |
%st1 | Scratch | 2nd return value register. |
%st2—%st7 | Scratch | Temporary registers. |
%mm0—%mm7 | Scratch | The MMX registers. Overlay the x87 floating-point
(%st0—%st7 )
registers. |
Control Word | Preserved | Stores the value of the control word. |
Status Word | Scratch | Stores the value of the status word. |
| — | Not used by applications. |
The CPU should be in x87 mode, not MMX mode, on procedure entry and exit.
2.1.4.5. x86-64 Segment Register Usage
Register | Class | Usage |
---|---|---|
%cs %ds %ss %es | — | Managed by OpenVMS and implicitly used by applications |
%fs | — | Reserved to OpenVMS |
%gs | — | Reserved to OpenVMS |
2.1.4.6. x86-64 Bound Register Usage
Use of the x86-64 bound registers is deprecated on OpenVMS. The only support provided is to context switch the contents of the bound registers as part of the normal application context; they are otherwise unused and unsupported.
2.1.4.7. Legacy Pseudo-Registers
The OpenVMS MACRO compiler for x86-64 (XMACRO) generates code that uses a set of pseudo-registers to emulate the Alpha register set. The pseudo-register set consists of 32 64-bit registers (R0—R31). The contents of these pseudo-registers are well defined only at procedure calls and returns; otherwise, XMACRO uses pseudo-registers at its discretion. No special semantics are associated with the pseudo-registers, even for the registers that would otherwise be considered special or part of the Alpha hardware.
The pseudo-registers are invisible to high-level languages, except for BLISS and VSI C. BLISS linkage attributes and VSI C linkage pragmas may be used to access pseudo-registers on calls and returns. See Section 2.1.2, “Register Usage for OpenVMS Alpha”, for more information regarding Alpha register conventions and usage.
Use of such registers for other than legacy applications from other OpenVMS environments is deprecated.
The pseudo-registers are stored as a per-thread vector of quadwords in memory.
alpha_reg_vector_t* LIB$GET_ALPHA_REG_VECTOR ();Arguments:
None. |
ptr | Pointer to the Alpha pseudo-register vector for the current thread. |
LIB$GET_ALPHA_REG_VECTOR preserves
all registers other than the return value register
%rax
.
Any procedure that accesses the pseudo-registers must make its own call to LIB$GET_ALPHA_REG_VECTOR to obtain the array address. Passing the array address to another procedure by any means is an error that may result in undefined behavior.
2.2. Stack Usage for Procedures
A stack is a last-in/first-out (LIFO) temporary storage area that the system allocates for every user process. The system keeps information about each routine call in the current image on the call stack. Then, each time you call a routine, the system creates a structure on the stack, defined as the stack frame.
Stack frames and call frames are synonymous. A call frame for each procedure has a specified format containing pointers and control information necessary in the transfer of control between procedures of a call chain. Stack frames (call frames) of standard calling procedures differ across OpenVMS VAX, Alpha, I64, and x86-64 systems.
2.2.1. Stack Procedure Usage for OpenVMS VAX
A pointer to the call frame of the previous procedure call, defined as the frame pointer (FP).
Note that FP points at the condition handler longword at the beginning of the previous call frame. Unless the procedure has a condition handler, this longword contains all zeros. See the VSI OpenVMS Calling Standard for more information on condition handlers.
The argument pointer (AP) of the previous routine call.
The stored address (program count) of the point at which the routine was called. Specifically, this address is the program count from the program counter (PC) of the instruction following the call to the current routine.
The contents of other general registers. Based on a register save mask specified in the control information of the second longword, the system restores the saved contents of the identified registers to the calling routine when control returns to it.

The contents of the stack located at addresses following the call frame belong to the calling program; they should not be read or written by the called procedure, except as specified in the argument list. The contents of the stack located at addresses lower than the call frame (at FP) belong to interrupt and exception routines; they are modified continually and unpredictably.
The called procedure allocates local storage by subtracting the required number of bytes from the stack provided on entry. This local storage is freed automatically by the RET instruction.
2.2.1.1. Calling Sequence
CALLG arglst, procedure CALLS argcnt, procedure
argcnt
onto the stack
as along word and sets the argument pointer, AP, to the top of the stack. The
complete sequence using CALLS
follows:push argn . . . push arg1 CALLS #n, procedure
2.2.1.2. Call Frames on Return
If the called procedure returns control to the calling procedure, control must return to the instruction immediately following the CALLG or CALLS instruction. Skip returns and GOTO returns are allowed only during stack unwind operations.
The called procedure returns control to the calling procedure by executing the return instruction (RET).
Note that when a routine completes execution, the system uses the FP in the call frame of the current procedure to locate the frame of the previous procedure. The system then removes the stack frame of the current procedure from the stack.
2.2.2. Stack Procedure Usage for OpenVMS Alpha
Fixed-size
Variable-size
2.2.2.1. Fixed-Size Stack Frame
Figure 2.2, “Fixed-Size Stack Frame Format” illustrates the format of the stack frame for a procedure with a fixed amount of stack. The SP register is the stack base pointer for a fixed-size stack. In this case, R29 (FP) typically contains the address of the procedure descriptor for the current procedure.
The optional parts of the stack frame are created only as required by the particular procedure. As shown in Figure 2.2, “Fixed-Size Stack Frame Format”, the field names within brackets are optional fields. The fixed temporary locations are optional sections of any stack frame that contain language-specific locations required by the procedure context of some high-level languages.
The register save area is a set of consecutive quadwords in which registers that are saved and restored by the current procedure are stored. The register save area (RSA) begins at the location pointed to by the RSA offset. The contents of the return address register (R26) are always saved in the first register field (SAVED_RETURN) of the register save area.
Use of the arguments passed in memory appending the end of the frame is described in Section 2.4.2, “Argument Lists on OpenVMS Alpha”. For more detail concerning the fixed-size stack frame, see the VSI OpenVMS Calling Standard.

2.2.2.2. Variable-Size Stack Frame
Figure 2.3, “Variable-Size Stack Frame Format” illustrates the format of the stack frame for procedures with a varying amount of stack when PDSC$V_BASE_REG_IS_FP is 1. In this case, R29 (FP) contains the address that points to the base of the stack frame on the stack. This frame-base quadword location contains the address of the current procedure's descriptor.
The optional parts of the stack frame are created as required by the particular procedure. As shown in Figure 2.3, “Variable-Size Stack Frame Format”, field names within brackets are optional fields. The fixed temporary locations are optional sections of any stack frame that contain language-specific locations required by the procedure context of some high-level languages.
A compiler can use the stack temporary area pointed to by the SP base register for fixed local variables, such as constant-sized data items and program state, as well as for dynamically sized local variables. The stack temporary area may also be used for dynamically sized items with a limited lifetime, for example, a dynamically sized function result or string concatenation that cannot be directly stored in a target variable. When a procedure uses this area, the compiler must keep track of its base and reset SP to the base to reclaim storage used by temporaries.
The register save area is a set of consecutive quadwords in which registers saved and restored by the current procedure are stored. The register save area (RSA) begins at the location pointed to by the offset PDSC$W_RSA_OFFSET. The contents of the return address register (R26) is always saved in the first register field (SAVED_RETURN) of the register save area.
Use of the arguments passed in memory appending the end of the frame is described in Section 2.4.2, “Argument Lists on OpenVMS Alpha”. For more detail concerning the variable-size stack frame, see the VSI OpenVMS Calling Standard.

2.2.3. Stack Procedure Usage for OpenVMS I64
The I64 general registers are organized as a logically infinite set of stack frames that are allocated from a finite pool of physical registers.
Registers R0 through R31 are called global or static registers and are not part of the stacked registers. The stacked registers are numbered R32 up to a user-configurable maximum of R127. A called procedure specifies the size of its new stack frame using the alloc instruction. The procedure can use this instruction to allocate up to 96 registers per frame shared among input, output, and local values. When a call is made, the output registers of the calling procedure are overlapped with the input registers of the called procedure, thereby allowing parameters to be passed with no register copying or spilling. The hardware renames physical registers so that the stacked registers are always referenced in a procedure starting at R32.
Management of the register stack is handled by a hardware mechanism called the Register Stack Engine (RSE). The RSE moves the contents of physical registers between the general register file and memory without explicit program intervention. This provides a programming model that looks like an unlimited physical register stack to compilers; however, saving and restoring of registers by the RSE may be costly, so compilers should still attempt to minimize register usage.
2.2.3.1. Procedure Types
Memory stack procedure—allocates a memory stack and may maintain part or all of its caller's context on that stack.
Register stack procedure—allocates only a register stack and maintains its caller's context in registers.
- Null frame procedure—allocates neither a memory stack nor a register stack and therefore preserves no context of its caller.
Note
Unlike an Alpha null frame procedure (see the VSI OpenVMS Calling Standard), an I64 null frame procedure does not execute in the context of its caller because the I64 call instruction (br.call) changes the register set so that only the caller's output registers are accessible in the called routine. The caller's input and local registers cannot be accessed at all. The call instruction also changes the previous frame state (PFS) of the I64 processor.
A compiler may choose which type of procedure to generate based on the requirements of the procedure in question. A calling procedure does not need to know what type of procedure it is calling.
Every memory stack procedure or register stack procedure must have an associated unwind description (see the VSI OpenVMS Calling Standard) that describes what type of procedure it is and other procedure characteristics. A null frame procedure may also have an associated unwind description. (If not, a default description applies). This data structure is used to interpret the call stack at any given point in a thread's execution. It is typically built at compile time and usually is not accessed at run time except to support exception processing or other rarely executed code.
Read access to unwind descriptions is provided through the procedural interfaces described in the VSI OpenVMS Calling Standard.
To make invocations of that procedure visible to and interpretable by facilities such as the debugger, exception-handling system, and the unwinder.
To ensure that the context of the caller saved by the called procedure can be restored if an unwind occurs. (For a description of unwinding, see the VSI OpenVMS Calling Standard).
2.2.3.2. Memory Stack
The memory stack is used for local dynamic storage, spilled registers, and parameter passing. It is organized as a stack of procedure frames, beginning with the main program's frame at the base of the stack, and continuing towards the top of the stack with nested procedure calls. At the top of the stack is the frame for the currently active procedure. (There may be some system-dependent frames at the base of the stack, prior to the main program's frame, but an application program may not make any assumptions about them).
The memory stack begins at an address determined by the operating system, and grows towards lower addresses in memory. The stack pointer register (SP) always points to the lowest address in the current, topmost frame on the stack.
Each procedure creates its frame on entry by subtracting its frame size from the stack pointer, and removes its frame from the stack on exit by restoring the previous value of SP (usually by adding its frame size, but a procedure may save the original value of SP when its frame size varies).
Because the register stack is also used for the same purposes as the memory stack, not all procedures need a memory stack frame. However, every nonleaf procedure must save at least its return link and the previous frame marker, either on the register stack or on the memory stack. This ensures that there is an invocation context for every nonleaf procedure on one or both of the stacks.
2.2.3.3. Procedure Frames
A memory stack procedure frame consists of five regions, as illustrated in Figure 2.4, “Procedure Frame”.

Scratch area. This 16-byte region is provided as scratch storage for procedures that are called by the current procedure. Leaf procedures need not allocate this region. A procedure may use the 16 bytes pointed to by the stack pointer (SP) as scratch memory, but the contents of this area are not preserved by a procedure call.
Outgoing parameters. Parameters in excess of those passed in registers are stored in this region of the stack frame. A procedure accesses its incoming parameters in the outgoing parameter region of its caller's stack frame.
Frame marker (optional). This region may contain information required for unwinding through the stack (for example, a copy of the previous stack pointer).
Dynamic allocation. This variable-sized region (initially zero length) can be created as needed.
Local storage. A procedure can store local variables, temporaries, and spilled registers in this region. For conventions affecting the layout of this area for spilled registers, see the VSI OpenVMS Calling Standard.
Note
A stack pointer that is not octaword aligned is valid only in a variable-sized frame because the unwind descriptor (MEM_STACK_F, see the VSI OpenVMS Calling Standard) for a fixed-size frame specifies the size in 16-byte units.
An application may not write to memory addresses lower than the stack pointer, because this memory area may be written to asynchronously (for example, as a result of exception processing).
Most procedures are expected to have a fixed-size frame, and the conventions are biased in favor of this. A procedure with a fixed-size frame may reference all regions of the frame with a compile-time constant offset relative to the stack pointer. Compilers should determine the total size required for each region, and pad the local storage area to make the total frame size a multiple of 16 bytes. The procedure can then create the frame by subtracting an immediate constant from the stack pointer in the prologue, and remove the frame by adding the same immediate constant to the stack pointer in the epilogue.
If a procedure has a variable-size frame (for example, a C routine that calls the alloca builtin), it should make a copy of SP to serve as a frame pointer before subtracting the initial frame size from the stack pointer. The procedure can then restore the previous value of the stack pointer in the epilogue without regard for how much dynamic storage has been allocated within the frame. It can also use the frame pointer to access the local storage region, because offsets from SP will vary.
The procedure uses an equivalent method of addressing the local storage region correctly before and after dynamic allocation.
The code satisfies the conditions imposed by the stack unwind mechanism.
To expand a stack frame dynamically, the scratch area, outgoing parameters, and frame marker regions (which are always located relative to the current stack pointer), must be relocated to the new top of stack. If the scratch area and outgoing parameter area are both clear of any live values, there is no actual work involved in relocating these areas. For procedures with dynamically sized frames, it is recommended that the previous stack pointer value be stored in a local stacked general register instead of the frame marker, so that the frame marker is also empty. If the previous stack pointer is stored in the frame marker, the code must take care to ensure that the stack is always unwindable while the stack is being expanded (see the VSI OpenVMS Calling Standard).
Other issues depend on the compiler and the code being compiled. The standard calling sequence does not define a maximum stack frame size, nor does it restrict how a language system uses any stack frame region beyond those purposes described here. For example, the outgoing parameter region can be used as scratch storage whenever it is not needed for passing parameters.
2.2.3.4. Register Stack
General registers R32 through R127 form a register stack that is automatically managed across procedure calls and returns. Each procedure frame on the register stack is divided into two dynamically sized regions: one for input parameters and local variables, and one for output parameters.
On a procedure call, the registers are automatically renamed by the hardware so that the caller's output registers form the base of the register stack frame of the callee. On return, the registers are restored to the previous state, so that the input and local registers are preserved across the call.
The ALLOC instruction is used at the beginning of a procedure to allocate the input, local, and output regions; the sizes of these regions are supplied as immediate operands. A procedure is not required to issue an ALLOC instruction if it does not need to store any values in its register stack frame. It may write to the first N stacked registers, where N is the value of the argument count passed in the argument information (AI) register (see Section 2.4.3.3, “Argument Information (AI) Register”). It may not write to any other stack register without first issuing an ALLOC instruction.
ALLOC R36=rspfs, 4, 6, 5, 0
The actual registers to which the stacking registers are physically mapped are not directly addressable by the application software.
2.2.3.4.1. Input and Local Registers
The hardware makes no distinction between input and local registers. The caller's output registers automatically become the callee's register stack frame on a procedure call, with all registers initially allocated as output registers. An ALLOC instruction may increase or decrease the total size of the register stack frame, and may adjust the boundary between the input and local region and the output region.
The software conventions specify that up to eight general registers are used for parameter passing. Any registers in the input and local region beyond those eight may be allocated for use as preserved locals. Floating-point parameters may produce holes in the parameter list that is passed in the general registers; those unused input registers may also be used for preserved locals.
The caller's output registers do not need to be preserved for the caller. Once an input parameter is no longer needed, or has been copied elsewhere, that register may be reused for any other purpose within the procedure.

2.2.3.4.2. Output Registers
Up to eight output registers are used for passing parameters. If a procedure call requires fewer than eight general registers for its parameters, the calling procedure does not need to allocate more than are needed. If the called procedure expects more parameters, it will allocate extra input registers; these registers will be uninitialized.
A procedure may also allocate more than eight registers in the output region. While the extra registers may not be used for passing parameters, they can be used as extra scratch registers. On a procedure call, they will show up in the called procedure's output area as excess registers, and may be modified by that procedure. The called procedure may also allocate few enough total registers in its stack frame that the top of the called procedure's frame is lower than the caller's top-of-frame, but those registers will become available again when control returns to the caller.
2.2.3.4.3. Rotating Registers
A subset of the registers in the procedure frame may be designated as rotating registers. The rotating register region always starts with R32, and may be any multiple of eight registers in number, up to a maximum of 96 rotating registers. The renaming is under control of the Register Rename Base (RRB).
If the rotating registers include any or all of the output registers, software must be careful when using the output registers for passing parameters, because a non-zero RRB will change the virtual register numbers that are part of the output region. In general, software should ensure either that the rotating region does not overlap the output region, or that the RRB is cleared to zero before setting output parameter registers.
2.2.3.4.4. Frame Markers
The current application-visible state of the register stack is stored in an architecturally inaccessible register called the current frame marker. On a procedure call, this register is automatically saved by copying it to an application register, the previous function state (AR.PFS). The current frame marker is modified to describe a new stack frame whose input and local area is initially zero size, and whose output area is equal in size to the previous output area. On return, the previous frame state register is used to restore the current frame marker to its earlier value, and the base of the register stack is adjusted accordingly.
It is the responsibility of a procedure to save the previous function state register before issuing any procedure calls of its own, and to restore it before returning.
2.2.3.4.5. Backing Store for Register Stack
When the depth of the procedure call stack exceeds the capacity of the physical register file, the hardware frees physical registers by saving them into a memory stack. This backing store is distinct from the memory stack described in Section 2.2.3.2, “Memory Stack”.
As returns unwind the procedure call stack, the hardware also restores previously-saved physical registers from the backing store.
The operation of this register stack engine (RSE) is mostly transparent to application software. While the RSE is running, application software may not examine the contents of the backing store, and may not make any assumptions about how much of the register stack is still in physical registers or in the backing store. In order to examine previous stack frames, application software must synchronize the RSE with the FLUSHRS instruction. Synchronizing the RSE forces all stack frames up to, but not including, the current frame to be saved in backing store, allowing the software to examine the contents of the backing store without asynchronous operations modifying the memory. Modifications to the backing store require setting the RSE to enforced lazy mode after synchronizing it, which prevents the RSE from doing any operations other than those required by calls and returns. The procedure for synchronizing the RSE and setting the mode is described in the Itanium® Software Conventions and Runtime Architecture Guide.
The backing store grows towards higher addresses. The top of the stack, which corresponds to the top of the previous procedure frame, is available in the Backing Store Pointer (BSP) application register. The BSP must always point to a valid backing store address, because the operating system may need to start the RSE to process an exception.
Backing store overflow is automatically detected by the OpenVMS operating system, which will either extend the backing store to allow continued operation or will raise an exception. Unlike for the memory stack (see Section 2.2.3.2, “Memory Stack”), there are no specific rules or requirements that must be satisfied to facilitate detection of backing store overflow.
A NaT collection register is stored into the backing store following each group of 63 physical registers. The NaT bit of each register stored is shifted into the collection register. When the BSP reaches the quadword just before a 64-quadword boundary, the RSE stores the collection register. Software can determine the position of the NaT collection registers in the backing store by examining the memory address. This process is described in greater detail in the Itanium® Software Conventions and Runtime Architecture Guide.
2.2.4. Stack Procedure Usage for OpenVMS x86-64
Variable-size stack procedure (sometimes known as a normal procedure in industry x86-64 documentation)—allocates a memory stack that is addressable using either
%rbp
(the frame pointer register) or%rsp
(the stack pointer register). The size of the stack may vary during the procedure execution. The called procedure may maintain a part or the whole context of its caller on that stack.Fixed-size stack procedure (sometimes known as a framepointerless procedure in industry x86-64 documentation)—allocates a memory stack that is addressable only using
%rsp
(the stack pointer register). The size of the stack is fixed during the procedure execution. The called procedure may maintain a part or the whole context of its caller on that stack.Null frame procedure (sometimes known as a frameless procedure in industry x86-64 documentation)—allocates no memory stack (other than the implicit saving of the caller return address that is a part of the CALL instruction). No context of its caller is saved.
All types of procedures allow use of 128 bytes of temporary storage below the address given in the stack pointer. This so-called red zone is not preserved across procedure calls, but is preserved by signal and condition handlers. Outside of the kernel, procedures may use this for temporary storage. Because hardware interrupts do not preserve the red zone, kernel code cannot use it. The use of the red zone can be disabled with a compiler option or pragma.
The red zone is useful in frameless leaf procedures (that call no other procedures). It gives them 128 bytes of scratch storage without the performance overhead of setting up and taking down a stack frame.
A compiler chooses which type of procedure to generate based on the requirements of the procedure in question. A calling procedure does not need to know what type of procedure it is calling.
Every variable-size stack or fixed-size stack procedure must have an associated unwind description (see the VSI OpenVMS Calling Standard) that provides information on the procedure type and its characteristics. A null frame procedure may also have an associated unwind description. (The default description applies if there is no unwind description). This data structure is used to interpret the call stack at any given point in a thread execution. It is built at compile time and usually is not accessed at run-time except to support exception processing or other rarely executed code.
2.2.4.1. Variable-Size Stack Procedures
Variable-size stack procedures allocate the stack that grows towards lower
addresses. The stack pointer (SP) is contained in the %rsp
register. The frame pointer (FP) is contained in the %rbp
register. The stack pointer is normally 0mod16 aligned and must be 0mod16
aligned when making a call. Because the return address is pushed on the stack by
the caller, the stack pointer is 8mod16 aligned on entry to a procedure. The
%rbp
register is saved immediately below the return
address. The frame pointer points to the saved %rbp
.

2.2.4.2. Fixed-Size Stack Procedures
Fixed-size stack procedures allocate the stack that grows towards lower
addresses. The stack pointer (SP) is contained in the %rsp
register. No frame pointer (FP) is used, so that the %rbp
register is available as an additional preserved register. The stack pointer is
normally 0mod16 aligned and must be 0mod16 aligned when making a call. Because
the return address is pushed on the stack by the caller, the stack pointer is
8mod16 aligned on entry to a procedure.

2.2.4.3. Null Frame Procedures
A null frame procedure is almost a special case of a fixed-size stack procedure. It is like a fixed-size stack which has no local storage other than the return address that is pushed on the stack as a result of the call. Because no additional stack is allocated it is unlike a fixed-size stack in that the alignment of the stack pointer is 8mod16 (not 0mod16).
A null frame procedure is necessarily a leaf procedure because the stack pointer must be 0mod16 aligned in order to make a call.

2.3. Procedure Representation
A procedure value is an address value that represents a procedure.
2.3.1. Procedure Values on OpenVMS VAX
On OpenVMS VAX systems, a procedure value is the address of the procedure entry mask that begins the actual code sequence of the procedure.
2.3.2. Procedure Values on OpenVMS Alpha
On OpenVMS Alpha systems, a procedure value in R27 is the address of the procedure descriptor that describes that procedure. So any OpenVMS Alpha procedure can be invoked by calling the stored address at offset 8 from the procedure descriptor (PDSC) starting address (procedure value).
2.3.3. Procedure Values on OpenVMS I64
On OpenVMS I64 systems, a procedure value is the address of a function descriptor, which consists of at least two quadword fields: the address of the entry point and the GP value required by that procedure.
Every procedure whose address is taken, or might be taken, must have a unique official function descriptor. The address of this function descriptor is used for the procedure value that is passed as a parameter or when two procedure values are compared. For other purposes, additional local function descriptors may be used for efficiency (notably in images other than the image that contains the procedure).
An official function descriptor for any procedure which might be callable from a VAX or Alpha translated image must include signature information. A local function descriptor used to call a procedure that might be part of a VAX or Alpha translated image must also include additional fields to facilitate the call. Both of these cases are described in the VSI OpenVMS Calling Standard.
A function descriptor for a bound procedure uses a special pseudo-GP value and includes an uplevel frame pointer. Such function descriptors are described in the VSI OpenVMS Calling Standard.
Kinds and Roles |
Size (Quadwords) |
---|---|
Local function descriptor without translated image support | 2 |
Local function descriptor with translated image support (jacket function descriptor) | 4 |
Official function descriptor without translated image support | 3 |
Official function descriptor with translated image support | 3 |
Bound function descriptor | 6 |
Note that the different kinds of function descriptor are not self-identifying (that is, they do not contain any form of tag or kind field).
2.3.4. Procedure Values on OpenVMS x86-64
On OpenVMS x86-64 systems, a procedure value (a function pointer) is a pointer to code. To call through a procedure value, call through the value itself, not through a location in the memory pointed to by the value.
All procedure values must be representable in 32 bits. Because 32-bit addresses and pointers are always sign-extended before use, this means that the code they point to must reside in either the (hexadecimal) range 0..7FFFFFFF FFFFFFFF or 80000000 00000000..FFFFFFFF FFFFFFFF (see the VSI OpenVMS Programming Concepts Manual, Volume I for discussion of the structure of the OpenVMS address space). If the code is not in either of these regions, the linker creates a 32-bit-addressable trampoline for it. The trampoline code simply jumps to the procedure. The address of this trampoline becomes the value for that procedure.
Unbound procedures normally do not require an associated trampoline. They need a trampoline only if code in the same image takes the address of the procedure, or if it is a universal symbol.
Bound procedure values always point to trampolines. These trampolines are created by the containing procedure at the time it is called. When the bound procedure value trampolines pass control to the procedure, they pass an environment pointer (a pointer to the containing procedure stack frame) as an additional hidden parameter to the procedure.
2.4. Argument List
The calling standard defines a data structure called the argument list. An argument list is a sequence of locations in memory that represents a routine parameter list and possibly includes a function value. You use an argument list to pass information to a routine and receive results.
2.4.1. Argument Lists on OpenVMS VAX
On OpenVMS VAX systems, the first longword in an argument list (see Figure 2.9, “Structure of a VAX Argument List”) stores the number of arguments (the argument count, n) as an unsigned integer value. The maximum argument count is 255. The remaining 24 bits of the first longword are reserved for OpenVMS and must be 0.
Both integer and floating-point values can be an argument passed in the argument list. Note that a 64-bit floating-point argument counts as 2 longword arguments in the list.

2.4.2. Argument Lists on OpenVMS Alpha
On OpenVMS Alpha systems, arguments are quadwords, and the calling program passes arguments in an argument item sequence. Each quadword in the sequence specifies a single argument. The argument item sequence is formed using R16—21 or F16—21 (a register for each argument). The argument item sequence can have a mix of integer and floating-point items that use both register types but must not repeat the same number. For example, an argument list might use R16, R17, F18, and R19. If there are more than six arguments, the argument items overflow to the end of the stack, as shown in Figure 2.10, “Alpha Argument List Format”.

The calling procedure must pass to the called procedure information about the argument list. For high-level languages, this is performed by the language processor. In the argument information (AI) register (R25), the quadword format is the structure shown in Figure 2.11, “Argument Information (AI) Register (R25) Format”. The AI register contains the argument count in the first byte. Table 2.15, “Contents of the Argument Information Register (R25)” describes the argument information fields in detail.

Field Name |
Contents | ||
---|---|---|---|
AI$B_ARG_COUNT |
Unsigned byte <7:0> that specifies the number of 64-bit argument items in the argument list (known as the “argument count”). | ||
AI$V_ARG_REG_ |
An 18-bit vector field <25:8> divided into six groups of 3 bits that correspond to the six arguments passed in registers. These groups describe how each of the first six arguments are passed in registers with the first group <10:8> describing the first argument. The encoding for each group for the argument register usage follows: | ||
Value |
Name |
Meaning | |
0 |
AI$K_AR_I64 |
64-bit or 32-bit sign-extended to 64-bit argument passed in an integer register (including addresses). or Argument is not present. | |
1 |
AI$K_AR_FF |
F_floating argument passed in a floating register. | |
2 |
AI$K_AR_FD |
D_floating argument passed in a floating register. | |
3 |
AI$K_AR_FG |
G_floating argument passed in a floating register. | |
4 |
AI$K_AR_FS |
S_floating argument passed in a floating register. | |
5 |
AI$K_AR_FT |
T_floating argument passed in a floating register. | |
6, 7 | — |
Reserved. | |
Bits 26—63 |
Reserved and must be 0. |
2.4.3. Argument Lists on OpenVMS I64
On OpenVMS I64 systems, parameters are passed in a combination of general registers, floating-point registers, and memory, as illustrated in Figure 2.12, “Parameter Passing in Registers and Memory”.
The parameter list is formed by placing each individual parameter into fixed-size elements of the parameter list, referred to as parameter slots. Each parameter slot is 64 bits wide; parameters larger than 64 bits are placed in as many consecutive parameter slots as are needed to contain the entire parameter. The rules for allocation and alignment of parameter slots are described in Section 2.4.3.1, “Allocation of Parameter Slots”.
The contents of the first eight parameter slots are always passed in registers, while the remaining parameters are always passed on the memory stack, beginning at the caller's stack pointer plus 16 bytes. The caller uses up to eight of the registers in the output region of its register stack for integer and VAX floating-point parameters, and up to eight floating-point registers for IEEE floating-point parameters. The maximum number of registers used is eight.

To accommodate variable argument lists in the C language, there is a fixed correspondence between parameter slots; the first parameter slot is always in either the first general output register or the first floating-point register (never both), the second parameter slot is always in the second general output register or the second floating-point register (never both), and so on. This allows a procedure to spill its register parameters easily to memory to form the argument home area before stepping through the parameter list with a pointer. The Argument Information register (AI) makes this possible, as explained in Section 2.4.3.3, “Argument Information (AI) Register”.
A procedure can assume that the NaT bits on its incoming general register arguments are clear, and that the incoming floating-point register arguments are not NaTVals. A procedure making a call must ensure only that registers containing actual parameters are clear of NaT bits or NaTVals; registers not used for actual parameters are undefined.
The parameter passing mechanisms for I64 are generally the same as for Alpha and are included here for completeness. Two notable difference between Alpha and I64 are that the first six parameter slots are passed in registers for Alpha, while for I64 the first eight parameter slots are passed in registers; and that I64 passes VAX floating-point parameters in general registers.
2.4.3.1. Allocation of Parameter Slots
Type |
Size (Bits) |
Number of Slots |
---|---|---|
Integer, small set |
1-64 |
1 |
Address/pointer (including all types passed by reference or descriptor) |
64 |
1 |
IEEE single-precision floating-point (S_floating) |
32 |
1 |
IEEE single-precision floating-point complex (S_floating) |
64 |
2 |
IEEE double-precision floating-point (T_floating) |
64 |
1 |
IEEE double-precision floating-point complex (T_floating) |
128 |
2 |
IEEE quad-precision floating-point (X_floating) |
64 (by reference) |
1 |
IEEE quad-precision floating-point complex (X_floating) |
64 (by reference) |
1 |
Aggregates (noncomplex) |
any |
(size+63)/64 |
VAX single-precision floating-point (F_floating) |
32 |
1 |
VAX single-precision floating-point complex (F_floating) |
64 |
2 |
VAX double-precision floating-point (D_ & G_floating) |
64 |
1 |
VAX double-precision floating-point complex (D_ & G_floating) |
128 |
2 |
Note
These rules are applied based on the type of the parameter after any type-promotion rules specified by the language have been applied. For example, a short integer passed without a function prototype in C is promoted to the int type, and is then passed according to the rules for the int type.
OpenVMS does not support passing the I64 double-precision extended
floating-point type (__float80
), although that type may be
used from time to time in code generation sequences.
This placement policy does not ensure that parameters greater than 64 bits in size will fall on a natural alignment boundary if passed in memory. Such parameters may need to be copied by the called procedure into an aligned temporary prior to use, or accessed in a way that does not depend on natural alignment.
2.4.3.2. Normal Register Parameters
These eight argument slots are associated, one-to-one, with the stacked output general registers, as shown in Figure 2.12, “Parameter Passing in Registers and Memory”.
Integral scalar parameters, (including addresses and pointers), VAX floating-point parameters, and aggregate parameters in these slots are passed only in the corresponding output general registers.
Aggregate parameters in these slots are passed by value only in the corresponding output general registers. The aggregate is treated as a sequence of 64-bit integral values, with each value allocated into the next available slot in aggregate memory address order. If the size of the aggregate is not an even multiple of 64 bits, then the unused bits in the last slot are undefined.
If an aggregate or VAX floating-point complex parameter straddles the boundary between slot 7 and slot 8, the part that lies within the first eight slots is passed in general registers, and the remainder is passed in memory, as described in Table 2.17, “Unused Bits in Passed Data”.
Complex values (other than IEEE quad-precision floating-point complex), in those languages that include complex types, are passed as a pair of floating-point values (either single-precision or double-precision as appropriate). It is possible for the first of the two floating-point values in a complex value to occupy the last output register slot; in this case, the second floating-point value is passed in memory. IEEE quad-precision floating-point complex values are passed by reference.
IEEE single-precision and double-precision floating-point scalar parameters are passed in the corresponding floating-point register slot. IEEE quad-precision floating-point scalar parameters are passed by reference in the corresponding output general registers.
When IEEE floating-point parameters are passed in floating-point registers, they are passed in the register format, rounded to the appropriate precision. They are never passed in the general registers unless part of an aggregate, in which case they are passed in the aggregate memory format. When VAX floating-point parameters are passed in general registers, they are passed in memory format.
Parameters allocated beyond the eighth parameter slot are never passed in registers.
Note
Bit 31 is replicated in bits 32—63, even for unsigned 32-bit integers.
Data Type |
Type Designator? |
Data Size (bytes) |
Register Extension Type |
Memory Extension Type |
---|---|---|---|---|
Byte logical |
DSC$K_DTYPE_BU |
1 |
Zero64 |
Zero64 |
Word logical |
DSC$K_DTYPE_WU |
2 |
Zero64 |
Zero64 |
Longword logical |
DSC$K_DTYPE_LU |
4 |
Sign64 |
Sign64 |
Quadword logical |
DSC$K_DTYPE_QU |
8 |
Data64 |
Data64 |
Byte integer |
DSC$K_DTYPE_B |
1 |
Sign64 |
Sign64 |
Word integer |
DSC$K_DTYPE_W |
2 |
Sign64 |
Sign64 |
Longword integer |
DSC$K_DTYPE_L |
4 |
Sign64 |
Sign64 |
Quadword integer |
DSC$K_DTYPE_Q |
8 |
Data64 |
Data64 |
F_floating |
DSC$K_DTYPE_F |
4 |
VAXF64 |
Data32 |
D_floating |
DSC$K_DTYPE_D |
8 |
VAXDG64 |
Data64 |
G_floating |
DSC$K_DTYPE_G |
8 |
VAXDG64 |
Data64 |
F_floating complex |
DSC$K_DTYPE_FC |
2 * 4 |
2*VAXF64 |
2*Data32 |
D_floating complex |
DSC$K_DTYPE_DC |
2 * 8 |
2*VAXDG64 |
2*Data64 |
G_floating complex |
DSC$K_DTYPE_GC |
2 * 8 |
2*VAXDG64 |
2*Data64 |
S_floating |
DSC$K_DTYPE_FS |
4 |
Hard |
Data32 |
T_floating |
DSC$K_DTYPE_FT |
8 |
Hard |
Data64 |
X_floating |
DSC$K_DTYPE_FX |
16 |
N/A |
N/A |
S_floating complex |
DSC$K_DTYPE_FSC |
2 * 4 |
2*Hard |
2*Data32 |
T_floating complex |
DSC$K_DTYPE_FTC |
2 * 8 |
2*Hard |
2*Data64 |
X_floating complex |
DSC$K_DTYPE_FXC |
2 * 16 |
N/A |
N/A |
Small structures of 8 bytes or less |
N/A |
≤8 |
Nostd |
Nostd |
Small arrays of 8 bytes or less |
N/A |
≤8 |
Nostd |
Nostd |
32-bit address |
N/A |
4 |
Sign64 |
Sign64 |
64-bit address |
N/A |
8 |
Data64 |
Data64 |
Sign Extension Type |
Defined Function |
---|---|
Sign64 |
Sign-extended to 64 bits. |
Zero64 |
Zero-extended to 64 bits. |
Data32 |
Data is 32 bits. The state of bits <63:32> is unpredictable. |
2*Data32 |
Two single-precision parts of the complex value are stored in memory as independent floating-point values (each handled as Data32). |
Data64 |
Data is 64 bits. |
2*Data64 |
Two double-precision parts of the complex value are stored in memory as independent floating-point values (each handled as Data64). |
VAXF64 |
Data is 64 bits. Low-order 32 bits are the same as the F_floating memory format and the high-order 32 bits are zero. (Used only in a general register, never in a floating-point register). |
VAXDG64 |
Data is 64 bits. Uses the corresponding D_floating or G_floating memory format. (Used only in a general register, never in a floating-point register.) |
2*VAXF64 |
Two single-precision parts of the complex value are stored in memory as independent floating-point values (each handled as VAXF64). |
2*VAXDG64 |
Two double-precision parts of the complex value are stored in memory as independent floating-point values (each handled as VAXDG64). |
Hard |
Passed in the layout defined by the hardware SRM. |
2*Hard |
Two floating-point parts of the complex value are stored in a pair of registers as independent floating-point values (each handled as Hard). |
Nostd |
State of all high-order bits not occupied by the data is unpredictable across a call or return. |
2.4.3.3. Argument Information (AI) Register
In addition to the normal parameters, an implicit argument information value is passed in register R25, the Argument Information (AI) register. This value is shown in Figure 2.13, “Argument Information Register Representation”. Note that I64 passes eight arguments in registers, while Alpha passes six arguments in registers.

Argument Count is an unsigned byte that specifies the number of 64-bit argument slots used for the argument list. (Note that single- and double-precision complex values use two slots, which is reflected in this count).
Value |
OpenVMS Name |
Meaning |
---|---|---|
0 |
AI$K_AR_I64 |
64-bit or 32-bit sign-extended to 64-bit argument passed in an integer register (including addresses). or Argument is not present. |
1 |
AI$K_AR_FF |
F_floating (also known as VAX single-precision floating-point) argument passed in a general register. |
2 |
AI$K_AR_FD |
D_floating (also known as VAX double-precision floating-point) argument passed in a general register. |
3 |
AI$K_AR_FG |
G_floating (also known as VAX double-precision floating-point) argument passed in a general register. |
4 |
AI$K_AR_FS |
S_floating (also known as IEEE single-precision floating-point) argument passed in a floating-point register. |
5 |
AI$K_AR_FT |
T_floating (also known as IEEE double-precision floating-point) argument passed in a floating-point register. |
6,7 |
— |
Reserved. |
2.4.3.4. Memory Stack Parameters
The remainder of the parameter list, beginning with slot 8, is passed in the outgoing parameter area of the memory stack frame, as described in the VSI OpenVMS Calling Standard. Parameters are mapped directly to memory, with slot 8 placed at location SP+16, slot 9 placed at location SP+24, and so on. Each argument is stored in memory as a series of one or more 64-bit storage units, with unused bits in the last unit undefined.
2.4.3.5. Variable Argument Lists
The rules above support variable-argument list functions in both the K&R and the ANSI dialects of the C language. (Note that argument location is independent of whether a prototype is in scope).
The nth argument is in either Rn or Fn regardless of the type of parameter in the preceding register slot. Therefore, a function with variable arguments may assume that the variable arguments that lie within the first eight argument slots can be found in either the stacked input integer registers (IN0-IN7), or in the floating-point parameter registers (F8-F15). Using the information codes from the AI (Argument Information) register (see Table 2.19, “Argument Information Register Codes”), the function can then store these registers to memory using the 16-byte scratch area for IN6/F14 and IN7/F15, and up to 48 bytes at the base of its own stack frame for IN0/F8-IN5/F13, as necessary. This arrangement places all of the variable parameters in one contiguous block of memory.
2.4.3.6. Pointers to Formal Parameters
Whenever the address is formed of a formal parameter that is passed in a register, the compiler must store the parameter to the stack, as it would for a variable argument list.
2.4.3.6.1. Languages Other than C
The placement of arguments in general registers versus floating-point registers does not depend on any notion or concept of a prototype being in scope. It is therefore applicable to all languages at all times.
2.4.3.7. Rounding Floating-Point Values
There must be no difference in behavior between a floating-point parameter passed directly in a register and a floating-point parameter that has been stored to memory and reloaded. In either case, the floating-point value must be the same. This implies that floating-point parameters passed in floating-point registers must be explicitly rounded to the proper precision by the caller.
2.4.4. Argument Lists on OpenVMS x86-64
On OpenVMS x86-64 systems, procedure parameters are passed in registers and/or on the stack.
2.4.4.1. Scalar Argument Types
the six general-purpose registers (
%rdi
,%rsi
,%rdx
,%rcx
,%r8
, and%r9
)the eight XMM registers (
%xmm0—%xmm7
)the stack.
Nominal Type | Argument Location | Return Value Location |
---|---|---|
Pointer [Q] |
The next available general-purpose register. Otherwise, in the next argument slot on the stack. | General-purpose register
%rax |
Boolean [B, BU] | ||
Integers (size ≤ 64 bits) [B, W, L, Q, BU, WU, LU, QU] | ||
Integers (64 < size ≤ 128 bits) [O, OU] |
The next two available general-purpose registers. Otherwise, in the next two argument slots on the stack. | General-purpose registers %rax (low
half) and %rdx (high half) |
VAX float (F_floating, D_floating, and G_floating) [F, D, G] |
The next available general-purpose register. Otherwise, in the next argument slot on the stack. | General-purpose register %rax |
IEEE single-precision float (S_floating) [FS] |
Bits 31:0 of the next available XMM register. Otherwise, in the next argument slot on the stack. | Bits 31:0 of register %xmm0 |
IEEE double-precision float (T_floating) [FT] |
Bits 63:0 of the next available XMM register. Otherwise, in the next argument slot on the stack. | Bits 63:0 of register %xmm0 |
IEEE quadruple-precision float (X_floating) [FX] |
The next available XMM register. Otherwise, in the next two argument slots on the stack. | Register %xmm0 |
VAX complex single-precision float (F_floating) [FC] |
The next available general-purpose register. Otherwise, in the next argument on the stack. |
General-purpose register
|
VAX complex double-precision float (D_floating and G_floating) [DC, GC] |
The next two available general-purpose registers. Otherwise, in the next two argument slots on the stack. | Registers %rax (the real part of a
value) and %rdx (the imaginary part of a
value) |
IEEE complex single-precision float [FSC] |
In the next available XMM register, real part in bits 31:0, imaginary part in bits 63:32. Otherwise, in the next argument slot on the stack. | Register %xmm0 , the real part of a
value in bits 31:0, the imaginary part in bits 63:32 |
IEEE complex double-precision float [FTC] |
In bits 63:0 of the next two available XMM registers. Otherwise, the next two argument slots on the stack. | Bits 63:0 of registers %xmm0 (the real
part of a value) and %xmm1 (the imaginary
part of a value) |
IEEE complex quadruple-precision float [FXC] | In the next four available argument slots on the stack. | In a caller-allocated memory buffer whose address is passed as a hidden first argument |
An argument that requires two registers is never split so that the first part is in a register and the second part is on the stack. Either both parts are in registers or both parts are on the stack.
For example, a procedure that takes ten integer scalar arguments will find the first six arguments in the general-purpose registers, and the last four on the stack. A procedure that takes ten IEEE double-precision floating-point scalars as arguments will find the first eight arguments in the XMM registers, and the last two on the stack. And, a procedure that takes six integer arguments and eight floating-point arguments, regardless of how the integer and floating-point arguments are intermixed, will find all 14 arguments in registers.
2.4.4.2. Aggregate Argument Types
This section describes how the aggregate argument types are passed to procedures.
First, the argument types are assigned in the appropriate classes and then the registers are allocated for passing them.
INTEGER class consists of integral types that fit in one of the general-purpose registers including pointers.
SSE class consists of types that fit in a floating-point register.
SSEUP class consists of types that fit into a floating-point register and can be passed and returned in the upper bytes of it.
X87, X87UP, COMPLEX_X87 classes consist of types that can be returned via the x87 FPU.
NO_CLASS is used as initializer in the algorithms. It is used for padding as well as empty structures and unions.
MEMORY class consists of types that are passed and returned in memory via the stack.
The size of each argument is rounded up to a quadword (8 bytes). Therefore, the stack will always be 8-byte aligned.
Nominal Type | Equivalent C/C++ Type(s) | Argument Passing Class |
---|---|---|
Pointer [Q] | * | INTEGER |
Boolean [B, BU] | _Bool (bool) | |
Integers (size ≤ 64 bits) [B, W, L, Q, BU, WU, LU, QU] | char, short, int, long (signed and unsigned) | |
Integers (64 < size ≤ 128 bits) [O, OU] | __int128 (signed and unsigned) | Split into two 8-byte chunks. Both belong to class INTEGER. |
VAX floating-point types (up to 64 bits) [F, D, G] | INTEGER | |
VAX floating-point complex (64 bits) [FC] | INTEGER | |
VAX floating-point complex (128 bits) [DC, GC] | Split into two 8-byte chunks. Both belong to class INTEGER. | |
IEEE binary floating-point types (up to 64 bits) [FS, FT] | float, double | SSE |
IEEE extended binary floating-point type (128 bits) [FX] | __float128 | Split into two halves. The first (lower addressed) 64-bits belong to class SSE and the second half to class SSEUP. |
IEEE binary floating-point complex (64 bits) [FSC] | complex float | Treat as two successive binary floating-point values, each treated as a scalar of half the size (see above). |
IEEE binary floating-point complex (128 bits) [FTC] | complex double | |
IEEE binary floating-point complex (256 bits) [FXC] | complex long double |
If the size of an object is larger than eight quadwords (64 bytes), or it contains unaligned fields, it belongs to the MEMORY class.
If a C++ object is non-trivial for the purpose of calls, as specified in the C++ ABI?, it is passed by an invisible reference—that is, the object is replaced in the parameter list by a pointer that has the INTEGER class.?
If the size of the aggregate exceeds a single quadword, each quadword is classified separately. Each quadword is initialized to the NO_CLASS class.
- Each field of an object is classified recursively so that always two fields are considered. The two fields are the containing quadword as a whole and the lowest level field components of the quadword, considered in order:
If both classes are equal, this is the resulting class.
If one of the classes is NO_CLASS, the resulting class is the other class.
If one of the classes is MEMORY, the result is the MEMORY class.
If one of the classes is INTEGER, the result is the INTEGER class.
If one of the classes is X87, X87UP, or COMPLEX_X87, the result is the MEMORY class.
Otherwise the result is the SSE class.
- Then a post merger cleanup is done:
If one of the classes is MEMORY, the whole argument is passed in memory.
If X87UP is not preceded by X87, the whole argument is passed in memory.
If the size of the aggregate exceeds two quadwords and the first quadword is not SSE or any other quadword is not SSEUP, the whole argument is passed in memory.
If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE.
If the class is MEMORY, the argument is passed on the stack.
If the class is INTEGER, the next available register of the sequence
%rdi
,%rsi
,%rdx
,%rcx
,%r8
, and%r9
is used.If the class is SSE, the argument is passed in the next available floating-point register. The registers are taken in order from
%xmm0
to%xmm7
.If the class is SSEUP, the quadword is passed in the next available 8-byte chunk of the last used floating-point register.
If the class is X87, X87UP, or COMPLEX_X87, the argument is passed in memory.
When a value of a boolean type is returned or passed in a register or on the stack, bit 0 contains the truth value, bits 1 to 7 must be zero, and all other bits are left unspecified. A consumer of such values can rely on it being 0 or 1 only when truncated to the low byte.
If there are no registers available for any quadword of an argument, the whole argument is passed on the stack. If registers have already been assigned for some quadwords of such an argument, the assignments are reverted.
Once registers are assigned, the arguments passed in memory are pushed on the stack in reversed (right-to-left?) order.
Nominal Type | Equivalent C/C++ Type(s) | Argument Passing Class |
---|---|---|
IEEE binary floating-point vector (up to 64 bits) [M64] | __m64 | SSE |
IEEE extended binary floating-point vector (128 bits) [M128] | __m128 | Split into two halves. The first (lower addressed) 64-bits belong to class SSE and the second half to class SSEUP. |
IEEE binary floating-point vector (256 bits) [M256] | __m256 | Split into four 8-byte chunks. The first chunk belongs to class SSE and the rest to class SSEUP. |
IEEE binary floating-point vector (512 bits) [M512] | __m512 | Split into eight 8-byte chunks. The first chunk belongs to class SSE and the rest to class SSEUP. |
When passing the __m256
or __m512
arguments to functions that use varargs or stdarg, function prototypes must be
provided. Otherwise, the run-time behavior is undefined.
2.4.4.3. Unused Bits in Passed Data
Note
Bit 31 is replicated in bits 32—63, even for unsigned 32-bit integers.
This rule applies to the argument types described in Section 2.4.4.1, “Scalar Argument Types” as well as the individual elements of aggregate types passed in general-purpose registers as described in Section 2.4.4.2, “Aggregate Argument Types”.
Data Type |
Type Designator? |
Data Size (bytes) |
Register Extension Type |
Memory Extension Type |
---|---|---|---|---|
Byte logical |
DSC$K_DTYPE_BU |
1 |
Zero64 |
Zero64 |
Word logical |
DSC$K_DTYPE_WU |
2 |
Zero64 |
Zero64 |
Longword logical |
DSC$K_DTYPE_LU |
4 |
Sign64 |
Sign64 |
Quadword logical |
DSC$K_DTYPE_QU |
8 |
Data64 |
Data64 |
Byte integer |
DSC$K_DTYPE_B |
1 |
Sign64 |
Sign64 |
Word integer |
DSC$K_DTYPE_W |
2 |
Sign64 |
Sign64 |
Longword integer |
DSC$K_DTYPE_L |
4 |
Sign64 |
Sign64 |
Quadword integer |
DSC$K_DTYPE_Q |
8 |
Data64 |
Data64 |
F_floating |
DSC$K_DTYPE_F |
4 |
VAXF64 |
Data32 |
D_floating |
DSC$K_DTYPE_D |
8 |
VAXDG64 |
Data64 |
G_floating |
DSC$K_DTYPE_G |
8 |
VAXDG64 |
Data64 |
F_floating complex |
DSC$K_DTYPE_FC |
2 * 4 |
2*VAXF64 |
2*Data32 |
D_floating complex |
DSC$K_DTYPE_DC |
2 * 8 |
2*VAXDG64 |
2*Data64 |
G_floating complex |
DSC$K_DTYPE_GC |
2 * 8 |
2*VAXDG64 |
2*Data64 |
S_floating |
DSC$K_DTYPE_FS |
4 |
Hard |
Data32 |
T_floating |
DSC$K_DTYPE_FT |
8 |
Hard |
Data64 |
X_floating |
DSC$K_DTYPE_FX |
16 |
N/A |
N/A |
S_floating complex |
DSC$K_DTYPE_FSC |
2 * 4 | Hard? |
2*Data32 |
T_floating complex |
DSC$K_DTYPE_FTC |
2 * 8 |
2*Hard |
2*Data64 |
X_floating complex |
DSC$K_DTYPE_FXC |
2 * 16 |
N/A |
N/A |
Small structures of 8 bytes or less |
N/A |
≤8 |
Nostd |
Nostd |
Small arrays of 8 bytes or less |
N/A |
≤8 |
Nostd |
Nostd |
32-bit address |
N/A |
4 |
Sign64 |
Sign64 |
64-bit address |
N/A |
8 |
Data64 |
Data64 |
Sign Extension Type |
Defined Function |
---|---|
Sign64 |
Sign-extended to 64 bits. |
Zero64 |
Zero-extended to 64 bits. |
Data32 |
Data is 32 bits. The state of bits <63:32> is unpredictable. |
2*Data32 |
Two single-precision parts of the complex value are stored in memory as independent floating-point values (each handled as Data32). |
Data64 |
Data is 64 bits. |
2*Data64 |
Two double-precision parts of the complex value are stored in memory as independent floating-point values (each handled as Data64). |
VAXF64 |
Data is 64 bits. Low-order 32 bits are the same as the F_floating memory format and the high-order 32 bits are zero. (Used only in a general register, never in a floating-point register). |
VAXDG64 |
Data is 64 bits. Uses the corresponding D_floating or G_floating memory format. (Used only in a general register, never in a floating-point register). |
2*VAXF64 |
Two single-precision parts of the complex value are stored in memory as independent floating-point values (each handled as VAXF64). |
2*VAXDG64 |
Two double-precision parts of the complex value are stored in memory as independent floating-point values (each handled as VAXDG64). |
Hard |
Passed in the layout defined by the hardware SRM. |
2*Hard |
Two floating-point parts of the complex value are stored in a pair of registers as independent floating-point values (each handled as Hard). |
Nostd |
State of all high-order bits not occupied by the data is unpredictable across a call or return. |
2.4.4.4. Argument Information Register (AI)
%rax
is used as the AI register. It must
contain the argument information that is presented in Table 2.25, “Contents of the Argument Information Register
(%rax
)”.%rax
)Bit | Contents |
---|---|
7:0 (%al ) | Upper bound on the number of XMM registers that are used to pass arguments |
15:8 (%ah ) | Total number of passed argument slots |
47:16 | Argument Info Offset relative to the return address of the caller, or zero |
63:48 |
Reserved and must be either 0x0000 or 0xFFFF? |
If the Argument Info Offset field is non-zero, it contains a signed byte offset to an Argument Info Block (AIB). This byte offset is relative to the return address of the caller, that is, an offset from the location of the instruction after the call instruction. The Argument Info Block must be close enough to the call site for the offset to fit in 32 bits. If the AIB is in the same section as the code, this offset can be calculated at compile time.
Bit | Name | Usage |
---|---|---|
7:0 | version | Format version. This format is version 1. |
15:8 | arg info count | Number of argument slots represented in this block. |
19:16 | 1st arg info | Information on the 1st argument slot. |
23:20 | 2nd arg info | Information on the 2nd argument slot. |
. | ||
Information on the nth argument slot. |
The arg info count may be less than, equal to, or greater than the actual number of passed arguments. If it is less, the missing argument information fields are assumed to be 0 (AI$K_AR_I64). If it is greater, the extra entries in this block are ignored.
If all the passed arguments are integers and pointers, there is no need to pass an Argument Info Block. Instead, the Argument Info Offset should be set to zero.
Value | Name | Meaning |
---|---|---|
0 | AI$K_AR_I64 |
Argument is passed in a general-purpose register, if one is available, otherwise on the stack. or Argument is not present. |
1 | AI$K_AR_FF | F_floating argument is passed in a general-purpose register. |
2 | AI$K_AR_FD | D_floating argument is passed in a general-purpose register. |
3 | AI$K_AR_FG | G_floating argument is passed in a general-purpose register. |
4 | AI$K_AR_FS | Argument is passed in bits 31:0 of an XMM register. |
5 | AI$K_AR_FT | Argument is passed in bits 63:0 of an XMM register. |
6 | AI$K_AR_FXL | Low half of argument is passed in bits 63:0 of an XMM register. |
7 | AI$K_AR_FXH | High half of argument is passed in bits 127:64 of an XMM register. |
8 | AI$K_AR_MEM | Argument is pushed on the stack. |
9—15 | — | Reserved. |
2.4.4.5. Variable Argument Lists
The x86-64 industry standards define how C-style variable argument lists (va_start, va_arg and so on) are implemented. OpenVMS also allows variable argument lists to be accessed as arrays. On prior OpenVMS architectures, a single common mechanism supports both. On OpenVMS x86-64, different mechanisms are implemented.
2.4.4.5.1. Standard Variable Arguments
Offset | Register | Usage |
---|---|---|
0 | %rdi | 1st general-purpose argument register |
8 | %rsi | 2nd general-purpose argument register |
16 | %rdx | 3rd general-purpose argument register |
24 | %rcx | 4th general-purpose argument register |
32 | %r8 | 5th general-purpose argument register |
40 | %r9 | 6th general-purpose argument register |
48 | %xmm0 | 1st floating-point argument register |
64 | %xmm1 | 2nd floating-point argument register |
80 | %xmm2 | 3rd floating-point argument register |
96 | %xmm3 | 4th floating-point argument register |
112 | %xmm4 | 5th floating-point argument register |
128 | %xmm5 | 6th floating-point argument register |
144 | %xmm6 | 7th floating-point argument register |
160 | %xmm7 | 8th floating-point argument register |
The register save area is always allocated in the stack frame of the
called function. Any function that contains an invocation of the va_start
macro must save argument registers in the register save area. The six
general-purpose registers are always saved. The number of floating-point
registers to be saved depends on the value passed in the
%al
register. In theory, code should not save more
registers than indicated in %al
, but in practice, it
either saves none (if %al
is zero) or all the
registers.
The standard requires the caller to pass a floating-point register
argument count in the %al
register whenever the called
function uses the C variable arguments. This includes not only functions
explicitly declared with the variable arguments, but all unprototyped
functions as well.
Note that the OpenVMS “arginfo notused” linkage does not influence whether
this value is passed in the %al
or not. The passed value
does not need to be absolutely correct, but should at least be an upper
bound on the number of arguments passed in floating-point registers.
Offset | Field | Usage |
---|---|---|
0 | gp_offset | Byte offset from the start of the register save area of the next available saved integer argument register |
4 | fp_offset | Byte offset from the start of the register save area of the next available saved floating-point argument register |
8 | overflow_arg_area | Pointer to the first available stack argument |
16 | reg_save_area | Pointer to the register save area |
gp_offset is the byte offset within the register save area of the first unused general-purpose register.
fp_offset is the byte offset within the register save area of the first unused floating-point register.
overflow_arg_area points to the first unused stack argument.
reg_save_area points to the register save area that is already initialized.
printf(const char *fmt, ...)
function, the va_list structure is initialized as follows:gp_offset is set to +8, the offset of the second general-purpose argument; the first argument (
fmt
) is already used.fp_offset is set to +48, the offset of the first floating-point argument.
overflow_arg_area is set to FP+16, the location of the first stack argument.
When the va_arg macro is invoked, it fetches the argument from a saved register or the stack and increments one field on the va_list structure accordingly. For example, if an integer argument is requested, the va_arg macro will compare the value of gp_offset against 48. If gp_offset is less than 48, the va_arg macro will return a saved integer register and increment gp_offset. Otherwise, it will return a stack argument and increment overflow_arg_area.
2.4.4.5.2. OpenVMS Variable Argument Lists
ARGPTR, ACTUALPARAMETER and ACTUALCOUNT in BLISS
[list], argument, and argument_list_length in VSI Pascal
va_count in VSI C
All rely on OpenVMS extensions to the standard calling conventions.
On OpenVMS standard calls, the caller passes argument information in the
%rax
register that specifies the total number of the
used argument slots and location of each register argument. In theory, this
information only needs to be passed if the called procedure uses one of the
above mentioned language constructs, but since the caller is not able to
determine this, the argument information is passed in
%rax
on all OpenVMS standard calls. It can be
suppressed with the “arginfo notused” linkage specification.
%ah
. If a called procedure requests an argument list,
the called procedure performs the following:Allocates the storage in its own stack frame for the entire arglist (8 *
%ah
).Copies all general-purpose registers, floating-point registers, and memory arguments to the arglist as indicated by the values in
%rax
.
Unlike the prior OpenVMS architectures, on OpenVMS x86-64 it is not possible to create a register “home” on the stack that is contiguous with the incoming memory arguments.
2.5. Argument Passing Mechanisms
Each high-level language supported by OpenVMS provides a mechanism for passing arguments to a procedure. The specifics of the mechanism and the terminology used, however, vary from one language to another. For specific information, refer to the appropriate high-level language user's guide.
arg1
through argn
are the actual parameters, which can be any of the
following addresses or value:An uninterpreted 32-bit value on VAX or 64-bit value on Alpha and I64 systems is passed by value.
An address of a data value is passed by reference.
An address of a descriptor that contains a pointer to a data value is passed by descriptor (for example, a string might be the data value).


OpenVMS programming reference manuals provide a description of each OpenVMS system routine that indicates how each argument is to be passed. Phrases such as “an address” and “address of a character string descriptor” identify reference and descriptor arguments, respectively. Terms like “Boolean value,” “number,” “value,” and “mask” indicate an argument that is passed by value.
2.5.1. Passing Arguments by Value
When your program passes an argument using the by value mechanism, the argument list entry contains either the actual uninterpreted 32-bit VAX value or a 64-bit Alpha or I64 value (zero- or sign-extended) of the argument. For example, to pass the constant 100 by value, the calling program puts 100 directly in the argument list or sequence. For more information about passing 64-bit Alpha and I64 values, refer to VSI OpenVMS Programming Concepts Manual, Volume I.
All high-level languages (except C) require you to specify the by-value mechanism explicitly when you call a procedure that accepts an argument by value. For example, FORTRAN uses the %VAL built-in function, while COBOL uses the BY VALUE qualifier on the CALL[USING] statement.
INCLUDE '($SSDEF)' CALL LIB$STOP (%VAL(SS$_INTOVF))
LIB$SIGNAL (SS$_INTOVF)
PUSHL #SS$_INTOVF ; Push longword by value CALLS #1,G^LIB$SIGNAL ; Call LIB$SIGNAL
#include <starlet.h> /* Declare the function*/
.
.
enum cluster0
{
completion, breakdown, beginning
} event;
int status;
event = completion;
.
.
status = sys$setef(event); /* Set event flag */
2.5.2. Passing Arguments by Reference
When your program passes arguments using the by reference
mechanism, the argument list entry contains the address of the location that
contains the value of the argument. For example, if variable x
is
allocated at location 1000, the argument list entry will contain 1000, the address
of the value of x
.
On Alpha processors and I64, the address is sign-extended from 32 bits to 64 bits.
Most languages (but not C) pass scalar data by reference by default. Therefore, if
you simply specify x
in the CALL statement or function
invocation, the language automatically passes the value stored at the location
allocated to x
to the OpenVMS system routine.
LIB$FLT_UNDER (%REF(1))
ONE: .LONG 1 ; Longword value 1 . . . PUSHAL ONE ; Push address of longword CALLS #1,G^LIB$FLT_UNDER ; Call LIB$FLT_UNDER
/* This program shows how to call system service SYS$READEF. */ #include <ssdef.h> #include <stdio.h> #include <starlet.h> /* Declare the function */ main(void) { /* Longword that receives the status * * of the event flag cluster */ unsigned cluster_status; int return_status; /* Status: SYS$READEF */ /* Argument values for SYS$READEF */ enum cluster0 { completion, breakdown, beginning } event; . . . event = completion; /* Event flag in cluster 0 */ /* Obtain status of cluster 0. * * Pass value of event and * * address of cluster_status. */ return_status = SYS$READEF(event, &cluster_status); /* Check for successful call */ if (return_status != SS$WASCLR && return_status != SS$WASSSET) { /* Handle the error here. */ . . . } else { /* Check bits of interest in cluster_status here. */ . . . } }
2.5.3. Passing Arguments by Descriptor
When a procedure specifies that an argument is passed by descriptor, the argument list entry must contain the address of a descriptor for the argument. For more information about OpenVMS Alpha 64-bit descriptors, refer to VSI OpenVMS Programming Concepts Manual, Volume I.
On Alpha and I64 processors, the address is sign-extended from 32 bits to 64 bits.
Symbol |
Description |
---|---|
DSC$W_LENGTH |
Length of data (or DSC$W_MAXSTRLEN, maximum length, for varying strings) |
DSC$B_DTYPE |
Data type |
DSC$B_CLASS |
Descriptor class code |
DSC$A_POINTER |
Address at which the data begins |
The VSI OpenVMS Calling Standard describes these fields in greater detail.
100 COMMON STRING GREETING = 30
200 CALL LIB$PUT_SCREEN(GREETING)
CALL LIB$PUT_OUTPUT USING BY DESCRIPTOR GREETING
MSGDSC: .WORD LEN ; DESCRIPTOR: DSC$W_LENGTH .BYTE DSC$K_DTYPE_T ; DSC$B_DTYPE .BYTE DSC$K_CLASS_S ; DSC$B_CLASS .ADDRESS MSG ; DSC$A_POINTER MSG: .ASCII/Hello/ ; String itself LEN = .-MSG ; Define the length of the string .ENTRY EX1,^M<> PUSHAQ MSGDSC ; Push address of descriptor CALLS #1,G^LIB$PUT_OUTPUT ; Output the string RET .END EX1
MODULE BLISS1 (MAIN = BLISS1, ! Example of calling LIB$PUT_OUTPUT IDENT = '1-001', ADDRESSING_MODE(EXTERNAL = GENERAL)) = BEGIN EXTERNAL ROUTINE LIB$STOP, ! Stop execution via signaling LIB$PUT_OUTPUT; ! Put a line to SYS$OUTPUT FORWARD ROUTINE BLISS1 : NOVALUE; LIBRARY 'SYS$LIBRARY:STARLET.L32'; ROUTINE BLISS1 ! Routine : NOVALUE = BEGIN !+ ! Allocate the necessary local storage. !- LOCAL STATUS, ! Return status MSG_DESC : BLOCK [8, BYTE]; ! Message descriptor BIND MSG = UPLIT('HELLO'); !+ ! Initialize the string descriptor. !- MSG_DESC [DSC$B_CLASS] = DSC$K_CLASS_S; MSG_DESC [DSC$B_DTYPE] = DSC$K_DTYPE_T; MSG_DESC [DSC$W_LENGTH] = 5; MSG_DESC [DSC$A_POINTER] = MSG; !+ ! Put out the string. Test the return status. ! If it is not a success, then signal the RMS error. !- STATUS = LIB$PUT_OUTPUT(MSG_DESC); IF NOT .STATUS THEN LIB$STOP(.STATUS); END; ! End of routine BLISS1 END ! End of module BLISS1 ELUDOM
/* This program shows a call to system service SYS$SETPRN. */ #include <ssdef.h> #include <stdio.h> /* Define structures for descriptors */ #include <descrip.h> #include starlet.h /* Declare the function */ int main(void) { int ret; /* Define return status of SYS$SETPRN */ struct dsc$descriptor_s name_desc; /* Name the descriptor */ char *name = "NEWPROC"; /* Define new process name */ . . . name_desc.dsc$w_length = strlen(name); /* Length of name without * * null terminator */ name_desc.dsc$a_pointer = name; /* Put address of shortened string * * in descriptor */ name_desc.dsc$b_class = DSC$K_CLASS_S; /* String descriptor class */ name_desc.dsc$b_dtype = DSC$K_DTYPE_T; /* Data type: ASCII string */ . . . ret = sys$setprn(&name_desc); if (ret != SS$_NORMAL) /* Test return status */ fprintf(stderr, "Failed to set process name\n"), exit(ret); . . . }
2.5.4. Passing Scalars as Arguments
When you are passing an input scalar value to an OpenVMS system routine, you usually pass it either by reference or by value. You usually pass output scalar arguments by reference to OpenVMS system routines. An output scalar argument is the address of a location where some scalar output of the routine will be stored.
2.5.5. Passing Arrays as Arguments
Arrays are passed to OpenVMS system routines by reference or by descriptor.
Sometimes the routine knows the length and dimensions of the array to be received, as in the case of the table passed to LIB$CRC_TABLE. Arrays such as this are normally passed by reference.
In other cases, the routine actually analyzes and operates on the input array. The routine does not necessarily know the length or dimensions of such an input array, so a descriptor is necessary to provide the information the routine needs to describe the array accurately.
2.5.6. Passing Strings as Arguments
Descriptor Function |
Descriptor Class Code |
Numeric Value |
---|---|---|
Fixed length (string/scalar) |
DSC$K_CLASS_S |
1 |
Dynamic |
DSC$K_CLASS_D |
2 |
Array |
DSC$K_CLASS_A |
4 |
Scaled decimal |
DSC$K_CLASS_SD |
9 |
Noncontiguous array |
DSC$K_CLASS_NCA |
10 |
Varying length |
DSC$K_CLASS_VS |
11 |
Fixed length — Characterized by an address and a constant length
Varying length — Characterized by an address, a current length, and a maximum length
Dynamic — Characterized by a current address and a current length
2.6. Combinations of Descriptor Class and Data Type
Some combinations of descriptor class and data type are not permitted, either because they are not meaningful or because the calling standard does not recognize them. Possibly, the same function can be performed with more than one combination. This section describes the restrictions on the combinations of descriptor classes and data types. These restrictions help to keep procedure interfaces simple by allowing a procedure to accept a limited set of argument formats without sacrificing functional flexibility.
The tables in Figures 2.16, 2.17, and 2.18 show all possible combinations of descriptor classes and data types. For example, Figure 2.16, “Atomic Data Types and Descriptor Classes” shows that your program can pass an argument to an OpenVMS system routine whose descriptor class is DSC$K_CLASS_A (array descriptor) and whose data type is unsigned byte (DSC$K_DTYPE_BU). The calling standard does not permit your program to pass an argument whose descriptor class is DSC$K_CLASS_D (dynamic string) and whose data type is unsigned byte.
A descriptor with data type DSC$K_DTYPE_DSC (24) points to a descriptor that has class DSC$K_CLASS_D (2) and data type DSC$K_DTYPE_T (14). All other class and data type combinations in the target descriptor are reserved for future definition in the standard.
The scale factor for DSC$K_CLASS_SD is always a decimal data type. It does not vary with the data type of the data described by the descriptor.
For DSC$K_CLASS_UBS and DSC$K_CLASS_UBA, the length field specifies the length of the data field in bits. For example, if the data type is unsigned word (DSC$K_DTYPE_WU), DSC$W_LENGTH equals 16.



2.7. Function Value Return
A function is a routine that returns a single value to the calling routine. The function value represents the value of the expression in the return statement. As specified by the calling standard, a function value may be returned as an actual value in R0.
2.7.1. Return Values on OpenVMS VAX
On OpenVMS VAX systems, if the actual function value returned is greater than 32 bits, then both R0 and R1 should be used.
2.7.2. Return Values on OpenVMS Alpha
On OpenVMS Alpha systems, if the actual function returned is a floating-point value, the floating-point value is returned either in F0 or in both F0 and F1.
Immediate value
Reference
Descriptor
These mechanisms are the standard return convention because they support the language-independent data types. For information about condition values returned in R0, see Section 2.8, “Condition Value Return”.
2.7.3. Return Values on OpenVMS I64
On OpenVMS I64 systems, values up to 128 bits are returned directly in the registers, according to the rules in Table 2.31, “Rules for Return Values”.
Integer, enumeration, record, and set values (bit vectors) smaller than 64 bits must be zero-filled (unsigned integers, enumerations, records, sets) or sign-extended (signed integrals) to a full 64 bits. However, for unsigned 32-bit integers, bit 31 is replicated in bits 32—63.
When floating-point values are returned in floating-point registers, they are returned in the register format, rounded to the appropriate precision. When they are returned in the general registers (for example, as part of a record), they are returned in their memory format.
Type |
Size (Bits) |
Location of Return Value |
Alignment |
---|---|---|---|
Integer/Pointer, small Record, Set |
1—64 |
R8 |
LSB |
IEEE single-precision floating-point (S_floating) |
32 |
F8 |
N/A |
IEEE double-precision floating-point (T_floating) |
64 |
F8 |
N/A |
IEEE single-precision complex (S_floating) |
64 |
F8, F9 |
N/A |
IEEE double-precision complex (T_floating) |
128 |
F8, F9 |
N/A |
VAX single-precision floating-point (F_floating) |
32 |
R8 |
N/A |
VAX double-precision floating-point (D_ and G_floating) |
64 |
R8 |
N/A |
VAX single-precision floating-point complex (F_floating) |
64 |
R8, R9 |
N/A |
VAX double-precision floating-point complex (D_ and G_floating) |
128 |
R8, R9 |
N/A |
Note
X_floating and X_floating complex are not included in this table because they are returned using he hidden parameter method.
The rules in Table 2.31, “Rules for Return Values” are expressed in more detail in Table 2.17, “Unused Bits in Passed Data”. F_floating and F_floating complex values in the general registers are zero-extended (Zero64), because this most closely approximates the effect of using the Alpha register format.
Hidden Parameter
Return values other than those covered by Table 2.31, “Rules for Return Values” are returned in a buffer allocated by the caller. A pointer to the buffer is passed to the called procedure as a hidden first parameter, and all normal parameters are shifted one slot to make this possible. The return buffer must be aligned at a 16-byte boundary.
2.7.4. Return Values on OpenVMS x86-64
If the class is MEMORY, then the caller provides the space for the return value and passes the address of this storage in
%rdi
as if it were the first argument to the function. In effect, this address becomes a hidden first argument. This storage must not overlap any data visible to the callee through the other parameters in this argument list.On return
%rax
will contain the address that was passed in%rdi
by the caller.If the class is INTEGER, the next available register of the sequence
%rax
,%rdx
is used.If the class is SSE, the next available floating-point register of the sequence
%xmm0
,%xmm1
is used.If the class is SSEUP, the quadword is returned in the next available 8-byte chunk of the last used floating-point register.
If the class is X87, the value is returned on the X87 stack in
%st0
as an 80-bit x87 number.If the class is X87UP, the value is returned together with the previous X87 value in
%st0
.If the class is COMPLEX_X87, the real part of the value is returned in
%st0
and the imaginary part in%st1
.
As a result scalar values and complex floating-point values are returned in
registers %rax
, %rax
and
%rdi
, %mm0
, or %mm0
and
%mm1
. The exception is an IEEE complex quadruple precision
value which is returned in a caller-provided temporary location.
2.8. Condition Value Return
An OpenVMS system routine can indicate success or failure to the calling program by returning a condition value. In addition, an error condition to the calling program can return as a condition value in R0 (R8, R9 for I64) or by error signaling.
A condition value in R0 (R8, R9 for I64), also called a return status or completion code, is either a success (bit 0 = 1) value or an error condition (bit 0 = 0) value. In an error condition value, the low-order 3 bits specify the severity of the error (see Figure 2.19, “Format of a Condition Value”). Bits <27:16> contain the facility number, and bits <15:3> indicate the particular condition. Bits <31:28> are the control field. When the called procedure returns a condition value, the calling program can test R0 and choose a recovery path. A general guideline to follow when testing for success or failure is that all success codes have odd values and all error codes have even values.

When the completion code is signaled, the calling program must establish a handler to get control and take appropriate action. (See VSI OpenVMS Programming Concepts Manual, Volume I or the VSI OpenVMS Calling Standard for a description of signaling and condition handling and for more information about the condition value).
2.9. MACRO Compiler Register Mapping
2.9.1. MACRO Register Usage and Mapping for I64
Because the I64 calling standard diverges from the Alpha and VAX calling standards regarding the use of registers and register mapping, and because MACRO-32 assumes that registers are preserved across calls, the MACRO compiler maps registers to allow existing code to compile unmodified.
If you use OpenVMS high-level languages, the register and register mapping differences in the calling standards are handled by the compilers and are not exposed to your code. However, if your code uses MACRO-32, C #pragmalinkages, or BLISS linkages, your code might have to take into account the differences in register mapping.
This section describes I64 register usage and mapping.
2.9.1.1. I64 Register Usage Compared with Alpha and VAX
OpenVMS I64 systems employ 32 integer registers, R0 through R31, with R0 being a read-only register that contains 0. This is different from OpenVMS Alpha, where R31 is a read-write register that contains 0.
In addition, the I64 calling standard has been written to be highly compatible with the Intel calling standard, and is quite different from the OpenVMS Alpha calling standard. For example, the standard return registers on I64 are R8/R9, not R0/R1 as on Alpha. The I64 calling standard reserves R1 as the GP (global pointer), does not include a standardized FP (frame pointer), and only has R4 through R7 as preserved across calls, not R2 through R15 as on Alpha.
Registers 2 through 11 are preserved on OpenVMS VAX
Registers 2 through 15 are preserved on OpenVMS Alpha
Registers 4 through 7 are preserved on OpenVMS I64
I64 has more “volatile” registers
I64 returns values in R8/R9 instead of R0/R1
R0 is read only in I64
I64 reserves R1 as the GP (global pointer)
I64 does not include a standardized FP (frame pointer)
Arguments are also passed in stacked registers in I64. R32—R39 are used as incoming argument registers.
2.9.1.1.1. I64 Register Mapping in MACRO Compiler
The OpenVMS MACRO compiler compiles MACRO-32 source code written for OpenVMS VAX systems (the VAX MACRO assembler) into machine code that runs on OpenVMS Alpha and OpenVMS I64 systems. Because MACRO-32 source code is written with the VAX and Alpha calling standards in mind, the compiler performs several transformations to allow existing code to compile unmodified with the I64 compiler.
OpenVMS VAX/OpenVMS Alpha Register in Source Code |
OpenVMS I64 Register Used in Generated Code |
---|---|
R0 |
R8 |
R1 |
R9 |
R2 |
R28 |
R3 |
R3 |
R4 |
R4 |
R5 |
R5 |
R6 |
R6 |
R7 |
R7 |
R8 |
R26 |
R9 |
R27 |
R10 |
R10 |
R11 |
R11 |
R12 |
R30 |
R13 |
R31 |
R14 |
R20 |
R15 |
R21 |
R16 |
R14 |
R17 |
R15 |
R18 |
R16 |
R19 |
R17 |
R20 |
R18 |
R21 |
R19 |
R22 |
R22 |
R23 |
R23 |
R24 |
R24 |
R25 |
R25 |
R26 |
Itanium stacked register |
R27 |
Itanium stacked register |
R28 |
Itanium stacked register |
R29 |
R29 |
R30 |
R12 |
R31 |
R0 |
The register mapping was carefully chosen based on which registers were preserved across calls, which registers may be modified across calls, and which registers are volatile and do not even survive into or out of a call.
As on Alpha, MACRO-32 references to AP are mapped by the compiler to the appropriate location depending on whether the arguments have been saved to the stack. To support references to FP, the compiler creates an FP value where needed. The compiler supports references to 0 (FP) to establish condition handlers just like on VAX and Alpha.
The compiler does not provide any syntax for accessing I64 registers directly without going through the mapping table.
The automatic register mapping done by the compiler allows many MACRO-32 programs (including those that access Alpha registers R16—R31) to compile without modifications.
Note, however, that use of registers R16—R21 as routine parameters on Alpha is not portable to I64. Use PUSHL to pass parameters to a CALL, and use 4(AP), 8(AP), and so forth in the called routine to refer to them. The compiler will generate the correct register references instead of the stack references implied by the VAX operands.
On I64 systems, the compiler continues to recognize many of the EVAX_* built-ins that provide direct access to Alpha instructions on Alpha systems. These built-ins will generate one or more I64 instructions to perform the same logical operation. See the VSI OpenVMS MACRO Compiler Porting and User's Guide for a complete list of which EVAX_* built-ins are also supported on I64.
2.9.1.1.2. Use of MACRO Linkage Directives to Preserve Registers
For I64 systems, add linkage directives (.CALL_LINKAGE,.DEFINE_LINKAGE, or .USE_LINKAGE) to mark VAX CALLS or CALLG instructions that call routines that return values in registers other than R0 or R1, or to JSB to routines written in a language other than MACRO-32. These directives look similar to the .CALL_ENTRY directive and specify input, output, preserved, and scratch masks. In addition, they also have a language keyword to provide an alternative quick specification.
The .CALL_LINKAGE directive associates a named or anonymous linkage with a routine name. When the compiler sees a CALLS, CALLG, JSB, BSBB, or BSBW instruction with the routine name as the target, it will use the associated linkage to decide which registers need to be saved and restored around the call.
The .USE_LINKAGE directive establishes a temporary named or anonymous linkage that will be used by the compiler for the next CALLS, CALLG, JSB, BSBB, or BSBW instruction processed in lexical order. This directive is used when the target of the next CALLS, CALLG, JSB, BSBB, or BSBW instruction is not a name, but a run-time value (for example, CALLS #0, (R6)). When the compiler sees the next CALLS, CALLG, JSB, BSBB, or BSBW instruction, it will use the associated linkage to decide which registers need to be saved and restored around the call. After the instruction is processed, the temporary linkage is reset to null.
The .DEFINE_LINKAGE directive defines a named linkage that can be used with subsequent .CALL_LINKAGE or .USE_LINKAGE directives.
If your MACRO-32 code uses a CALLS or CALLG instruction to access routines that return values in registers other than R0 or R1, the contents of the saved and restored registers may not be what you expect. Existing MACRO-32 code traditionally assumes that registers R2—R11 and R15 are preserved and returned across calls. For CALLS and CALLG instructions, the MACRO compiler automatically saves and restores registers R2—R3 and R8—R15 in case the target of the call is not MACRO-32. However, this means that changes made to these registers by the routine call are undone. This can cause problems if the routine return values were in registers other than R0—R1.
M1.mar calls #3,g^body_scan M2.mar Body_scan: .call_entry preserve=<r6,r7,r8>, output=<r2,r3,r4,r5,r9>
.call_linkage rtn_name=body_scan preserve=<r6,r7,r8> - output=<r2,r3,r4,r5,r9>
For JSB instructions, the MACRO compiler assumes that the target is also MACRO-32 and does not save and restore anything. The compiler assumes that all registers flow in and out of the target routine. Alpha high-level language compilers would have preserved registers R2—R15. However, I64 high-level language compilers preserve only registers R4—R7.
.call_linkage rtn_name=body_scan preserve=<r6,r7,r8> - output=<r2,r3,r4,r5,r9>
M1.mar jsb search_path M2.bli linkage l = jsb(register=0) : global(wrk=10,prc=11) global routine search_path : l = begin . . . End;
.call_linkage rtn_name=search_path language=other - output=<r10,r11>
.use_linkage language=other jsb (r5)
See the VSI OpenVMS MACRO Compiler Porting and User's Guide for additional information.
2.9.2. MACRO Register Usage and Mapping for x86-64
2.9.3. High-Level Language Compiler Register Mapping
If you use OpenVMS high-level languages, the register and register mapping differences in the calling standards are handled by the compilers and are not exposed to your code. However, if your code uses C #pragma linkages or BLISS linkages to interface with MACRO-32 source code, your code might have to take into account the differences in register mapping.
BLISS added a new qualifier and source level switch to enable register mapping for
register numbers in linkage and register declarations. It is off by default. BLISS
also has additional support for linkages that reference arguments. The C compiler
changed the #pragma
linkage to map the registers by default,
along with additional support for linkages that reference arguments or floating
registers. There are new pragmas to get unmapped linkages.
See your compiler documentation for additional information.
Chapter 3. Calling Run-Time Library Routines
The OpenVMS Run-Time Library is a set of language-independent routines that establish a common run-time environment for user programs. The procedures ensure correct operation of complex language features and help enforce consistent operations on data across languages.
The VSI OpenVMS Calling Standard describes the mechanisms used by OpenVMS languages for invoking routines and passing data between them. In effect, this standard describes the interface between your program and the run-time library routines that your program calls. This chapter describes the basic methods for coding calls to run-time library routines from an OpenVMS common language.
3.1. Overview
When you call a run-time library routine from your program, you must furnish whatever arguments the routine requires. When the routine completes execution, in most cases it returns control to your program. If the routine returns a status code, your program should check the value of the code to determine whether or not the routine completed successfully. If the return status indicates an error, you may want to change the flow of execution of your program to handle the error before returning control to your program.
When you log in, the operating system creates a process that exists until you log out. When you run a program, the system activates an executable image in your process. This image consists of a set of user procedures.
From the run-time library's point of view, user procedures are procedures that exist outside the run-time library and that can call run-time library routines. When you write a program that calls a run-time library routine, the run-time library views your program as a user procedure. User procedures also can call other user procedures that are either supplied by VSI or written by you. Because an OpenVMS native-mode language compiler program exists outside the run-time library, compiler-generated programs that call any run-time library routine are also defined as a set of user procedures.
The main program, or main procedure, is the first user procedure that the system calls after calling a number of initialization procedures. A user program consists of the main program and all of the other user procedures that it calls.
Figure 3.1, “Calling the Run-Time Library” shows the calling relationships among a main program, other user procedures, library routines, and the operating system. In this figure, Call indicates that the calling procedures requested some information or action; Return indicates that the called procedure returned the information to the calling procedure or performed the action.

When a user procedure establishes its own condition handler. For example, LIB$SIGNAL operates by searching for and calling user procedures that have been established as condition handlers (see the VSI OpenVMS RTL Library (LIB$) Manual for more information).
When a user procedure passes to a routine the address of another procedure that the library will call later. For example, when your program calls LIB$SHOW_TIMER, you can pass the address of an action routine that LIB$SHOW_TIMER will call to process timing statistics.
3.2. Call Instructions
CALL — Call procedure from a high-level language
CALLS — Call procedure with stack argument list instruction (VAX MACRO)
CALLG — Call procedure with general argument list instruction (VAX MACRO)
JSB — Jump to subroutine instruction (for VAX systems only)
JSR — Jump to subroutine instruction (MACRO-64)
High-level languages do not differentiate between CALLS and CALLG. They use a CALL statement or a function reference to invoke a run-time library routine.
VAX MACRO does not differentiate between functions and subroutines in its CALLS and CALLG instructions.
Only VAX MACRO and BLISS programs on VAX systems can explicitly access the JSB entry points that are provided for some routines in the run-time library. You cannot write a program to access the JSB entry points directly from a high-level language.
3.2.1. Facility Prefix and Routine Name
fac$symbol
|
A 2- or 3-character facility name |
|
A 1- to 27-character symbol |
The facility names are maintained in a systemwide registry. A unique, 12-bit facility number is assigned to each facility name for use in (1) condition value symbols, and (2) condition values in procedure return status codes, signaled conditions, and messages. The high-order bit of this number is 0 for facilities assigned by VSI and 1 for those assigned by Application Project Services (APS) and customers. For further information, refer to the VSI OpenVMS Calling Standard.
CVT$ |
Convert routines |
DTK$ |
DECtalk routines |
LIB$ |
Library routines |
MTH$ |
Mathematics routines |
OTS$ |
General-purpose routines |
PPL$ |
Parallel processing routines |
SMG$ |
Screen management routines |
STR$ |
String-handling routines |
3.2.2. The RTL Call Entry
Arguments passed to a routine must be listed in your call entry in the order shown in the format section of the routine description. Each argument has four characteristics: OpenVMS usage, data type, access type, and passing mechanism. These characteristics are described in Chapter 1, Call Format to OpenVMS Routines.
Some arguments are optional. Optional arguments are indicated by brackets in the routine descriptions. When your program invokes a run-time library routine using a CALL entry point, you can omit optional arguments at the end of the argument list. If the optional argument is not the last argument in the list, you must either pass a zero by value or use a comma to indicate the place of the omitted argument. Some languages, such as C, require that you pass zero by value for trailing optional arguments. See your language processor documentation for further information.
On VAX systems, the calling program passes an argument list of longwords to a called routine; each longword in the argument list specifies a single argument. Note that a 64-bit floating-point argument would count as 2 longword arguments in the list.
On Alpha systems, the calling program passes arguments in an argument item sequence; each quadword in the sequence specifies a single argument item. Note that the argument item sequence is formed using R16–21 or F16–21 (a register for each argument). The argument item sequence can have a mix of integer and floating-point items that use both register types but must not repeat the same number.
For I64, parameters are passed in a combination of general registers, floating-point registers, and memory, as illustrated in Figure 2.12, “Parameter Passing in Registers and Memory”.The first eight parameters are passed in R32 through R39, with the parameter count in R25 and subsequent parameters in quadwords on the stack.
In the Alpha, VAX, and I64 environments, the called routine interprets each argument using one of three standard passing mechanisms: by value, by reference, or by descriptor. For more information on arguments, see Section 2.4, “Argument List” and Section 2.5, “Argument Passing Mechanisms”.
LIB$GET_INPUT get-str [,prompt-str] [,out-len]
INTEGER*4 STAT . . . STAT = LIB$GET_INPUT (GET_STR,PROMPT,LENGTH) STAT = LIB$GET_INPUT (GET_STR,PROMPT) STAT = LIB$GET_INPUT (GET_STR,PROMPT,) STAT = LIB$GET_INPUT (GET_STR,,LENGTH) STAT = LIB$GET_INPUT (GET_STR) STAT = LIB$GET_INPUT (GET_STR,) STAT = LIB$GET_INPUT (GET_STR,%VAL(0))
The following examples illustrate the standard mechanism for calling an external procedure, subroutine, or function in most high-level languages.
BASIC
CALL LIB$MOVTC(SRC, FILL, TABLE, DEST) STATUS = LIB$GET_INPUT(STRING, 'NAME:')
BLISS
LOCAL MSG_DESC : BLOCK [8,BYTE]; MSG_DESC [DSC$B_CLASS] = DSC$K_CLASS_S; MSG_DESC [DSC$B_DTYPE] = DSC$K_DTYPE_T; MSG_DESC [DSC$W_LENGTH] = 5; MSG_DESC [DSC$A_POINTER] = MSG; STATUS = LIB$PUT_OUTPUT(MSG_DESC);
C
#include <lib$routines.h> #include <descrip.h> $DESCRIPTOR(name, "Name:"); struct dsc$descriptor_s string: . . . status = lib$get_input(&string, &name);
COBOL
CALL LIB$MOVTC USING BY DESCRIPTOR
SRC,
FILL,
TABLE,
DEST,
GIVING RET-STATUS.
FORTRAN
CALL LIB$MOVTC(SRC, FILL, TABLE, DEST) STATUS = LIB$GET_INPUT(STRING, 'NAME:')
Pascal
RET_STATUS := LIB$MOVTC (SRC, FILL, TABLE, DEST);
PL/I
CALL LIB$MOVTC(SRC, FILL, TABLE, DEST); STATUS = LIB$GET_INPUT(STRING, 'NAME:');
VAX MACRO
CALLS #2,G^LIB$GET_INPUT CALLG ARGLIST, G^LIB$GET_VM JSB G^MTH$SIN_R4
As these examples show, high-level languages use different forms of the call statement. Each language's user guide gives specific information about calling the run-time library from that language.
3.2.2.1. JSB Call Entries (VAX Only)
On VAX systems, JSB entry point names follow the naming conventions explained in Section 3.2.1, “Facility Prefix and Routine Name”, except that they include a suffix indicating the number of the highest register accessed or modified. This suffix helps ensure that the calling program and the called routine agree on the number of registers that the called routine is going to change.
JSB G^MTH$SIN_R4 ;F_floating sine uses R0 through R4
JSB entry points are available only to VAX MACRO and VAX BLISS programs. No VAX high-level language provides a mechanism for accessing JSB entry points.
3.2.3. Returns from an RTL Routine
On VAX systems, some run-time library routines return a function value. Typically on a VAX system, the return is in the form of a 32-bit value in register R0 or a 64-bit value in registers R0 and R1. In high-level languages, statuses or function return values in R0 appear as the function result. When a routine returns a function value in R0, it cannot also use R1 to return a status code. Therefore, such a procedure signals errors rather than returning a status. For more information, refer to the VSI OpenVMS Calling Standard or the description of LIB$SIGNAL in the VSI OpenVMS RTL Library (LIB$) Manual.
On Alpha systems, a standard function returns its function value in R0, F0, or F0 and F1. A function value of less than 64 bits returned by immediate value in R0 is zero-extended or sign-extended to a full quadword as required by the data type. Note that a floating function value is returned by immediate value in F0 or in F0 and F1.
For I64, values up to 128 bits are returned directly in the registers (R8, R9 or F8, F9), according to the rules in Table 2.31, “Rules for Return Values”. Integer, enumeration, record, and set values (bit vectors) smaller than 64 bits must be zero-filled (unsigned integers, enumerations, records, sets) or sign-extended (signed integrals) to a full 64 bits. However, for unsigned 32-bit integers, bit 31 is replicated in bits 32-63.
When floating-point values are returned in floating-point registers, they are returned in the register format, rounded to the appropriate precision. When they are returned in the general registers (for example, as part of a record), they are returned in their memory format.
3.2.3.1. Facility Return Status and Condition Value Symbols
fac$_abcmnoxyz
|
The 2- or 3-letter facility symbol |
|
The first 3 letters of the first word of the associated message |
|
The first 3 letters of the next word |
|
The first 3 letters of the third word, if any |
SS$_NORMAL |
Routine successfully completed |
LIB$_INSVIRMEM |
Insufficient virtual memory |
MTH$_FLOOVEMAT |
Floating overflow in mathematics library procedure |
OTS$_FATINTERR |
Fatal internal error in a language-independent support procedure |
LIB$_SCRBUFOVF |
Screen buffer overflow |
3.3. Calling a Library Procedure in VAX MACRO (VAX Only)
This section describes how to code MACRO calls to library routines using a CALLS, CALLG, or JSB instruction for VAX systems. The routine descriptions that appear later in this manual describe the entry points for each routine. You can use either a CALLS or a CALLG instruction to invoke a procedure with a CALL entry point. You must use a JSB instruction to invoke a procedure with a JSB entry point. All MACRO calls are explicitly defined.
3.3.1. VAX MACRO Calling Sequence
All run-time library routines have a CALL entry point. Some routines also have a JSB entry point. In MACRO, you invoke a CALL entry point with a CALLS or CALLG instruction. To access a JSB entry point, use a JSB instruction.
For CALLS, the calling procedure pushes the argument list onto the stack (in reverse order) before performing the call. The list is automatically removed from the stack upon return.
For CALLG, the calling program specifies the address of the argument list, which can be anywhere in memory. This list remains in memory upon return.
Both of these instructions have the same effect on the called procedure.
JSB instructions execute faster than CALL instructions. They do not set up a new stack frame, do not change the enabling of hardware traps or faults, and do not preserve the contents of any registers before modifying them. For these reasons, you must be careful when invoking a JSB entry point in order to prevent the loss of information stored by the calling program.
Whichever type of call you use, the actual reference to the procedure entry point should use general-mode addressing (G^). This ensures that the linker and the image activator are able to locate the module within the shareable image.
In most cases, you have to tell a library routine where to find input values and store output values. You must select a data type for each argument when you code your program. Most routines accept and return 32-bit arguments.
For input arguments of byte, word, or longword values, you can supply a constant value, a variable name, or an expression in the run-time library routine call. If you supply a variable name for the argument, the data type of the variable must be as large as or larger than the data types that the called procedure requires. For example, if the called procedure expects a byte in the range 0 to 100, you can use a variable data type of a byte, word, or longword with a value between 0 and 100.
For each output argument, you must declare a variable of exactly the length required to avoid extraneous data. For example, if the called procedure returns a byte value to a word-length variable, the leftmost 8 bits of the variable <15:8> are not overwritten on output. Conversely, if a procedure returns a longword value to a word-length variable, it modifies variables in the next higher word.
3.3.2. VAX MACRO CALLS Instruction Example
.PSECT DATA PIC,USR,CON,REL,GBL,NOSHR,NOEXE,RD,WRT,NOVEC MEM: .LONG 0 ; Longword to hold address of ; allocated memory LEN: .LONG 700 ; Number of bytes to allocate .PSECT CODE PIC,USR,CON,REL,GBL,SHR,EXE,RD,NOWRT,NOVEC .ENTRY PROG, ^M<> PUSHAL MEM ; Push address of longword ; to receive address of block PUSHAL LEN ; Push address of longword ; containing number of bytes ; desired CALLS #2, G^LIB$GET_VM ; Allocate memory BLBC R0, 1$ ; Branch if memory not available RET 1$: PUSHL R0 ; Signal the error CALLS #1, G^LIB$SIGNAL RET .END PROG
Because the stack grows toward location 0, arguments are pushed onto
the stack in reverse order from the order shown in the general
format for the routine. Thus, the
base-address
argument, here called
START, is pushed first, and then the
number-bytes
argument, called LEN.
Upon return from LIB$GET_VM, the calling
program tests the return status (ret-status
),
which is returned in R0 and branches to an appropriate error routine
if an error occurred.
3.3.3. VAX MACRO CALLG Instruction Example
ARGLST:
.LONG 2 ; Argument list count
.ADDRESS LEN ; Address of longword containing
; the number of bytes to allocate.
.ADDRESS START ; Address of longword to receive
; the starting address of the
; virtual memory allocated.
LEN: .LONG 20 ; Number of bytes to allocate
START: .BLKL 1 ; Starting address of the virtual
; memory.
CALLG ARGLIST, G^LIB$GET_VM ; Get virtual memory
BLBC R0, ERROR ; Check for error
BRB 10$
3.3.4. VAX MACRO JSB Entry Points
A procedure's JSB entry point name indicates the highest numbered register that the procedure modifies. Thus, a procedure with a suffix Rn modifies registers R0 through Rn. (You should always assume that R0 and R1 are modified). The calling program loads the arguments in the registers before the JSB instruction is executed.
NUM: .FLOAT 0.7853981 ; Constant P1/4
MOVF NUM, R0 ; Set up input argument
JSB G^MTH$SIN_R4 ; Call F_floating sine procedure
; Return with value in R0
In this example, R4 in the entry point name indicates that MTH$SIN_R4 changes the contents of registers R0 through R4. The routine does not reference or change the contents of registers R5 through R11.
The entry mask of a calling procedure should specify all the registers to be saved if the procedure invokes a JSB routine. This step is necessary because a JSB procedure does not have an entry mask and thus has no way to specify registers to be saved or restored.
Procedure B modifies the contents of R2 through R6, so the contents of these registers are preserved at the time of the call.
Procedure B then invokes procedure C by means of a JSB entry point.
Procedure C modifies registers R0 through R7.
When control returns to procedure B, R7 has been modified, but when procedure B passes control back to procedure A, it restores only R2 through R6. Thus, the contents of R7 are unpredictable, and program A does not execute as expected. Procedure B should be rewritten so that R2 through R7 are saved in procedure B's entry mask.
.ENTRY PROC, ^M <R2, R3, R4, R5> ; Save R2:R5 MOVF @4(AP), R0 ; R0 = A JSB G^MTH$SIN_R4 ; R0 = SIN(A) MOVF R0 , R5 ; Copy result to register ; not modified by MTH$SIN MOVF @8(AP) , R0 ; R0 = B JSB G^MTH$SIN_R4 ; R0 = SIN(B) MULF R5 , R0 ; R0 = SIN(A)SIN(B) RET ; Return
3.3.5. Return Status
Your VAX MACRO program can test for errors by examining segments of the 32-bit status code returned by a run-time library routine.
To test for errors, check for a zero in bit 0 using a Branch on Low Bit Set (BLBS) or Branch on Low Bit Clear (BLBC) instruction.
To test for a particular condition value, compare the 32 bits of the return status with the appropriate return status symbol using a Compare Long (CMPL) instruction or the run-time library routine LIB$MATCH_COND.
Using the .EXTRN symbol directive. This causes the assembler to generate an external symbol declaration.
Using the $
fac
DEF macro call. Calling the $LIBDEF macro, for example, causes the assembler to define all LIB$ condition values.By default. The assembler automatically declares the condition value as an external symbol that is defined as a global symbol in the run-time library.
$SSDEF ; Define SS$ symbols $DSCDEF ; Define DSC$ symbols .PSECT $DATA PROMPT_D: ; Descriptor for prompt .WORD PROMPT_LEN ; Length field .BYTE DSC$K_DTYPE_T ; Type field is text .BYTE DSC$K_CLASS_S ; Class field is string .ADDRESS PROMPT ; Address PROMPT: .ASCII /NAME: / ; String descriptor PROMPT_LEN = . - PROMPT ; Calculate length of ; string STR_LEN = 30 ; Use 30-byte string STRING_D: ; Input string descriptor .WORD STR_LEN ; Length field .BYTE DSC$K_DTYPE_T ; Type field in text .BYTE DSC$K_CLASS_S ; Class field is string .ADDRESS STR_AREA ; Address STR_AREA: .BLKB STR_LEN ; Area to receive string .PSECT $CODE .ENTRY START , ^M<> PUSHAQ PROMPT_D ; Push address of prompt ; descriptor PUSHAQ STRING_D ; Push address of string ; descriptor CALLS #2 , G^LIB$GET_INPUT ; Get input string BLBS R0 , 10$ ; Check for success CMPL R0 , #LIB$_INPSTRTRU ; Error: Was it ; truncated string? BEQL 10$ ; No, more serious error PUSHL R0 CALLS #1 , G^LIB$SIGNAL 10$: MOVL #SS$_NORMAL , R0 ; Success, or name too ; long RET .END START
3.3.6. Function Return Values in VAX MACRO (VAX and Alpha)
Function values are generally returned in R0 (32-bit values) or R0 and R1 (64-bit values). A MACRO program can access a function value by referencing R0 or R0 and R1 directly. For functions that return a string, the address of the string or the address of its descriptor is returned in R0. If a function needs to return a value larger than 64 bits, it must return the value by using an output argument.
JSB entry points in the MTH$ facility return H_floating values in R0 through R3.
- One routine, MTH$SINCOS, returns two function values: the sine and the cosine of an angle. Depending on the data type of the function values, the function values are returned in the following registers:
F_floating
R0 and R1
D_floating
R0 through R3
G_floating
R0 through R3
H_floating
R0 through R7
As in the case of output arguments, a variable declared to receive the function values must be the same length as the value.
3.4. Calling a Library Routine in BLISS
No value.
A function value (typically, an integer or floating point number). For example, MTH$SIN returns its result as an F_floating value in R0 on VAX systems, in F0 on Alpha systems, or in R8 on I64 systems.
On Alpha processors, BLISS cannot access floating point registers. Direct use of the I64 floating-point registers is not supported.
A return status (typically, a 32-bit condition value) indicating that the routine has either executed successfully or failed. For example, LIB$GET_INPUT returns a return status in R0 (R8, R9 for I64). If the routine executes successfully, it returns SS$_NORMAL; if not, it returns one of several possible error condition values. BLISS treats the return status like any other value.
3.4.1. BLISS Calling Sequence
Scalar arguments are usually passed to run-time library routines by reference. Thus, when a BLISS program passes a variable, the variable appears with no preceding period in the procedure-call actual argument list. A constant value can be easily passed by using the %REF built-in function.
MODULE SHOWTIME(IDENT='1-1' %TITLE'Print time', MAIN=TIMEOUT)= BEGIN LIBRARY 'SYS$LIBRARY:STARLET'; ! Defines system services, etc. MACRO DESC[]=%CHARCOUNT(%REMAINING), ! VAX string descriptor UPLIT BYTE(%REMAINING) %; ! definition BIND FMTDESC=UPLIT( DESC('At the tone, the time will be ', %CHAR(7), '!%T' )); EXTERNAL ROUTINE LIB$PUT_OUTPUT: ADDRESSING_MODE(GENERAL); ROUTINE TIMEOUT = BEGIN LOCAL TIMEBUF: VECTOR[2], ! 64-bit system time MSGBUF: VECTOR[80,BYTE], ! Output message buffer MSGDESC: BLOCK[8,BYTE], ! Descriptor for message buffer RSLT: WORD; ! Length of result string !+ ! Initialize the fields of the string descriptor. !- MSGDESC[DSC$B_CLASS]=DSC$K_CLASS_S; MSGDESC[DSC$B_DTYPE]=DSC$K_DTYPE_T; MSGDESC[DSC$W_LENGTH]=80; MSGDESC[DSC$A_POINTER]=MSGBUF[0] $GETTIM(TIMADR=TIMEBUF); ! Get time as 64-bit integer $FAOL(CTRSTR=FMTDESC, ! Format descriptor OUTLEN=RSLT, ! Output length (only a word!) OUTBUF=MSGDESC, ! Output buffer desc. PRMLST= %REF(TIMEBUF)); ! Address of 64-bit ! time block MSGDESC [DSC$W_LENGTH] = .RSLT; ! Modify output desc. RETURN (LIB$PUT_OUTPUT(MSGDESC); ! Return status END; END ELUDOM
3.4.2. Accessing a Return Status in BLISS
STATUS = LIB$PUT_OUTPUT(MSG_DESC); IF NOT .STATUS THEN LIB$STOP(.STATUS);
3.4.3. Calling JSB Entry Points from BLISS
Note
I64 register usage differs from that of Alpha and VAX. If you use OpenVMS high-level languages, the register and register mapping differences in the calling standards are handled by the compilers and are not exposed to your code. However, if your code uses BLISS linkages to interface with MACRO-32 source code, your code might have to take into account the differences in register mapping.
BLISS added a new qualifier and source level switch to enable register mapping for register numbers in linkage and register declarations. It is off by default. BLISS also has additional support for linkages that reference arguments.
See your compiler documentation for additional information.
MODULE JSB_LINK (MAIN = MATH_JSB, ! Example of using JSB linkage IDENT = '1-001', ADDRESSING_MODE(EXTERNAL = GENERAL)) = BEGIN LINKAGE LINK_MATH_R4 = JSB (REGISTER = 0; ! input reg REGISTER = 0): ! output reg NOPRESERVE (0,1,2,3,4) NOTUSED (5,6,7,8,9,10,11); EXTERNAL ROUTINE MTH$SIND_R4 : LINK_MATH_R4; FORWARD ROUTINE MATH_JSB; LIBRARY 'SYS$LIBRARY:STARLET.L32'; ROUTINE MATH_JSB = ! Routine BEGIN LOCAL INPUT_VALUE : INITIAL (%E'30.0'), SIN_VALUE; !+ ! Get the sine of single floating 30 degrees. The input, 30 degrees, ! is passed in R0, and the answer, is returned in R0. Registers ! 0 to 4 are modified by MTH$SIND_R4. !- MTH$SIND_R4 (.INPUT_VALUE ; SIN_VALUE); RETURN SS$_NORMAL; END; ! End of routine END ! End of module JSB_LINK ELUDOM
Chapter 4. Calling System Services
The OpenVMS operating system kernel has many services that are made available to application and system programs for use at run time. These system services are procedures that the OpenVMS operating system uses to control resources available to processes; to provide for communication among processes; and to perform basic operating system functions, such as the coordination of input/output operations.
This chapter describes the basic methods and conventions for coding calls to system services from OpenVMS high-level languages or from an assembly language.
For more information about using the system services that support 64-bit addressing and to see example programs that demonstrate the use of these services, refer to VSI OpenVMS Programming Concepts Manual, Volume I.
4.1. Overview
System services are called by using the conventions of the VSI OpenVMS Calling Standard. The programming languages that generate VAX, Alpha, or I64 native mode instructions provide mechanisms for specifying the procedure calls.
When you call a system service from your program, you must furnish whatever arguments the routine requires. When the system service procedure completes execution, in most cases it returns control to your program. If the service returns a status code, your program should check the value of the code to determine whether or not the service completed successfully. If the return status indicates an error, you may want to change the flow of execution of your program to handle the error before returning control to your program.
When you write a program that calls a system service in the OpenVMS operating system, the operating system views your program as a user procedure. User procedures also can call other user procedures that are either supplied by VSI or written by you. Because an OpenVMS native-mode language compiler program exists outside the operating system, compiler generated programs calling any system service are also defined as a set of user procedures.
If you program in a high-level language, refer to Chapter 5, STARLET Structures and Definitions for C Programmers for information about the SYS$LIBRARY:SYS$LIB_C.TLB file, which is an OpenVMS Alpha and OpenVMS I64 library of C header files.
For VAX MACRO, system service macros generate argument lists and CALL instructions to call system services. These macros are located in the system library (see SYS$LIBRARY:STARLET.MLB). When you assemble a source program, this library is searched automatically for unresolved references. (See Appendix A, Generic Macros for Calling System Services for further details.) Similar macros are available for BLISS and are located in SYS$LIBRARY:STARLET.REQ.
4.2. Preserving System Integrity
As described in this document and the VSI OpenVMS System Services Reference Manual, many system services are available and suitable for application programs, but the use of some of these powerful services must be restricted to protect the performance of the system and the integrity of user processes.
For example, because the creation of permanent mailboxes uses system dynamic memory, the unrestricted use of permanent mailboxes could decrease the amount of memory available to other users. Therefore, the ability to create permanent mailboxes is controlled: a user must be specifically assigned the privilege to use the Create Mailbox (SYS$CREMBX) system service to create a permanent mailbox.
The various controls and restrictions applied to system service usage are described in this chapter. The Description section of each system service in the VSI OpenVMS System Services Reference Manual lists any privileges and quotas necessary to use the service.
4.2.1. User Privileges
The system manager, who maintains the user authorization file for the system, grants privileges for access to the protected system services. The user authorization file contains, in addition to profile information about each user, a list of specific user privileges and resource quotas.
When you log in to the system, the privileges and quotas assigned to you are associated with the process created on your behalf. These privileges and quotas are applied to every image the process executes.
When an image issues a call to a system service that is protected by privilege, the privilege list is checked. If you have the specific privilege required, the image is allowed to execute the system service; otherwise, a condition value indicating an error is returned.
For a list of privileges, see the description of the Create Process ($CREPRC) system service in the VSI OpenVMS System Services Reference Manual.
4.2.2. Resource Quotas
Many system services require certain system resources for execution. These resources include system dynamic memory and process quotas for I/O operations. When a system service that uses a resource controlled by a quota is called, the process's quota for that resource is checked. If the process has exceeded its quota, or if it has no quota allotment, an error condition value may be returned.
4.2.3. Access Modes
A process can execute at any one of four access modes: user, supervisor, executive, or kernel. The access modes determine a process's ability to access pages of virtual memory. Each page has a protection code associated with it, specifying the type of access—read, write, or no access—allowed for each mode.
For the most part, user-written programs execute in user mode; system programs executing at the user's request (system services, for example) may execute atone of the other three, more privileged access modes.
In some system service calls, the access mode of the caller is checked. For example, when a process tries to cancel timer requests, it can cancel only those requests that were issued from the same or less privileged access modes. For example, a process executing in user mode cannot cancel a timer request made from supervisor, executive, or kernel mode.
Access Mode |
Numeric Value |
Symbolic Name |
Privilege Rank |
---|---|---|---|
Kernel |
0 |
PSL$C_KERNEL |
Highest |
Executive |
1 |
PSL$C_EXEC | |
Supervisor |
2 |
PSL$C_SUPER | |
User |
3 |
PSL$C_USER |
Lowest |
The symbolic names are defined by the symbolic definition macro SYS$PSLDEF.
System services that permit an access mode argument allow callers to specify only an access mode of equal or lesser privilege than the access mode from which the service was called. If the specified access mode is more privileged than the access mode from which the service was called, the less privileged access mode is always used.
To determine the mode to use, the operating system compares the specified access mode with the access mode from which the service was called. Because this operation results in an access mode with a higher numeric value (when the access mode of the caller is different from the specified access mode), the access mode is said to be maximized.
Because much of the code you write executes in user mode, you can omit the access mode argument. The argument value defaults to 0 (kernel mode), and when this value is compared with the value of the current execution mode (3, user mode), the higher value (3) is used.
4.3. System Service Call Entry
$SERVICE arga ,argb ,argc ,argd
This format indicates that the macro name of the service is
$SERVICE and that it requires four arguments, ordered as
shown and with keyword names arga
, argb
,
argc
, and argd
.
Arguments passed to a service must be listed in your call entry in the order shown in the Format section of the service description. Each argument has four characteristics: OpenVMS usage, data type, access type, and passing mechanism. These characteristics are described in Chapter 1, Call Format to OpenVMS Routines.
The OpenVMS Alpha and OpenVMS I64, SYS$LIBRARY:SYS$LIB_C.TLB file contains C function prototypes for system services. These prototypes are documented in VSI OpenVMS System Services Reference Manual: A-GETUAI and VSI OpenVMS System Services Reference Manual: GETUTC-Z. For each prototype, the manuals provide the correct syntax (which shows the arguments the function accepts in the order in which it expects them), a description of each argument, and the type of data returned by the function.
Some arguments are optional. Optional arguments are indicated by brackets in the service descriptions. When your program invokes a system service by using a CALL entry point, you can omit optional arguments at the end of the argument list. If the optional argument is not the last argument in the list, you must either pass a zero by value or use a comma to indicate the place of the omitted argument. Some languages, such as C, require that you pass a zero by value for all trailing optional arguments. See your language processor documentation for further information.
return_status = sys$getdvi (event_flagnum, channel, &devnam, &item_list,0,0,0);
Note that in C, you must not omit the optional trailing arguments and should pass a zero by value for these unused parameters. See your language processor documentation for further information.
The VSI OpenVMS System Services Reference Manual provides a description of each service that indicates how each argument is to be passed. Phrases such as “an address” and “address of a character string descriptor” identify reference and descriptor arguments, respectively. Terms like “Boolean value,” “number,” “value,” or “mask” indicate an argument that is passed by value.
In the Alpha, VAX, and I64 environments, the called routine interprets each argument using one of three standard passing mechanisms: by value, by reference, or by descriptor.
On VAX systems, the calling program passes an argument list of longwords to a called service; each longword in the argument list specifies a single argument.
On Alpha systems, the calling program passes arguments in an argument item sequence; each quadword in the sequence specifies a single argument item. Note that the argument item sequence is formed using R16—R21 or F16—F21 (a register for each argument).
On I64 systems, the first eight parameters are passed in R32 through R39, with the parameter count in R25 and subsequent parameters in quadwords on the stack.
For more detailed information on arguments lists and passing mechanisms, see Section 2.4, “Argument List” and Section 2.5, “Argument Passing Mechanisms”.
Some services also require service-specific data structures that either indicate functions to be performed or hold information to be returned. The VSI OpenVMS System Services Reference Manual includes descriptions of these service-specific data structures. You can use this information and information from your programming language manuals to define such service-specific item lists.
4.4. System Service Completion
When a system service completes, control is returned to your program. You can specify how and when control is returned to your program by choosing synchronous or asynchronous forms of system services and by enabling process execution modes.
When synchronous system services return control to your program
When asynchronous system services return control to your program
How you can synchronize the completion of asynchronous system services
How control is returned to your program when special process execution modes are enabled
4.4.1. Asynchronous and Synchronous System Services
You can execute a number of system services either asynchronously or synchronously (such as, SYS$GETJPI and SYS$GETJPIW or SYS$ENQ and SYS$ENQW). The W at the end of the system service name indicates the synchronous version of the system service.
The asynchronous version of a system service queues a request and returns control to your program. You can perform operations while the system service executes; however, you should not attempt to access information returned by the service until you check for the system service completion.
Typically, you pass to an asynchronous system service an event flag and an I/O status block or a lock status block. When the system service completes, it sets the event flag and places the final status of the request in the status block. You use the SYS$SYNCH system service to ensure that the system service has completed. You pass SYS$SYNCH the event flag and the status block that you passed to the asynchronous system service; SYS$SYNCH waits for the event flag to be set, then ensures that the system service (rather than some other program) sets the event flag by checking the status block. If the status block is still zero, SYS$SYNCH waits until the status block is filled.
The synchronous version of a system service acts exactly as if you had used the
asynchronous version followed immediately by a call to
SYS$SYNCH. If you omit the efn
argument, the service uses event flag number 0 whether you use the synchronous or
asynchronous version of a system service.
! Data structure for SYS$GETJPI . . . INTEGER*4 STATUS, 2 FLAG, 2 PID_VALUE ! I/O status block INTEGER*2 JPISTATUS, 2 LEN INTEGER*4 ZERO /0/ COMMON /IO_BLOCK/ JPISTATUS, 2 LEN, 2 ZERO . . . ! Call SYS$GETJPI and wait for information STATUS = LIB$GET_EF (FLAG) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) STATUS = SYS$GETJPI (%VAL(FLAG), 2 PID_VALUE, 2 , 2 NAME_BUF_LEN, 2 JPISTATUS, 2 ,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) . . . STATUS = SYS$SYNCH (%VAL(FLAG), 2 JPISTATUS) IF (.NOT. JPISTATUS) THEN CALL LIB$SIGNAL (%VAL(JPISTATUS)) END IF END
4.4.2. System Service Resource Wait Mode
Normally, when a system service is called and a required resource is not available, the process is placed in a wait state until the resource becomes available. Then the service completes execution. This mode is called resource wait mode.
In a real-time environment, however, it may not be practical or desirable for a program to wait. In these cases, you can choose to disable resource wait mode so that when a required resource is unavailable, control returns immediately to the calling program with an error condition value. You can disable (and reenable) resource wait mode with the Set Resource Wait Mode (SYS$SETRWM) system service.
If resource wait mode is disabled, it remains disabled until it is explicitly reenabled or until your process is deleted. For example, if your program has disabled resource wait mode and has exited to the DCL prompt, subsequent programs or utilities invoked by this process continue to run with resource wait mode disabled and might not perform properly because they are not prepared to handle a failure to obtain a resource. In this case, you should reenable the wait mode before your program exits to the DCL prompt.
How a program responds to the unavailability of a resource depends primarily on the application and the particular service being called. In some instances, the program may be able to continue execution and retry the service call later. In other instances, it may be necessary for the program to wait for the resource and the system service to complete.
4.4.3. Condition Values Returned from System Services
When a service returns control to your program, it places a return status value in the general register R0 (R8, R9 for I64). The value in the low-order word indicates either that the service completed successfully or that some specific error prevented the service from performing some or all of its functions. After each call to a system service, you must check whether it completed successfully. You can also test for specific errors in the condition value.
The low-order bit indicates successful (1) or unsuccessful (0) completion of the service.
The low-order 3 bits, taken together, represent the severity of the error. Table 4.2, “Severity Codes of Condition Value Returned” lists the possible severity code values returned.
For VAX MACRO, the symbolic definition macro SYS$STSDEF defines the symbolic names. For the C programming language, the SSDEF.H file defines the symbolic names.
The remaining bits (bits 3 through 31) classify the particular return condition and the operating system component that issued the condition value. For system service return status values, the high-order word (bits 16 through 31) contains zeros.
Value |
Meaning |
Symbolic Name |
---|---|---|
0 |
Warning |
STS$K_WARNING |
1 |
Success |
STS$K_SUCCESS |
2 |
Error |
STS$K_ERROR |
3 |
Informational |
STS$K_INFO |
4 |
Severe or fatal error |
STS$K_SEVERR |
5—7 |
Reserved |
SS$_code
where code is a mnemonic describing the return condition.
SS$_NORMAL
SS$_ACCVIO
This condition value indicates that an access violation occurred because a service could not read an input field or write an output field.
The symbolic definitions for condition values are included in the default system library SYS$LIBRARY:STARLET.OLB. You can obtain a listing of these symbolic codes at assembly time by invoking the system macro SYS$SSDEF. To check return conditions, use the symbolic names for system condition values.
The OpenVMS operating system does not automatically handle system service failure or warning conditions; you must test for them and handle them yourself. This contrasts with the operating system's handling of exception conditions detected by the hardware or software; the system handles these exceptions by default, although you can intervene in or override the default handling by declaring a condition handler.
4.4.4. Testing the Condition Value
Each language provides some mechanism for testing the return status. Often you need only check the low-order bit, such as by a test for TRUE (success or informational return) or FALSE (error or warning return). Condition values that are returned by system services can provide information and whether the service completed successfully. The condition value that usually indicates success is SS$_NORMAL, but others are defined. For example, the condition value SS$_BUFFEROVF, which is returned when a character string returned by a service is longer than the buffer provided to receive it, is a success code. This condition value, however, gives the program additional information.
Warning returns and some error returns indicate that the service performed some, but not all, of the requested function.
The possible condition values that each service can return are described with the individual service descriptions in the VSI OpenVMS System Services Reference Manual. When you write calls to system services, read the descriptions of the return condition values to determine whether you want the program to check for particular return conditions.
To check the entire value for a specific return condition, each language provides a way for your program to determine the values associated with specific symbolically defined codes. You should always use these symbolic names when you write tests for specific conditions.
For information about how to test for these codes, see the user's guide for your programming language.
4.4.4.1. Testing the Condition Value With $VMS_STATUS_SUCCESS Macro
You can use the $VMS_STATUS_SUCCESS macro, defined in stsdef.h, to test an OpenVMS condition value. $VMS_STATUS_SUCCESS depends on the documented format of an OpenVMS condition value, and particularly on the setting of the lowest bit in a condition value. If the lowest bit is set, the condition indicates a successful status, while the bit is clear for an unsuccessful status.
$VMS_STATUS_SUCCESS is used only with condition values that follow the OpenVMS condition status value format, and not with C standard library routines and return values that follow C native status value norms. For details on the OpenVMS condition status value structure, please see VSI OpenVMS Programming Concepts Manual, Volume I. For information on the return values from the various C standard library routines, see the VSI C Run-Time Library Reference Manual for OpenVMS Systems.
RetStat = sys$dassgn( IOChan ); if (!$VMS_STATUS_SUCCESS( RetStat )) return RetStat;
4.4.5. Special Condition Values Using Symbolic Codes
Individual services have symbolic codes for special return conditions, argument list offsets, identifiers, and flags associated with these services. For example, the Create Process (SYS$CREPRC) system service(which is used to create a subprocess or a detached process) has symbolic codes associated with the various privileges and quotas you can grant to the created process.
The SYS$LIBRARY:SYS$LIB_C.TLB file contains the C header files for OpenVMS Alpha and OpenVMS I64 C data structures and definitions. For more information about SYS$LIBRARY:SYS$LIB_C.TLB, refer to Chapter 5, STARLET Structures and Definitions for C Programmers.
The default system macro library, STARLET.MLB, contains the macro definitions for most system symbols. When you assemble a source program that calls any of these macros, the assembler automatically searches STARLET.MLB for the macro definitions. Each symbol name has a numeric value.
If your language has a method of obtaining values for these symbols, this method is explained in the user's guide.
Write a short VAX MACRO program containing the desired macros.
Assemble or compile the program and generate a listing. Using the listing, find the desired symbols and their hexadecimal values.
Define each symbol with its value within your source program.
- Create the following three-line VAX MACRO program (named JPIDEF.MAR here; you can choose any name you want):
.TITLE JPIDEF "Obtain values for $JPIDEF" $JPIDEF GLOBAL ; These MUST be UPPERCASE .END
- On VAX, assemble and link the program to create the file JPIDEF.MAP as follows:
$ MACRO JPIDEF $ LINK/NOEXE/MAP/FULL JPIDEF %LINK-W-USRTFR, image NL:[].EXE; has no user transfer address
The file JPIDEF.MAP contains the symbols defined by $JPIDEF listed both alphabetically and numerically.
On Alpha and I64, to compile the program to create the JPIDEF.MAP, enter the following:$ MACRO/MIGRATION JPIDEF $ LINK/NOEXE/MAP/FULL JPIDEF %LINK-W-USRTFR, image NL:[].EXE; has no user transfer address
Find the value of JPI$_CPUTIM and define the symbol in your program.
4.4.6. Testing the Return Condition Value for VAX MACRO
BLBC R0,errlabel ; Error if low bit clear
Programs should not test for success by comparing the return status to SS$_NORMAL. A future release of OpenVMS may add new, alternate success codes to an existing service, causing programs that test for SS$_NORMAL to fail.
CMPL #SS$_ILLEFC,R0 ; Is event flag number illegal?
Note that return condition values are always longword values; however, all system services always return the same value in the high-order word of all condition values returned in R0.
4.4.7. System Messages Generated by Condition Values
When you execute a program with the DCL command RUN, the command interpreter uses the contents of R0 to issue a descriptive message if the program completes with an unsuccessful status. On I64, the calling standard specifies that the return status is returned in R8. As an aid to portable code, the MACRO compiler automatically maps uses of R0 to R8. See the VSI OpenVMS MACRO Compiler Porting and User's Guide for additional information.
$READEF_S -
EFN=#64, -
STATE=TEST
BSBW ERROR
.
.
.
ERROR: BLBC R0,10$ ; Check register 0
RSB ; Success, return
10$: RET ; Exit with R0 status
After a system service call, the BSBW instruction branches to the subroutine ERROR. The subroutine checks the low-order bit in register 0 and, if the bit is clear, branches to a RET instruction that causes the program to exit with the status of R0 preserved. Otherwise, the subroutine issues an RSB instruction to return to the main program.
%SYSTEM-F-UNASEFC, unassociated event flag cluster
The keyword UNASEFC in the message corresponds to the condition value SS$_UNASEFC.
Error |
Meaning |
---|---|
SS$_ACCVIO |
The argument list cannot be read by the caller (using the
$ This meaning of SS$_ACCVIO is different from its meaning for individual services. When SS$_ACCVIO is returned from individual services, the service is called, but one or more arguments to the service cannot be read or written by the caller. |
SS$_INSFARG |
Not enough arguments were supplied to the service. |
SS$_ILLSER |
An illegal system service was called. |
4.5. Program Examples with System Service Calls
ith SYSTEM, TEXT_IO, STARLET, CONDITION_HANDLING;procedure ORION is -- Declare variables to hold equivalence name and length -- EQUIV_NAME: STRING (1..255);
pragma VOLATILE (EQUIV_NAME); NAME_LENGTH: SYSTEM.UNSIGNED_WORD; pragma VOLATILE (NAME_LENGTH); -- Declare itemlist and fill in entries. -- ITEM_LIST: STARLET.ITEM_LIST_3_TYPE (1..2) :=
(1 => (ITEM_CODE => STARLET.LNM_STRING,
BUF_LEN => EQUIV_NAME'LENGTH, BUF_ADDRESS => EQUIV_NAME'ADDRESS, RET_ADDRESS => NAME_LENGTH'ADDRESS), 2 => (ITEM_CODE => 0, BUF_LEN => 0, BUF_ADDRESS => SYSTEM.ADDRESS_ZERO, RET_ADDRESS => SYSTEM.ADDRESS_ZERO)); STATUS: CONDITION_HANDLING.COND_VALUE_TYPE;
begin -- Translate the logical name -- STARLET.TRNLNM (
STATUS => STATUS, TABNAM => "LNM$FILE_DEV", LOGNAM => "CYGNUS", ITMLST => ITEM_LIST); -- Display name if success, else signal error -- if not CONDITION_HANDLING.SUCCESS (STATUS) then
CONDITION_HANDLING.SIGNAL (STATUS); else TEXT_IO.PUT ("CYGNUS translates to """); TEXT_IO.PUT (EQUIV_NAME (1..INTEGER(NAME_LENGTH))); TEXT_IO.PUT_LINE (""""); end if; end ORION;
Ada Notes
(The with clause names the predefined packages of declarations used in this program. SYSTEM and TEXT_IO are standard Ada packages; STARLET defines the OpenVMS system service routines, data types, and constants; and CONDITION_HANDLING defines error-handling facilities. | |
Enough space is allocated to EQUIV_NAME to hold the longest possible logical name. NAME_LENGTH will receive the actual length of the translated logical name. The VOLATILE pragma is required for variables that will be modified by means other than an assignment statement or being an output parameter to a routine call. | |
ITEM_LIST_3_TYPE is a predeclared type in package STARLET that defines the OpenVMS three-longword item list structure. | |
The dollar-sign character is not valid in Ada identifiers; package STARLET defines the
| |
COND_VALUE_TYPE is a predeclared type in package CONDITION_HANDLING that is used for return status values. | |
System services are defined in package STARLET using names that omit the prefix SYS$. The passing mechanisms are specified in the routine declaration in STARLET, so they need not be specified here. | |
In this example, any failure status from the SYS$TRNLNM service is signaled as an error. Other means of error recovery are possible; see your Ada language documentation for more details. |
10 SUB ORION! Subprogram ORION OPTION TYPE=EXPLICIT ! Require declaration of all ! symbols EXTERNAL LONG FUNCTION SYS$TRNLNM ! Declare the system service EXTERNAL WORD CONSTANT LNM$_STRING ! The request code that ! we will use DECLARE WORD NAMLEN,
! Word to receive length LONG SYS_STATUS ! Longword to receive status COMMON (BUF) STRING NAME_STRING = 255
RECORD ITEM_LIST ! Define item ! descriptor structure WORD BUFFER_LENGTH ! The buffer length WORD ITEM ! The request code LONG BUFFER_ADDRESS ! The buffer address LONG RETURN_LENGTH_ADDRESS ! The address of the return len ! word LONG TERMINATOR ! The terminator END RECORD ITEM_LIST ! End of structure definition DECLARE ITEM_LIST ITEMS ! Declare an item list ITEMS::BUFFER_LENGTH = 255% ! Initialize the item list ITEMS::ITEM = LNM$_STRING ITEMS::BUFFER_ADDRESS = LOC( NAME_STRING ) ITEMS::RETURN_LENGTH_ADDRESS = LOC( NAMLEN ) ITEMS::TERMINATOR = 0
SYS_STATUS = SYS$TRNLNM( , 'LNM$FILE_DEV', 'CYGNUS',, ITEMS)
IF (SYS_STATUS AND 1%) = 0%
THEN ! Error path ELSE ! Success path END IF END SUB
BASIC Notes
The SUB statement defines the routine and its entry mask. | |
The DECLARE WORD NAMLEN declaration reserves a 16-bit word for the output value. | |
The COMMON (BUF) STRING NAME_STRING = 255 declaration allocates 255 bytes for the output data in a static area. The compiler builds the descriptor. | |
The SYS$ form invokes the system service as a function. Enclose the arguments in parentheses and specify them in positional order only. Specify a comma for each optional argument that you omit (including trailing arguments). | |
The input character string is specified directly in the system service call;the compiler builds the descriptor. | |
The IF statement performs a test on the low-order bit of the return status. This form is recommended for all status returns. |
MODULE ORION= BEGIN EXTERNAL ROUTINE ERROR_PROC: NOVALUE; ! Error processing routine LIBRARY 'SYS$LIBRARY:STARLET.L32'; ! Library containing OpenVMS ! macros (including $TRNLNM). ! This declaration ! is required. GLOBAL ROUTINE ORION: NOVALUE= BEGIN OWN NAMBUF : VECTOR[255, BYTE], ! Output buffer NAMLEN : WORD, ! Translated string length ITEMS : BLOCK[16,BYTE] INITIAL(WORD(255, ! Output buffer length LNM$_STRING), ! Item code NAMBUF, ! Output buffer NAMLEN, ! Address of word for ! translated ! string length 0); ! List terminator LOCAL ! Return status from STATUS; ! system service STATUS = $TRNLNM(TABNAM = %ASCID'LNM$FILE_DEV', LOGNAME = %ASCID'CYGNUS', ITMLST = ITEMS);IF NOT .STATUS THEN ERROR_PROC(.STATUS);
END;
BLISS Notes
The macro is invoked by its service name, without a suffix. Enclose the arguments in parentheses and specify them by keyword. (Keyword names correspond to the names of the arguments shown in lowercase in the system service format descriptions in the VSI OpenVMS System Services Reference Manual). | |
The return status, which is assigned to the variable STATUS, is tested for TRUE or FALSE. FALSE (low bit = 0) indicates failure or warning. |
#include <starlet.h>#include <lib$routines.h> #include <ssdef.h> #include <lnmdef.h> #include <descrip.h> #include <stdio.h> typedef struct {
unsigned short buffer_length; unsigned short item_code; char *buffer_addr; short *return_len_addr; unsigned terminator; } item_list_t; main () {
$DESCRIPTOR(table_name, "LNM$FILE_DEV"); $DESCRIPTOR(log_name, "CYGNUS"); char translated_name[255]; int status; short return_length; item_list_t item_list; item_list.buffer_length = sizeof(translated_name);
item_list.item_code = LNM$_STRING; item_list.buffer_addr = translated_name; item_list.return_len_addr = &return_length; item_list.terminator = 0; status = sys$trnlnm(0, &table_name, &log_name, 0, &item_list);
if (!(status & 1))
lib$signal(status); else printf("The logical name %s is equivalent to %*s\n", log_name.dsc$a_pointer, return_length, translated_name); }
C Notes
The C language header file | |
The structure of an item list entry is defined. | |
The $DESCRIPTOR macro declares and initializes a character string
descriptor. Here, two descriptors are created for use with the
| |
The function | |
The | |
The IF statement performs a logical test following the function reference to determine whether the service completed successfully. If an error or warning occurs during the service call, the error is signaled. |
IDENTIFICATION DIVISION. PROGRAM-ID. ORION.ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 TABNAM PIC X(11) VALUE "LNM$FILE_DEV". 01 CYGDES PIC X(6) VALUE "CYGNUS". 01 NAMDES PIC X(255) VALUE SPACES.
01 NAMLEN PIC S9(4) COMP. 01 ITMLIS. 02 BUFLEN PIC S9(4) COMP VALUE 225. 02 ITMCOD PIC S9(4) COMP VALUE 2.
02 BUFADR POINTER VALUE REFERENCE NAMDES. 02 RETLEN POINTER VALUE REFERENCE NAMLEN. 02 FILLER PIC S9(5) COMP VALUE 0. 01 RESULT PIC S9(9) COMP.
PROCEDURE DIVISION. START-ORION. CALL "SYS$TRNLNM"
USING OMITTED BY DESCRIPTOR TABNAM BY DESCRIPTOR CYGDES
OMITTED BY REFERENCE ITMLIS GIVING RESULT. IF RESULT IS FAILURE
GO TO ERROR-CHECK. DISPLAY "NAMDES: ", NAMDES(1:NAMLEN). GO TO THE-END. ERROR-CHECK. DISPLAY "Returned Error: ", RESULT CONVERSION. THE-END. STOP RUN.
COBOL Notes
The PROGRAM-ID paragraph identifies the program by specifying the program name, which is the global symbol associated with the entry point. The compiler builds the entry mask. | |
Enough bytes are allocated for the alphanumeric output data. The compiler generates a descriptor when you specify USING BY DESCRIPTOR in the CALL statement. | |
The value of the symbolic code LNM$STRING is 2. Section 4.4.5, “Special Condition Values Using Symbolic Codes” explains how to obtain values for symbolic codes. | |
This definition reserves a signed longword with COMP (binary) usage to receive the output value. | |
The service is called by the SYS$ form of the service name, and the name is enclosed in quotation marks. Specify arguments in positional order only, with the USING statement. You cannot omit arguments; if you are accepting the default for an argument, you must pass the default value explicitly (OMITTED in this example). You can specify explicitly how each argument is being passed: by descriptor, by reference (that is, by address), or by value. You can also implicitly specify how an argument is being passed: through the default mechanism (by reference), or through association with the last specified mechanism (thus, the last two arguments in the example are implicitly passed by value). | |
The input string is defined as alphanumeric (ASCII) data. The compiler generates a descriptor when you specify USING BY DESCRIPTOR in the CALL statement. | |
The IF statement tests RESULT for a failure status. In this case, control is passed to the routine ERROR-CHECK. |
SUBROUTINE ORION IMPLICIT NONE ! Require declaration of all symbols INCLUDE '($SYSSRVNAM)' ! Declare system service namesINCLUDE '($LNMDEF)' ! Declare $TRNLNM item codes INCLUDE '(LIB$ROUTINES)' ! Declare LIB$ routines STRUCTURE /ITEM_LIST_3_TYPE/ ! Structure of item list
INTEGER*2 BUFLEN ! Item buffer length INTEGER*2 ITMCOD ! Item code INTEGER*4 BUFADR ! Item buffer address INTEGER*4 RETADR ! Item return length address END STRUCTURE RECORD /ITEM_LIST_3_TYPE/ ITEMLIST(2) ! Declare itemlist CHARACTER*255 EQUIV_NAME ! For returned equivalence name INTEGER*2 NAMLEN ! For returned name length VOLATILE EQUIV_NAME,NAMLEN
INTEGER*4 STATUS ! For returned service status
! Fill in itemlist ! ITEMLIST(1).ITMCOD = LNM$_STRING ITEMLIST(1).BUFLEN = LEN(EQUIV_NAME)
ITEMLIST(1).BUFADR = %LOC(EQUIV_NAME) ITEMLIST(1).RETADR = %LOC(NAMLEN) ITEMLIST(2).ITMCOD = 0 ! For terminator ITEMLIST(2).BUFLEN = 0 ! Call SYS$TRNLM ! STATUS = SYS$TRNLNM (, ! ATTR omitted
1 'LNM$FILE_DEV', ! TABNAM 2 'CYGNUS', ! LOGNAM 3 , ! ACMODE omitted 4 ITEMLIST) ! ITMLST ! Check return status, display translation if successful ! IF (.NOT. STATUS) THEN
CALL LIB$SIGNAL(%VAL(STATUS)) ELSE WRITE (*,*) 'CYGNUS translates to: "', 1 EQUIV_NAME(1:NAMLEN), '"' END IF END
FORTRAN Notes
The module $SYSSRVNAM in the FORTRAN system default library FORSYSDEF.TLB contains INTEGER and EXTERNAL declarations for each of the system services, so you need not explicitly provide these declarations in your program. Module $LNMDEF defines constants and data structures used when calling the logical name services, and module LIB$ROUTINES contains declarations for the LIB$ Run-Time Library routines. | |
The structure of an OpenVMS 3-longword item list is declared and then used to define the record variable ITEM_LIST. The second element will be used for the terminator. | |
The VOLATILE declaration is required for variables that are modified by means other than a direct assignment or as an argument in a routine call. | |
Return status variables should always be declared as longword integers. | |
The LEN intrinsic function returns the allocated length of EQUIV_NAME. The %LOC built-in function returns the address of its argument. | |
By default, FORTRAN passes arguments by reference, except for strings which are passed by CLASS_S descriptor. Arguments are omitted in FORTRAN by leaving the comma as a placeholder. All arguments must be specified or explicitly omitted. | |
A condition value can be tested for success or failure by a true/false test. For more information on testing return statuses, see the OpenVMS FORTRAN documentation. |
[INHERIT('SYS$LIBRARY:STARLET','SYS$LIBRARY:PASCAL$LIB_ROUTINES')] PROGRAM ORION (OUTPUT); TYPE Item_List_Cell = RECORD CASE INTEGER OF
1:( { Normal Cell } Buffer_Length : [WORD] 0..65535; Item_Code : [WORD] 0..65535; Buffer_Addr : UNSIGNED; Return_Addr : UNSIGNED ); 2:( { Terminator } Terminator : UNSIGNED ); END; Item_List_Template(Count:INTEGER) = ARRAY [1..Count] OF Item_List_Cell; VAR Item_List : Item_List_Template(2); Translated_Name : [VOLATILE] VARYING [255] OF CHAR;
Status : INTEGER; BEGIN { Specify the buffer to return the translation }
Item_List[1].Buffer_Length := SIZE(Translated_Name.Body); Item_List[1].Item_Code := LNM$_String; Item_List[1].Buffer_Addr := IADDRESS(Translated_Name.Body); Item_List[1].Return_Addr := IADDRESS(Translated_Name.Length); { Terminate the item list } Item_List[2].Terminator := 0; { Translate the CYGNUS logical name } Status := $trnlnm(Tabnam := 'LNM$FILE_DEV', Lognam := 'CYGNUS',
Itmlst := Item_List); IF NOT ODD(Status)
THEN LIB$SIGNAL(Status) ELSE WRITELN('CYGNUS is equivalent to ',Translated_Name); END.
Pascal Notes
The Pascal environment file STARLET.PEN defines OpenVMS system services, data structures and constants. PASCAL$LIB_ROUTINES declares the LIB$ Run-Time Library routines. | |
The structure of an item list entry is defined using a variant record type. | |
The VARYING OF CHAR type is a variable-length character string with two components: a word-integer length and a character string body, which in this example is 255 bytes long. The VOLATILE attribute is required for variables that are modified by means other than a direct assignment or as an argument in a routine call. | |
The functions SIZE and IADDRESS obtain the allocated size of the string body and the address of the string body and length. The returned length will be stored into the length field of the varying string Translated_Name, so that it will appear to be the correct size. | |
The definition of the SYS$TRNLNM routine in STARLET.PEN contains specifications of the passing mechanism to be used for each argument;thus, it is not necessary to specify the mechanism here. | |
The IF statement performs a logical test following the function reference to see if the service completed successfully. If an error or warning occurs during the service call, the error is signaled. |
CYGDES: .ASCID /CYGNUS/; Descriptor for CYGNUS string TBLDES: .ASCID /LNM$FILE_DEV/
; Logical name table NAMBUF: .BLKB 255
; Output buffer NAMLEN: .BLKW 1
; Word to receive length ITEMS: .WORD 255 ; Output buffer length .WORD LNM$STRING ; Item code .ADDRESS - ; Output buffer NAMBUF .ADDRESS - ; Return length NAMLEN .LONG 0 ; List terminator . . . .ENTRY ORION,0
; Routine entry point & mask $TRNLNM_S -
TABNAM=TBLDES, - LOGNAM=CYGDES, - ITMLST=ITEMS BLBC R0,ERROR
; Check for error . . . .END
VAX MACRO Notes
The input character string descriptor argument is defined using the .ASCID directive. | |
The name of the table to search is defined using the .ASCID directive. | |
Enough bytes to hold the output data are allocated for an output character string argument. | |
The MACRO directive .BLKW reserves a word to hold the output length. | |
A routine name and entry mask show the beginning of executable code in a routine or subroutine. | |
A macro name that has the suffix _S or _G calls the service. You can specify arguments either by keyword (as in this example) or by positional order. (Keyword names correspond to the names of the arguments shown in lowercase in the system service format descriptions in the VSI OpenVMS System Services Reference Manual). If you omit any optional arguments (if you accept the defaults), you can omit them completely if you specify arguments by keyword. If you specify arguments by positional order, however, you must specify the comma for each missing argument. Use the number sign (#) to indicate a literal value for an argument. | |
The BLBC instruction causes a branch to a subroutine named ERROR (not shown) if the low bit of the condition value returned from the service is clear (low bit clear = failure or warning). You can use a BSBW instruction to branch unconditionally to a routine that checks the return status. |
Chapter 5. STARLET Structures and Definitions for C Programmers
This chapter describes the libraries that contain C header files for routines supplied by the OpenVMS Alpha and OpenVMS I64 operating systems.
5.1. SYS$STARLET_C.TLB Equivalency to STARLETSD.TLB
The SYS$STARLET_C.TLB file, which was introduced in OpenVMS Alpha Version 1.0, contains all the .H files that provide STARLET functionality equivalent to STARLETSD.TLB. The file SYS$STARLET_C.TLB, together with DECC$RTLDEF.TLB that ships with the VSI C Compiler, replaces VAXCDEF.TLB that previously shipped with the VAX C Compiler. DECC$RTLDEF.TLB contains all the .H files that support the compiler and RTL, such as STDIO.H.
RMS structures
Previously, the RMS structures FAB, NAM, RAB, XABALL, and so forth, were defined in the appropriate .H files as “struct RAB {...”, for example. The .H files supplied in OpenVMS Alpha Version 1.0 define them as “struct rabdef {...”. To compensate for this difference, lines of the form “#define RAB rabdef” have been added. However, there is one situation where a source change is required because of this change. If you have a private structure that contains a pointer to one of these structures and your private structure is defined (but not used) before the RMS structure has been defined, you will receive compile-time errors similar to the following:%CC-E-PASNOTMEM, In this statement, "rab$b_rac" is not a member of "rab".
This error can be avoided by reordering your source file so that the RMS structure is defined before the private structure. Typically, this involves moving around “#include” statements.
LIB (privileged interface) structures
Historically, three structures from LIB (NFBDEF.H, FATDEF.H, and FCHDEF.H) have been made available as .H files. These files were shipped as .H files in OpenVMS Alpha Version 1.0 and 1.5 (not in the new SYS$STARLET_C.TLB). As of OpenVMS Alpha Version 7.0, the file SYS$LIB_C.TLB, containing all LIB structures and definitions, was added. These three .H files are now part of that .TLB and are no longer shipped separately. Source changes may be required, because no attempt has been made to preserve any existing anomalies in these files. The structures and definitions from LIB are for privileged interfaces only and are therefore subject to change.
Use of “variant_struct” and “variant_union”
In the new .H files, “variant_struct” and “variant_union” are always used; whereas previously some structures used “struct” and “union”. Therefore, the intermediate structure names cannot be specified when referencing fields within data structures.
For example, the following statement:AlignFaultItem.PC[0] = DataPtr->afr$r_pc_data_overlay.afr$q_fault_pc[0];
becomes:AlignFaultItem.PC[0] = DataPtr->afr$q_fault_pc[0];
Member alignment
Each of the .H files in SYS$STARLET_C.TLB saves and restores the state of “#pragma member_alignment”.
Conventions The .H files in SYS$STARLET_C.TLB adhere to some conventions that were only partly followed in VAXCDEF.TLB. All constants (#defines) have uppercase names. All identifiers (routines, structure members, and so forth) have lowercase names. Where there is a difference from VAXCDEF.TLB, the old symbol name is also included for compatibility, but users are encouraged to follow the new conventions.
Use of Librarian utility to access the .H files
During installation of OpenVMS Alpha, the contents of SYS$STARLET_C.TLB are not extracted into the separate .H files. The VSI C Compiler accesses these files from within SYS$STARLET_C.TLB, regardless of the format of the #include statement. If you want to inspect an individual .H file, you can use the Librarian utility, as in the following example:$ LIBRARY /EXTRACT=AFRDEF /OUTPUT=AFRDEF.H SYS$LIBRARY:SYS$STARLET_C.TLB
Additional .H files included in SYS$STARLET_C.TLB
In addition to the .H files derived from STARLET sources, SYS$STARLET_C.TLB includes .H files that provide support for POSIX Threads Library, such as CMA.H.
5.2. NEW STARLET Definitions for C
SYS$LIBRARY:SYS$STARLET_C.TLB (or STARLET) provides C function prototypes for system services, as well as data structure definitions. The compiler searches the library file SYS$LIBRARY:SYS$STARLET_C.TLB for the STARLET header files. The definitions are consistent with the OpenVMS C language coding conventions and definitions (typedefs) used in SYS$LIBRARY:SYS$LIB_C.TLB.
To maintain source compatibility for users of STARLET.H as provided prior to OpenVMS Alpha Version 7.0, the “old style” function declarations and definitions are still provided by default. To take advantage of the new system service function prototypes and type definitions, you must explicitly enable them.
- Define the _NEW_STARLET symbol with the VSI C command line qualifier as follows:
/DEFINE=(__NEW_STARLET=1)
or
- Define the _NEW_STARLET symbol in your C source program before including the SYS$STARLET_C.TLB header files:
#define __NEW_STARLET 1 #include <starlet.h> #include <vadef.h>
$ LIBRARY/OUTPUT=STARLET.H SYS$LIBRARY:SYS$STARLET_C.TLB/EXTRACT=STARLET
#pragma __required_pointer_size __long
int sys$expreg_64(
struct _generic_64 *region_id_64,
unsigned __int64 length_64,
unsigned int acmode,
unsigned int flags,
void *(*(return_va_64)),
unsigned __int64 *return_length_64);
#pragma __required_pointer_size __short
For more information about VSI C pointer size pragmas, see the VSI C User Manual.
#define __NEW_STARLET 1 /* Enable "New Starlet" features */ #include <starlet.h> /* Declare prototypes for system services */ #include <gen64def.h> /* Define GENERIC_64 type */ #include <vadef.h> /* Define VA$ constants */ #include <ints.h> /* Define 64-bit integer types */ #include <far_pointers.h> /* Define 64-bit pointer types */ { int status; /* Ubiquitous VMS status value */ GENERIC_64 region = { VA$C_P2 }; /* Expand in "default" P2 region */ VOID_PQ p2_va; /* Returned VA in P2 space */ uint64 length; /* Allocated size in bytes */ extern uint64 page_size; /* Page size in bytes */ status = sys$expreg_64( ®ion, request_size, 0, 0, &p2_va, &length ); ... }
Structure Used by Prototype |
Defined by Header File |
Common Prefix for Structure Member Names |
Description |
---|---|---|---|
struct _acmecb |
acmedef.h |
acmedef$ |
ACM communications buffer |
struct _acmesb |
acmedef.h |
acmedef$ |
ACM status block |
struct _cluevthndl |
cluevtdef.h |
cluevthndl$ |
Cluster event handle |
struct _fabdef |
fabdef.h |
fab$ |
File access block |
struct _generic_64 |
gen64def.h |
gen64$ |
Generic quadword structure |
struct _ieee |
ieeedef.h |
ieee$ |
IEEE Floating point control structure |
struct _ile2? |
iledef.h |
ile2$ |
Item list entry 2 |
struct _ile3? |
iledef.h |
ile3$ |
Item list entry 3 |
struct _ilea_64? |
iledef.h |
ilea_64$ |
64-bit item list entry A structure |
struct _ileb_64? |
iledef.h |
ileb_64$ |
64-bit item list entry B structure |
struct _iosa |
iosadef.h |
iosa$ |
I/O status area |
struct _iosb |
iosbdef.h |
iosb$ |
I/O status block |
struct _lksb |
lksbdef.h |
lksb$ |
Lock status block |
struct _rabdef |
rabdef.h |
rab$ |
RMS record access block |
struct _secid |
seciddef.h |
secid$ |
Global section identifier |
struct _va_range |
va_rangedef.h |
va_range$ |
32-bit virtual address range |
Part II. I/O, System, and Programming Routines
This part of this second volume describes the I/O operations, and the system and programming routines used by run-time libraries and system services.
Chapter 6. Run-Time Library Input/Output Operations
This chapter describes the different I/O programming capabilities provided by the run-time library and illustrates these capabilities with examples of common I/O tasks.
6.1. Choosing I/O Techniques
DEC Text Processing Utility
DECforms software
Program language I/O statements
OpenVMS Record Management Services (RMS) and Run-Time Library (RTL) routines
SYS$QIO and SYS$QIOW system services
Third party-supplied device drivers to control the I/O to the device itself
High-level procedure language with several data types, relational operators, error interception, looping, case language statements, and built-in procedures
Compiler for the DECTPU procedure language
Interpreter for the DECTPU procedure language
Extensible Versatile Editor (EVE) editing interface which, in addition to the EVE keypad, provides EDT, VT100, WPS, and numeric keypad emulation
Multiple buffers
Multiple windows
Multiple subprocesses
Text processing in batch mode
Insert or overstrike text entry
Free or bound cursor motion
Learn sequences
Pattern matching
Key definition
The method you select for I/O operations depends on the task you want to accomplish, ease of use, speed, and level of control you want.
The VSI DECforms for OpenVMS software is a forms management product for transaction processing. DECforms integrates text and graphics into forms and menus that application programs use as an interface to users. DECforms software offers application developers software development tools and a run-time environment for implementing interfaces.
DECforms software integrates with the Application Control and Management System (ACMS), a transaction process (TP) monitor that works with other commercial applications to provide complete customizable development and run-time environments for TP applications. An asynchronous call interface to ACMS allows a single DECforms run-time process to control multiple terminals simultaneously in a multithreaded way, resulting in an efficient use of memory. By using the ACMS Remote Access Option, DECforms software can be distributed to remote CPUs. This technique allows the host CPU to offload forms processing and distribute it as closely as possible to the end user.
In contrast to OpenVMS RMS, RTLs, SYS$QIOs, and device driver I/O, program language I/O statements have the slowest speed and lowest level of control, but they are the easiest to use and are highly portable.
OpenVMS RMS and RTL routines can perform most I/O operations for a high-level or assembly language program. For information about OpenVMS RMS, see the VSI OpenVMS Record Management Services Reference Manual.
System services can complete any I/O operation and can access devices not supported within OpenVMS RMS. See Chapter 7, System Service Input/Output Operations for a description of using I/O system services.
Writing a device driver provides the most control over I/O operations, but can be more complex to implement. For information about device drivers for VAX systems, see the OpenVMS VAX Device Support Manual.
RTL routines allow you either to read simple input from a user or send simple output to a user. One RTL routine allows you to specify a string to prompt for input from the current input device, defined by SYS$INPUT. Another RTL routine allows you to write a string to the current output device, defined by SYS$OUTPUT. See Section 6.2, “Using SYS$INPUT and SYS$OUTPUT” and Section 6.3, “Working with Simple User I/O” for more information.
RTL routines allow you either to read complex input from a user or to send complex output to a user. By providing an extensive number of screen management (SMG$) routines, the RTL allows you either to read multiple lines of input from users or to send complex output to users. The SMG$ routines also allow you to create and modify complicated displays that accept input and produce output. See Section 6.4, “Working with Complex User I/O” for more information.
RTL routines allow you to use programming language I/O statements to send data to and receive data from files. Program language I/O statements call OpenVMS RMS routines to complete most file I/O. You can also use OpenVMS RMS directly in your programs for accomplishing file I/O. See Chapter 12, File Operations for more information.
The SYS$QIO and SYS$QIOW system services allow you to send data to and from devices with the most flexibility and control. You can use system services to access devices not supported by your programming language or by OpenVMS RMS.
You can perform other special I/O actions, such as using interrupts, controlling echo, handling unsolicited input, using the type-ahead buffer, using case conversion, and sending system broadcast messages, by using SMG$ routines or, for example, by using SYS$BRKTHRU system service to broadcast messages. See Section 6.5, “Performing Special Input/Output Actions” for more information.
6.2. Using SYS$INPUT and SYS$OUTPUT
Typically, you set up your program so that the user is the invoker. The user starts the program either by entering a DCL command associated with the program or by using the RUN command.
6.2.1. Default Input and Output Devices
Logical Name | User Mode | Equivalence Device or File |
---|---|---|
SYS$INPUT |
Interactive |
Terminal at which the user is logged in |
Batch job |
Data lines following the invocation of the program | |
Command procedure |
Data lines following the invocation of the program | |
SYS$OUTPUT |
Interactive |
Terminal at which the user is logged in |
Batch job |
Batch log file | |
Command procedure |
Terminal at which the user is logged in |
Generally, use of SYS$INPUT and SYS$OUTPUT as the primary input and output devices is recommended. A user of the program can redefine SYS$INPUT and SYS$OUTPUT to redirect input and output as desired. For example, the interactive user might redefine SYS$OUTPUT as a file name to save output in a file rather than display it on the terminal.
6.2.2. Reading and Writing to Alternate Devices and External Files
Alternatively, you can design your program to read input from and write output to a file or a device other than the user's terminal. Files may be useful for writing large amounts of data, for writing data that the user might want to save, and for writing data that can be reused as input. If you use files or devices other than SYS$INPUT and SYS$OUTPUT, you should provide the names of the files or devices (best form is to use logical names) and any conventions for their use. You can specify such information by having the program write it to the terminal, by creating a help file, or by providing user documentation.
6.3. Working with Simple User I/O
Usually, you can request information from or provide information to the user with little regard for formatting. For such simple I/O, use either LIB$GET_INPUT and LIB$PUT_OUTPUT or the I/O statements for your programming language.
To provide complex screen displays for input or output, use the screen management facility described in Section 6.4, “Working with Complex User I/O”.
6.3.1. Default Devices for Simple I/O
The LIB$GET_INPUT and LIB$PUT_OUTPUT routines read from SYS$INPUT and write to SYS$OUTPUT, respectively. The logical names SYS$INPUT and SYS$OUTPUT are implicit to the routines, because you need only call the routine to access the I/O unit (device or file) associated with SYS$INPUT and SYS$OUTPUT. You cannot use these routines to access an I/O unit other than the one associated with SYS$INPUT or SYS$OUTPUT.
6.3.2. Getting a Line of Input
A read operation transfers one record from the input unit to a variable or variables of your choice. At a terminal, the user ends a record by pressing a terminator. The terminators are the ASCII characters NUL through US (0 through 31) except for LF, VT, FF, TAB, and BS. The usual terminator is CR (carriage return), which is generated by pressing the Return key.
If you are reading character data, LIB$GET_INPUT is a simple way of prompting for and reading the data. If you are reading noncharacter data, programming language I/O statements are preferable since they allow you to translate the data to a format of your choice.
For example, Fortran offers the ACCEPT statement, which reads data from SYS$INPUT, and the READ statement, which reads data from an I/O unit of your choice.
Make sure the variables that you specify can hold the largest number of characters the user of your program might enter, unless you want to truncate the input deliberately. Overflowing the input variable using LIB$GET_INPUT causes the fatal error LIB$_INPSTRTRU (defined in $LIBDEF); overflowing the input variable using language I/O statements may not cause an error but does truncate your data.
LIB$GET_INPUT places the characters read in a variable of your choice. You must define the variable type as a character. Optionally, LIB$GET_INPUT places the number of characters read in another variable of your choice. For input at a terminal, LIB$GET_INPUT optionally writes a prompt before reading the input. The prompt is suppressed automatically for an operation not taking place at a terminal.
INTEGER*4 STATUS, 2 LIB$GET_INPUT INTEGER*2 INPUT_SIZE CHARACTER*512 INPUT STATUS = LIB$GET_INPUT (INPUT, ! Input value 2 'Input value: ', ! Prompt (optional) 2 INPUT_SIZE) ! Input size (optional) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
6.3.3. Getting Several Lines of Input
Terminal—The user has pressed Ctrl/Z. To ensure that the convention is followed, you might first write a message telling the user to press Ctrl/Z to terminate the input sequence.
Command procedure—The end of a sequence of data lines has been reached. That is, a sequence of data lines ends at the next DCL command (a line in the procedure beginning with a dollar sign [$]) or at the end of the command procedure file.
File—The end of an actual file has been reached.
Process the records in a loop (one record per iteration) and terminate the loop on end-of-file. LIB$GET_INPUT returns the error RMS$_EOF (defined in $RMSDEF) when end-of-file occurs.
! Return status and error codes INTEGER STATUS, 2 IOSTAT, 3 STATUS_OK, 4 IOSTAT_OK PARAMETER (STATUS_OK = 1, 2 IO_OK = 0) INCLUDE '($FORDEF)' ! Data record read on each iteration INTEGER INPUT_NUMBER ! Accumulated data records INTEGER STORAGE_COUNT, 2 STORAGE_MAX PARAMETER (STORAGE_MAX = 255) INTEGER STORAGE_NUMBER (STORAGE_MAX) ! Write instructions to interactive user TYPE *, 2 'Enter values below. Press CTRL/Z when done.' ! Get first input value WRITE (UNIT=*, 2 FMT='(A,$)') ' Input value: ' READ (UNIT=*, 2 IOSTAT=IOSTAT, 2 FMT='(BN,I)') INPUT_NUMBER IF (IOSTAT .EQ. IO_OK) THEN STATUS = STATUS_OK ELSE CALL ERRSNS (,,,,STATUS) END IF ! Process each input value until end-of-file DO WHILE ((STATUS .NE. FOR$_ENDDURREA) .AND. (STORAGE_COUNT .LT. STORAGE_MAX)) ! Keep repeating on conversion error DO WHILE (STATUS .EQ. FOR$_INPCONERR) WRITE (UNIT=*, 2 FMT='(A,$)') ' Try again: ' READ (UNIT=*, 2 IOSTAT=IOSTAT, 2 FMT='(BN,I)') INPUT_NUMBER IF (IOSTAT .EQ. IO_OK) THEN STATUS = STATUS_OK ELSE CALL ERRSNS (,,,,STATUS) END IF END DO ! Continue if end-of-file not entered IF (STATUS .NE. FOR$_ENDDURREA) THEN ! Status check on last read IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Store input numbers in input array STORAGE_COUNT = STORAGE_COUNT + 1 STORAGE_NUMBER (STORAGE_COUNT) = INPUT_NUMBER ! Get next input value WRITE (UNIT=*, 2 FMT='(A,$)') ' Input value: ' READ (UNIT=*, 2 IOSTAT=IOSTAT, 2 FMT='(BN,I)') INPUT_NUMBER IF (IOSTAT .EQ. IO_OK) THEN STATUS = STATUS_OK ELSE CALL ERRSNS (,,,,STATUS) END IF END IF END DO
6.3.4. Writing Simple Output
You can use LIB$PUT_OUTPUT to write character data. If you are writing noncharacter data, programming language I/O statements are preferable because they allow you to translate the data to a format of your choice.
LIB$PUT_OUTPUT writes one record of output to SYS$OUTPUT. Typically, you should avoid writing records that exceed the device width. The width of a terminal is 80 or 132 characters, depending on the setting of the physical characteristics of the device. The width of a line printer is 132 characters. If your output record exceeds the width of the device, the excess characters are either truncated or wrapped to the next line, depending on the setting of the physical characteristics.
You must define a value (a variable, constant, or expression) to be written. The value must be expressed in characters. You should specify the exact number of characters being written and not include the trailing portion of a variable.
INTEGER*4 STATUS, 2 LIB$PUT_OUTPUT CHARACTER*40 ANSWER INTEGER*4 ANSWER_SIZE . . . STATUS = LIB$PUT_OUTPUT ('Answer: ' // ANSWER (1:ANSWER_SIZE)) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
6.4. Working with Complex User I/O
The following sections present VSI DECwindows Motif for OpenVMS (DECwindows Motif), and the SMG$ run-time library routines that enable complex screen display I/O.
6.4.1. VSI DECwindows Motif
Toolkit composed on graphical user interface objects, such as widgets and gadgets. Widgets provide advanced programming capabilities that permit you to create graphic applications easily; gadgets, similar to widgets, require less memory to create labels, buttons, and separators.
Language to describe visual aspects of objects, such as menus, labels, and forms, and to specify changes resulting from user interaction.
OSF/Motif Window Manager to allow you to customize the interface.
VSI DECwindows Motif environment also makes available the LinkWorks services for creating, managing, and traversing informational links between different application-specific data. Along with the LinkWorks Manager application, LinkWorks services help organize information into a hyperinformation environment. LinkWorks Developer's Tools provide a development environment for creating, modifying, and maintaining hyperapplications.
6.4.1.1. DECwindows Server Height or Width Exceeding 32767 (VAX Only)
X error event received from server: BadValue (integer parameter out of range for operation) Major opcode of failed request: 61 (X_ClearArea) Value in failed request: 0xffff**** Serial number of failed request: ### Current serial number in output stream: ###
- CopyArea()
- CreateWindow ()
- PutImage()
- GetImage()
- CopyPlane()
- ClearArea()
This is due to the width and height being defined as a signed word by the display server when it should be defined as an unsigned word (CARD16) that allows for values up to 65536.
- Set the logical name DECW$CARD16_VALIDATE to TRUE as follows:
$DEFINE/TABLE=DECW$SERVER0_TABLE DECW$CARD16_VALIDATE TRUE
Exit the session and log back in.
Exiting the session causes the display server to reset using the new value of the logical name DECW$CARD16_VALIDATE. The server will now accept values that are greater than 32767 without generating an error.
To make this a permanent change, add the command from step 1 to the file SYS$MANAGER:DECW$PRIVATE_SERVER_SETUP.COM.
6.4.2. SMG$ Run-Time Routines
The SMG$ run-time library routines provide a simple, device-independent interface for managing the appearance of the terminal screen. The SMG$ routines are primarily for use with video terminals; however, they can be used with files or hardcopy terminals.
Create a pasteboard—A pasteboard is a logical, two-dimensional area on which you place virtual displays. Use the SMG$CREATE_PASTEBOARD routine to create a pasteboard, and associate it with a physical device. When you refer to the pasteboard, SMG performs the necessary I/O operation to the device.
Create a virtual display—A virtual display is a logical, two-dimensional area in which you place the information to be displayed. Use the SMG$CREATE_VIRTUAL_DISPLAY routine to create a virtual display.
Paste virtual displays to the pasteboard—To make a virtual display visible, map (or paste) it to the pasteboard using the SMG$PASTE_VIRTUAL_DISPLAY routine. You can reference a virtual display regardless of whether that display is currently pasted to a pasteboard.
Create a viewport for a virtual display—A view port is a rectangular viewing area that can be moved around on a buffer to view different pieces of the buffer. The viewport is associated with a virtual display.
. . . ! Screen management control structures INTEGER*4 PBID, ! Pasteboard ID 2 VDID, ! Virtual display ID 2 ROWS, ! Rows on screen 2 COLS ! Columns on screen ! Status variable and routines called as functions INTEGER*4 STATUS, 2 SMG$CREATE_PASTEBOARD, 2 SMG$CREATE_VIRTUAL_DISPLAY, 2 SMG$PASTE_VIRTUAL_DISPLAY ! Set up SYS$OUTPUT for screen management ! and get the number of rows and columns on the screen STATUS = SMG$CREATE_PASTEBOARD (PBID, ! Return value 2 'SYS$OUTPUT', 2 ROWS, ! Return value 2 COLUMNS) ! Return value IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Create virtual display that pastes to the full screen size STATUS = SMG$CREATE_VIRTUAL_DISPLAY (ROWS, 2 COLUMNS, 2 VDID) ! Return value IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Paste virtual display to pasteboard STATUS = SMG$PASTE_VIRTUAL_DISPLAY (VDID, 2 PBID, 2 1, ! Starting at row 1 and 2 1) ! column 1 of the screen IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . .
To use the SMG$ routines for input, you associate a virtual keyboard with a physical device or file using the SMG$CREATE_VIRTUAL_KEYBOARD routine. The SMG$input routines can be used alone or with the output routines. This section assumes that you are using the input routines with the output routines. Section 6.5, “Performing Special Input/Output Actions” describes how to use the input routines without the output routines.
The screen management facility keeps an internal representation of the screen contents; therefore, it is important that you do not mix SMG$ routines with other forms of terminal I/O. The following subsections contain guidelines for using most of the SMG$ routines; for more details, see the VSI OpenVMS RTL Screen Management (SMG$) Manual.
6.4.3. Pasteboards
STATUS = SMG$CREATE_PASTEBOARD (PBID, ROWS, COLUMNS) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
6.4.3.1. Erasing a Pasteboard
STATUS = SMG$ERASE_PASTEBOARD (PBID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
6.4.3.2. Deleting a Pasteboard
STATUS = SMG$DELETE_PASTEBOARD (PBID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
By default, the screen is erased when you create a pasteboard. Generally, you should erase the screen at the end of a session.
6.4.3.3. Setting Screen Dimensions and Background Color
. . . INTEGER*4 WIDTH, 2 COLOR INCLUDE '($SMGDEF)' ! Get current width and background color STATUS = SMG$CHANGE_PBD_CHARACTERISTICS (PBID,, 2 WIDTH,,,, 2 COLOR) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Change width and background color STATUS = SMG$CHANGE_PBD_CHARACTERISTICS (PBID, 2 132,,,, 2 SMG$C_COLOR_WHITE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . . ! Restore width and background color STATUS = SMG$CHANGE_PBD_CHARACTERISTICS (PBID, 2 WIDTH,,,, 2 COLOR) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
6.4.4. Virtual Displays
You write to virtual displays, which are logically configured as rectangles, by using the SMG$ routines. The dimensions of a virtual display are designated vertically as rows and horizontally as columns. A position in a virtual display is designated by naming a row and a column. Row and column numbers begin at 1.
6.4.4.1. Creating a Virtual Display
Use the SMG$CREATE_VIRTUAL_DISPLAY routine to create a virtual display. SMG$CREATE_VIRTUAL_DISPLAY returns a unique virtual display identification number; use that number to refer to the virtual display.
INCLUDE '($SMGDEF)' . . . STATUS = SMG$CREATE_VIRTUAL_DISPLAY (1, ! Rows 2 80, ! Columns 2 HEADER_VDID,, 2 SMG$M_BOLD)
STATUS = SMG$CREATE_VIRTUAL_DISPLAY (10, ! Rows 2 55, ! Columns 2 STATS_VDID, 2 SMG$M_BORDER) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$LABEL_BORDER (STATS_VDID, 2 'statistics') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$PASTE_VIRTUAL_DISPLAY (STATS_VDID, 2 PBID, 2 3, ! Row 2 2) ! Column
6.4.4.2. Pasting Virtual Displays
. . . INCLUDE '($SMGDEF)' INTEGER*4 PBID, 2 HEADER_VDID, 2 STATS_VDID INTEGER*4 STATUS, 2 SMG$CREATE_PASTEBOARD, 2 SMG$CREATE_VIRTUAL_DISPLAY, 2 SMG$PASTE_VIRTUAL_DISPLAY ! Create pasteboard for SYS$OUTPUT STATUS = SMG$CREATE_PASTEBOARD (PBID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Header pastes to first rows of screen STATUS = SMG$CREATE_VIRTUAL_DISPLAY (3, ! Rows 2 78, ! Columns 2 HEADER_VDID, ! Name 2 SMG$M_BORDER) ! Border IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$PASTE_VIRTUAL_DISPLAY (HEADER_VDID, 2 PBID, 2 2, ! Row 2 2) ! Column IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Statistics area pastes to rows 5 through 15, ! columns 2 through 56 STATUS = SMG$CREATE_VIRTUAL_DISPLAY (10, ! Rows 2 55, ! Columns 2 STATS_VDID, ! Name 2 SMG$M_BORDER) ! Border IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$PASTE_VIRTUAL_DISPLAY (STATS_VDID, 2 PBID, 2 5, ! Row 2 2) ! Column IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . .
Figure 6.1, “Defining and Pasting Virtual Displays” shows the screen that results from Example 6.6, “Defining and Pasting a Virtual Display”.

You can paste a single display to any number of pasteboards. Any time you change the display, all pasteboards containing the display are automatically updated.
A pasteboard can hold any number of virtual displays. You can paste virtual displays over one another to any depth, occluding the displays underneath. The displays underneath are only occluded to the extent that they are covered;that is, the parts not occluded remain visible on the screen. (In Figure 6.2, “Moving a Virtual Display”, displays 1 and 2 are partially occluded). When you unpaste a virtual display that occludes another virtual display, the occluded part of the display underneath becomes visible again.
STATUS = SMG$CHECK_FOR_OCCLUSION (STATS_VDID, 2 PBID, 2 OCCLUDE_STATE) ! OCCLUDE_STATE must be defined as INTEGER*4 IF (OCCLUDE_STATE) THEN STATUS = SMG$UNPASTE_VIRTUAL_DISPLAY (SUM_VDID, 2 PBID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ELSE STATUS = SMG$PASTE_VIRTUAL_DISPLAY (SUM_VDID, 2 PBID, 2 11, 2 2) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) END IF
6.4.4.3. Rearranging Virtual Displays
- Moving—To move a display, use the SMG$MOVE_VIRTUAL_DISPLAY routine. The following example moves display 2. Figure 6.2, “Moving a Virtual Display” shows the screen before and after the statement executes.
STATUS = SMG$MOVE_VIRTUAL_DISPLAY (VDID, 2 PBID, 2 5, 2 10) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
Figure 6.2. Moving a Virtual Display - Repasting—To repaste a display, use the SMG$REPASTE_VIRTUAL_DISPLAY routine. The following example repastes display 2. Figure 6.3, “Repasting a Virtual Display” shows the screen before and after the statement executes.
STATUS = SMG$REPASTE_VIRTUAL_DISPLAY (VDID, 2 PBID, 2 4, 2 4) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS))
Figure 6.3. Repasting a Virtual Display
You can obtain the pasting order of the virtual displays using SMG$LIST_PASTING_ORDER. This routine returns the identifiers of all the virtual displays pasted to a specified pasteboard.
6.4.4.4. Removing Virtual Displays
- Erase a virtual display—Invoking SMG$UNPASTE_VIRTUAL_DISPLAY erases a virtual display from the screen but retains its contents in memory. The following example erases the statistics display:
STATUS = SMG$UNPASTE_VIRTUAL_DISPLAY (STATS_VDID, 2 PBID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
- Delete a virtual display—Invoking SMG$DELETE_VIRTUAL_DISPLAY removes a virtual display from the screen and removes its contents from memory. The following example deletes the statistics display:
STATUS = SMG$DELETE_VIRTUAL_DISPLAY (STATS_VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
- Delete several virtual displays—Invoking SMG$POP_VIRTUAL_DISPLAY removes a specified virtual display and any virtual displays pasted after that display from the screen and removes the contents of those displays from memory. The following example “pops” display 2. Figure 6.4, “Popping a Virtual Display” shows the screen before and after popping. (Note that display 3 is deleted because it was pasted after display 2, and not because it is occluding display 2).
STATUS = SMG$POP_VIRTUAL_DISPLAY (STATS_VDID, 2 PBID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
Figure 6.4. Popping a Virtual Display
6.4.4.5. Modifying a Virtual Display
SMG$CHANGE_VIRTUAL_DISPLAY—Changes the size, video attributes, or border of a display
SMG$CHANGE_RENDITION—Changes the video attributes of a portion of a display
SMG$MOVE_TEXT—Moves text from one virtual display to another
STATUS = SMG$CHANGE_VIRTUAL_DISPLAY (WHOOPS_VDID,
2 5, ! Rows
2 7,, ! Columns
2 0) ! Video attributes off
STATUS = SMG$CHANGE_RENDITION (STATS_VDID, 2 1, ! Row 2 1, ! Column 2 10, ! Number of rows 2 20, ! Number of columns 2 , ! Video-set argument 2 SMG$M_REVERSE) ! Video-comp argument 2
rendition-set
argument of
SMG$CHANGE_RENDITION, and (3) the attributes
specified by the rendition-complement
argument of
SMG$CHANGE_RENDITION. Table 6.2, “Setting Video Attributes” shows
the result of each possible combination.
|
|
Result |
---|---|---|
off |
off |
Uses display default |
on |
off |
Sets attribute |
off |
on |
Uses the complement of display default |
on |
on |
Clears attribute |
In the preceding example, the reverse video attribute is set in the
rendition-complement
argument but not in the
rendition-set
argument, thus specifying that
SMG$CHANGE_RENDITION use the complement of the display's
default setting to ensure that the selected portion of the display is easily seen.
Note that the resulting attributes are based on the display's default attributes, not its current attributes. If you use SMG$ routines that explicitly set video attributes, the current attributes of the display may not match its default attributes.
6.4.4.6. Using Spawned Subprocesses
SMG$CREATE_SUBPROCESS—Creates a DCL spawned subprocess and associates it with a virtual display.
- SMG$EXECUTE_COMMAND—Allows execution of a specified command in the created spawned subprocess by using mailboxes. Some restrictions apply to specifying the following commands:
SPAWN, GOTO, or LOGOUT cannot be used and will result in unpredictable results.
Single-character commands such as Ctrl/C have no effect. You can signal an end-of-file (that is, press Ctrl/Z) command by setting the
flags
argument.A dollar sign ($) must be specified as the first character of any DCL command.
SMG$DELETE_SUBPROCESS—Deletes the subprocess created by SMG$CREATE_SUBPROCESS.
6.4.5. Viewports
Viewports allow you to view different pieces of a virtual display by moving a rectangular area around on the virtual display. Only one viewport is allowed for each virtual display. Once you have associated a viewport with a virtual display, the only part of the virtual display that is viewable is contained in the viewport.
SMG$CREATE_VIEWPORT—Creates a viewport and associates it with a virtual display. You must create the virtual display first. To view the viewport, you must paste the virtual display first with SMG$PASTE_VIRTUAL_DISPLAY.
SMG$SCROLL_VIEWPORT—Scrolls the viewport within the virtual display. If you try to move the viewport outside of the virtual display, the viewport is truncated to stay within the virtual display. This routine allows you to specify the direction and extent of the scroll.
SMG$CHANGE_VIEWPORT—Moves the viewport to a new starting location and changes the size of the viewport.
SMG$DELETE_VIEWPORT—Deletes the viewport and dissociates it from the virtual display. The viewport is automatically unpasted. The virtual display associated with the viewport remains intact. You can unpaste a viewport without deleting it by using SMG$UNPASTE_VIRTUAL_DISPLAY.
6.4.6. Writing Text to Virtual Display
The SMG$ output routines allow you to write text to displays and to delete or modify the existing text of a display. Remember that changes to a virtual display are visible only if the virtual display is pasted to a pasteboard.
6.4.6.1. Positioning the Cursor
SMG$HOME_CURSOR—Moves the cursor to a corner of the virtual display. The default corner is the upper left corner, that is, row 1, column 1 of the display.
SMG$SET_CURSOR_ABS—Moves the cursor to a specified row and column.
SMG$SET_CURSOR_REL—Moves the cursor to offsets from the current cursor position. A negative value means up (rows) or left (columns). A value of 0 means no movement.
In addition, many routines permit you to specify a starting location other than the current cursor position for the operation.
The SMG$RETURN_CURSOR_POS routine returns the row and column of the current cursor position within a virtual display. You do not have to write special code to track the cursor position.
Typically, the physical cursor is at the logical cursor position of the most recently written-to display. If necessary, you can use the SMG$SET_PHYSICAL_CURSOR routine to set the physical cursor location.
6.4.6.2. Writing Data Character by Character
SMG$DRAW_CHAR—Puts one line-drawing character on the screen at a specified position. It does not change the cursor position.
SMG$PUT_CHARS—Puts one or more characters on the screen at a specified position, with the option of one video attribute.
SMG$PUT_CHARS_MULTI—Puts several characters on the screen at a specified position, with multiple video attributes.
These routines are simple and precise. They place exactly the specified characters on the screen, starting at a specified position in a virtual display. Anything currently in the positions written-to is overwritten; no other positions on the screen are affected. Convert numeric data to character data with language I/O statements before invoking SMG$PUT_CHARS.
CHARACTER*4 HOUSE_NO_STRING
INTEGER*4 HOUSE_NO,
2 LINE_NO,
2 STATS_VDID
.
.
.
WRITE (UNIT=HOUSE_NO_STRING,
2 FMT='(I4)') HOUSE_NO
STATUS = SMG$PUT_CHARS (STATS_VDID,
2 HOUSE_NO_STRING,
2 LINE_NO, ! Row
2 1) ! Column
Note that the converted integer is right-justified from column 4 because the format specification is I4 and the full character string is written. To left-justify a converted number, you must locate the first nonblank character and write a substring starting with that character and ending with the last character.
Inserting and Overwriting Text
To insert characters rather than overwrite the current contents of the screen, use the routine SMG$INSERT_CHARS. Existing characters at the location written to are shifted to the right. Characters pushed out of the display are truncated; no wrapping occurs and the cursor remains at the end of the last character inserted.
Specifying Double-Size Characters
In addition to the preceding routines, you can use SMG$PUT_CHARS_WIDE to write characters to the screen in double width or SMG$PUT_CHARS_HIGHWIDE to write characters to the screen in double height and double width. When you use these routines, you must allot two spaces for each double-width character on the line and two lines for each line of double-height characters. You cannot mix single-and double-size characters on a line.
All the character routines provide rendition-set
and
rendition-complement
arguments, which allow you to specify
special video attributes for the characters being written.
SMG$PUT_CHARS_MULTI allows you to specify more than one video
attribute at a time. The explanation of the SMG$CHANGE_RENDITION
routine in Section 6.4.4.5, “Modifying a Virtual Display” discusses how to use
rendition-set
and rendition-complement
arguments.
6.4.6.3. Writing Data Line by Line
The SMG$PUT_LINE and SMG$PUT_LINE_MULTI routines write lines to virtual displays one line after another. If the display area is full, it is scrolled. You do not have to keep track of which line you are on. All routines permit you to scroll forward (up); SMG$PUT_LINE and SMG$PUT_LINE_MULTI permit you to scroll backward (down) as well. SMG$PUT_LINE permits spacing other than single spacing.
INTEGER*4 BUFF_COUNT, 2 BUFF_SIZE (4096) CHARACTER*512 BUFF (4096) . . . DO I = 1, BUFF_COUNT STATUS = SMG$PUT_LINE (VDID, 2 BUFF (I) (1:BUFF_SIZE (I))) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) END DO
DO I = BUFF_COUNT, 1, -1 STATUS = SMG$PUT_LINE (VDID, 2 BUFF (I) (1:BUFF_SIZE (I)), 2 SMG$M_DOWN) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) END DO
Cursor Movement and Scrolling
To maintain precise control over cursor movement and scrolling, you can write with SMG$PUT_CHARS and scroll explicitly with SMG$SCROLL_DISPLAY_AREA.SMG$PUT_CHARS leaves the cursor after the last character written and does not force scrolling; SMG$SCROLL_DISPLAY_AREA scrolls the current contents of the display forward, backward, or sideways without writing to the display. To restrict the scrolling region to a portion of the display area, use the SMG$SET_DISPLAY_SCROLL_REGION routine.
Inserting and Overwriting Text
To insert text rather than overwrite the current contents of the screen, use the SMG$INSERT_LINE routine. Existing lines are shifted up or down to open space for the new text. If the text is longer than a single line, you can specify whether or not you want the excess characters to be truncated or wrapped.
Using Double-Width Characters
In addition, you can use SMG$PUT_LINE_WIDE to write a line of text to the screen using double-width characters. You must allot two spaces for each double-width character on the line. You cannot mix single- and double-width characters on a line.
Specifying Special Video Attributes
All line routines provide rendition-set
and
rendition-complement
arguments, which allow you to specify
special video attributes for the text being written.
SMG$PUT_LINE_MULTI allows you to specify more than one video
attribute for the text. The explanation of the
SMG$CHANGE_RENDITION routine in Section 6.4.4.5, “Modifying a Virtual Display” discusses how to use the rendition-set
and
rendition-complement
arguments.
6.4.6.4. Drawing Lines
The routine SMG$DRAW_LINE draws solid lines on the screen. Appropriate corner and crossing marks are drawn when lines join or intersect. The routine SMG$DRAW_CHARACTER draws a single character. You can also use the routine SMG$DRAW_RECTANGLE to draw a solid rectangle. Suppose that you want to draw an object such as that shown in Figure 6.5, “Statistics Display” in the statistics display area (an area of 10 rows by 55 columns).

STATUS = SMG$CREATE_VIRTUAL_DISPLAY (10, 2 55, 2 STATS_VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Draw rectangle with upper left corner at row 1 column 1 ! and lower right corner at row 10 column 55 STATUS =SMG$DRAW_RECTANGLE (STATS_VDID, 2 1, 1, 2 10, 55) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Draw vertical lines at columns 11, 21, and 31 DO I = 11, 31, 10 STATUS = SMG$DRAW_LINE (STATS_VDID, 2 1, I, 2 10, I) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) END DO ! Draw horizontal line at row 3 STATUS = SMG$DRAW_LINE (STATS_VDID, 2 3, 1, 2 3, 55) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$PASTE_VIRTUAL_DISPLAY (STATS_VDID, 2 PBID, 2 3, 2 2) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
6.4.6.5. Deleting Text
SMG$ERASE_CHARS—Erases specified characters on one line.
SMG$ERASE_LINE—Erases the characters on one line starting from a specified position.
SMG$ERASE_DISPLAY—Erases specified characters on one or more lines.
SMG$ERASE_COLUMN—Erases a column from the specified row to the end of the column from the virtual display.
SMG$DELETE_CHARS—Deletes specified characters on one line. Any characters to the right of the deleted characters are shifted left.
SMG$DELETE_LINE—Deletes one or more full lines. Any remaining lines in the display are scrolled up to fill the empty space.
STATUS = SMG$ERASE_LINE (STATS_VDID, 2 LINE_NO, 2 COLUMN_NO) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
6.4.7. Using Menus
Block menu—Selections are in matrix format. This is the type of menu often used.
Vertical menu—Each selection is on its own line.
Horizontal menu—All selections are on one line.
Menus are associated with a virtual display, and only one menu can be used for each virtual display.
SMG$CREATE_MENU—Creates a menu associated with a virtual display. This routine allows you to specify the type of menu, the position in which the menu is displayed, the format of the menu (single or double spaced), and video attributes.
SMG$SELECT_FROM_MENU—Sets up menu selection capability. You can specify a default menu selection (which is shown in reverse video), whether online help is available, a maximum time limit for making a menu selection, a key indicating read termination, whether to send the text of the menu item selected to a string, and a video attribute.
SMG$DELETE_MENU—Discontinues access to the menu and erases it.
When you are using menus, no other output should be sent to the menu area;otherwise, unpredictable results may occur.
The default SMG$SELECT_FROM_MENU allows specific operations,
such as use of the arrow keys to move up and down the menu selections, keys to make a menu
selection, ability to select more than one item at a time, ability to reselect an item
already selected, and the key sequence to invoke online help. By using the
flags
argument to modify this operation, you have the option of
disallowing reselection of a menu item and of allowing any key pressed to select an
item.
6.4.8. Reading Data
You can read text from a virtual display (SMG$READ_FROM_DISPLAY) or from a virtual keyboard (SMG$READ_STRING, SMG$READ_COMPOSED_LINE, or SMG$READ_KEYSTROKE). The three routines for virtual keyboard input are known as the SMG$ input routines. SMG$READ_FROM_DISPLAY is not a true input routine because it reads text from the virtual display rather than from a user.
The SMG$ input routines can be used alone or with the SMG$ output routines. This section assumes that you are using the input routines with the output routines. Section 6.5, “Performing Special Input/Output Actions” describes how to use the input routines without the output routines.
When you use the SMG$ input routines with the
SMG$ output routines, always specify the optional
vdid
argument of the input routine, which specifies the virtual
display in which the input is to occur. The specified virtual display must be pasted to the
device associated with the virtual keyboard that is specified as the first argument of the
input routine. The display must be pasted in column 1, cannot be occluded, and cannot have
any other display to its right; input begins at the current cursor position, but the cursor
must be in column 1.
6.4.8.1. Reading from a Display
You can read the contents of the display using the routine
SMG$READ_FROM_DISPLAY. By default, the read operation reads all
of the characters from the current cursor position to the end of that line. The
row
argument of SMG$READ_FROM_DISPLAY
allows you to choose the starting point of the read operation, that is, the contents of
the specified row to the rightmost column in that row.
If the terminator-string
argument is specified,
SMG$READ_FROM_DISPLAY searches backward from the current cursor
position and reads the line beginning at the first terminator
encountered (or at the beginning of the line). A terminator is a character string. You
must calculate the length of the character string read operation yourself.
CHARACTER*4 STRING INTEGER*4 SIZE . . . STATUS = SMG$HOME_CURSOR (STATS_VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) STATUS = SMG$READ_FROM_DISPLAY (STATS_VDID, 2 STRING) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) SIZE = 55 DO WHILE ((STRING (SIZE:SIZE) .EQ. ' ') .AND. 2 (SIZE .GT. 1)) SIZE = SIZE - 1 END DO
6.4.8.2. Reading from a Virtual Keyboard
The SMG$CREATE_VIRTUAL_KEYBOARD routine establishes a device for input operations; the default device is the user's terminal. The routine SMG$READ_STRING reads characters typed on the screen either until the user types a terminator or until the maximum size (which defaults to 512 characters) is exceeded. (The terminator is usually a carriage return; see the routine description in the VSI OpenVMS RTL Screen Management (SMG$) Manual for a complete list of terminators). The current cursor location for the display determines where the read operation begins.
The operating system's terminal driver processes carriage returns differently than the SMG$routines. Therefore, in order to scroll input accurately, you must keep track of your vertical position in the display area. Explicitly set the cursor position and scroll the display. If a read operation takes place on a row other than the last row of the display, advance the cursor to the beginning of the next row before the next operation. If a read operation takes place on the last row of the display, scroll the display with SMG$SCROLL_DISPLAY_AREA and then set the cursor to the beginning of the row. Modify the read operation with TRM$M_TM_NOTRMECHO to ensure that no extraneous scrolling occurs.
. . . ! Read first record STATUS = SMG$HOME_CURSOR (VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$READ_STRING (KBID, 2 TEXT, 2 'Prompt: ', 2 4, 2 TRM$M_TM_TRMNOECHO,,, 2 TEXT_SIZE,, 2 VDID) ! Read remaining records until CTRL/Z DO WHILE (STATUS .NE. SMG$_EOF) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Process record . . . ! Set up screen for next read ! Display area contains four rows STATUS = SMG$RETURN_CURSOR_POS (VDID, ROW, COL) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) IF (ROW .EQ. 4) THEN STATUS = SMG$SCROLL_DISPLAY_AREA (VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$SET_CURSOR_ABS (VDID, 4, 1) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ELSE STATUS = SMG$SET_CURSOR_ABS (VDID,, 1) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$SET_CURSOR_REL (VDID, 1) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) END IF ! Read next record STATUS = SMG$READ_STRING (KBID, 2 TEXT, 2 'Prompt: ', 2 4, 2 TRM$M_TM_TRMNOECHO,,, 2 TEXT_SIZE,, 2 VDID) END DO
Note
Because you are controlling the scrolling, SMG$PUT_LINE and SMG$PUT_LINE_MULTI might not scroll as expected. When scrolling a mix of input and output, you can prevent problems by using SMG$PUT_CHARS.
6.4.8.3. Reading from the Keypad
To read from the keypad in keypad mode (that is, pressing a keypad character to perform some special action rather than entering data), modify the read operation with TRM$M_TM_ESCAPE and TRM$M_TM_NOECHO. Examine the terminator to determine which key was pressed.
Example 6.11, “Reading Data from the Keypad” moves the cursor on the screen in response to the user's pressing the keys surrounding the keypad 5 key. The keypad 8 key moves the cursor north (up); the keypad 9 key moves the cursor northeast; the keypad 6 key moves the cursor east (right); and so on. The SMG$SET_CURSOR_REL routine is called, instead of being invoked as a function, because you do not want to abort the program on an error. (The error attempts to move the cursor out of the display area and, if this error occurs, you do not want the cursor to move.) The read operation is also modified with TRM$M_TM_PURGE to prevent the user from getting ahead of the cursor.
. . . INTEGER STATUS, 2 PBID, 2 ROWS, 2 COLUMNS, 2 VDID, ! Virtual display ID 2 KID, ! Keyboard ID 2 SMG$CREATE_PASTEBOARD, 2 SMG$CREATE_VIRTUAL_DISPLAY, 2 SMG$CREATE_VIRTUAL_KEYBOARD, 2 SMG$PASTE_VIRTUAL_DISPLAY, 2 SMG$HOME_CURSOR, 2 SMG$SET_CURSOR_REL, 2 SMG$READ_STRING, 2 SMG$ERASE_PASTEBOARD, 2 SMG$PUT_CHARS, 2 SMG$READ_FROM_DISPLAY CHARACTER*31 INPUT_STRING, 2 MENU_STRING INTEGER*2 TERMINATOR INTEGER*4 MODIFIERS INCLUDE '($SMGDEF)' INCLUDE '($TRMDEF)' ! Set up screen and keyboard STATUS = SMG$CREATE_PASTEBOARD (PBID, 2 'SYS$OUTPUT', 2 ROWS, 2 COLUMNS) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$CREATE_VIRTUAL_DISPLAY (ROWS, 2 COLUMNS, 2 VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$PUT_CHARS (VDID, 2 '__ MENU CHOICE ONE', 2 10,30) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$PUT_CHARS (VDID, 2 '__ MENU CHOICE TWO', 2 15,30) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$CREATE_VIRTUAL_KEYBOARD (KID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$PASTE_VIRTUAL_DISPLAY (VDID, 2 PBID, 2 1, 2 1) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Put cursor in NW corner STATUS = SMG$HOME_CURSOR (VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Read character from keyboard MODIFIERS = TRM$M_TM_ESCAPE .OR. 2 TRM$M_TM_NOECHO .OR. 2 TRM$M_TM_PURGE STATUS = SMG$READ_STRING (KID, 2 INPUT_STRING, 2 , 2 6, 2 MODIFIERS, 2 , 2 , 2 , 2 TERMINATOR) DO WHILE ((STATUS) .AND. 2 (TERMINATOR .NE. SMG$K_TRM_CR)) ! Check status of last read IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! North IF (TERMINATOR .EQ. SMG$K_TRM_KP8) THEN CALL SMG$SET_CURSOR_REL (VDID, -1, 0) ! Northeast ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP9) THEN CALL SMG$SET_CURSOR_REL (VDID, -1, 1) ! Northwest ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP7) THEN CALL SMG$SET_CURSOR_REL (VDID, -1, -1) ! South ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP2) THEN CALL SMG$SET_CURSOR_REL (VDID, 1, 0) ! Southeast ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP3) THEN CALL SMG$SET_CURSOR_REL (VDID, 1, 1) ! Southwest ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP1) THEN CALL SMG$SET_CURSOR_REL (VDID, 1, -1) ! East ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP6) THEN CALL SMG$SET_CURSOR_REL (VDID, 0, 1) ! West ELSE IF (TERMINATOR .EQ. SMG$K_TRM_KP4) THEN CALL SMG$SET_CURSOR_REL (VDID, 0, -1) END IF ! Read another character STATUS = SMG$READ_STRING (KID, 2 INPUT_STRING, 2 , 2 6, 2 MODIFIERS, 2 , 2 , 2 , 2 TERMINATOR) END DO ! Read menu entry and process ! STATUS = SMG$READ_FROM_DISPLAY (VDID, 2 MENU_STRING) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . . ! Clear screen STATUS = SMG$ERASE_PASTEBOARD (PBID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) END
6.4.8.4. Reading Composed Input
If states—You can define the same key to mean different things indifferent states. You can define a key to cause a change in state. The change in state can be temporary (until after the next defined key is pressed) or permanent (until a key that changes states is pressed).
Input termination—You can define the key to cause termination of the input transmission (as if the Return key were pressed after the character string). If the key is not defined to cause termination of the input, the user must press a terminator or another key that does cause termination.
INTEGER*4 TABLEID . . . ! Create table for key definitions STATUS = SMG$CREATE_KEY_TABLE (TABLEID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Load table ! If user presses PF1, the state changes to BYTEN ! The BYTEN state is in effect only for the very next key STATUS = SMG$ADD_KEY_DEF (TABLEID, 2 'PF1', 2 ,,,'BYTEN') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Pressing KP1 through Kp9 in the null state is like typing ! 1000 through 9000 and pressing return STATUS = SMG$ADD_KEY_DEF (TABLEID, 2 'KP1', 2 , 2 SMG$M_KEY_TERMINATE, 2 '1000') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$ADD_KEY_DEF (TABLEID, 2 'KP2', 2 , 2 SMG$M_KEY_TERMINATE, 2 '2000') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . . STATUS = SMG$ADD_KEY_DEF (TABLEID, 2 'KP9', 2 , 2 SMG$M_KEY_TERMINATE, 2 '9000') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Pressing KP1 through KP9 in the BYTEN state is like ! typing 10000 through 90000 and pressing return STATUS = SMG$ADD_KEY_DEF (TABLEID, 2 'KP1', 2 'BYTEN', 2 SMG$M_KEY_TERMINATE, 2 '10000') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$ADD_KEY_DEF (TABLEID, 2 'KP2', 2 'BYTEN', 2 SMG$M_KEY_TERMINATE, 2 '20000') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . . STATUS = SMG$ADD_KEY_DEF (TABLEID, 2 'KP9', 2 'BYTEN', 2 SMG$M_KEY_TERMINATE, 2 '90000') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! End loading key definition table . . . ! Read input which substitutes key definitions where appropriate STATUS = SMG$READ_COMPOSED_LINE (KBID, 2 TABLEID, 2 STRING, 2 SIZE, 2 VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . .
Use the SMG$DELETE_KEY_DEF routine to delete a key definition; use the SMG$GET_KEY_DEF routine to examine a key definition. You can also load key definition tables with the SMG$DEFINE_KEY and SMG$LOAD_KEY_DEFS routines; use the DCL command DEFINE/KEY to specify input to these routines.
To use keypad keys 0 through 9, the keypad must be in application mode. For details, see SMG$SET_KEYPAD_MODE in the VSI OpenVMS RTL Screen Management (SMG$) Manual.
6.4.9. Controlling Screen Updates
If your program needs to make a number of changes to a virtual display, you can use SMG$ routines to make all of the changes before updating the display. The SMG$BEGIN_DISPLAY_UPDATE routine causes output operations to a pasted display to be reflected only in the display's buffers. The SMG$END_DISPLAY_UPDATE routine writes the display's buffer to the pasteboard.
The SMG$BEGIN_DISPLAY_UPDATE and SMG$END_DISPLAY_UPDATE routines increment and decrement a counter. When this counter's value is 0, output to the virtual display is sent to the pasteboard immediately. The counter mechanism allows a subroutine to request and turn off batching without disturbing the batching state of the calling program.
A second set of routines, SMG$BEGIN_PASTEBOARD_UPDATE and SMG$END_PASTEBOARD_UPDATE, allow you to buffer output to a pasteboard in asimilar manner.
6.4.10. Maintaining Modularity
Mixing SMG I/O and other forms of I/O
In general, do not use any other form of terminal I/O while the terminal is active as a pasteboard. If you do use I/O other than SMG I/O (for example, if you invoke a subprogram that may perform non-SMG terminal I/O), first invoke the SMG$SAVE_PHYSICAL_SCREEN routine and when the non-SMG I/O completes, invoke the SMG$RESTORE_PHYSICAL_SCREEN routine, as demonstrated in the following example:STATUS = SMG$SAVE_PHYSICAL_SCREEN (PBID, 2 SAVE_VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) CALL GET_EXTRA_INFO (INFO_ARRAY) STATUS = SMG$RESTORE_PHYSICAL_SCREEN (PBID, 2 SAVE_VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
Sharing the pasteboard
A routine using the terminal screen without consideration for its current contents must use the existing pasteboard ID associated with the terminal and delete any virtual displays it creates before returning control to the high-level code. This guideline also applies to the program unit that invokes a subprogram that also performs screen I/O. The safest way to clean up your virtual displays is to call the SMG$POP_VIRTUAL_DISPLAY routine and name the first virtual display you created. The following example invokes a subprogram that uses the terminal screen:
Invoking Program Unit
CALL GET_EXTRA_INFO (PBID, 2 INFO_ARRAY) . . . CALL STATUS = SMG$CREATE_PASTEBOARD (PBID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
Subprogram
SUBROUTINE GET_EXTRA_INFO (PBID, 2 INFO_ARRAY) . . . ! Start executable code STATUS = SMG$CREATE_VIRTUAL_DISPLAY (4, 2 40, 2 INSTR_VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$PASTE_VIRTUAL_DISPLAY (INSTR_VDID, 2 PBID, 1, 1) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . . STATUS = SMG$POP_VIRTUAL_DISPLAY (INSTR_VDID, 2 PBID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) END
Sharing virtual displays
To share a virtual display created by high-level code, the low-level code must use the virtual display ID created by the high-level code; an invoking program unit must pass the virtual display ID to the subprogram. To share a virtual display created by low-level code, the high-level code must use the virtual display ID created by the low-level code; a subprogram must return the virtual display ID to the invoking program.
The following example permits a subprogram to use a virtual display created by the invoking program unit:
Invoking Program Unit
STATUS = SMG$CREATE_VIRTUAL_DISPLAY (4, 2 40, 2 INSTR_VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$PASTE_VIRTUAL_DISPLAY (INSTR_VDID, 2 PBID, 1, 1) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) CALL GET_EXTRA_INFO (PBID, 2 INSTR_VDID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
Subprogram
SUBROUTINE GET_EXTRA_INFO (PBID, 2 INSTR_VDID)
6.5. Performing Special Input/Output Actions
Screen management input routines and the SYS$QIO and SYS$QIOW system services allow you to perform I/O operations otherwise unavailable to high-level languages. For example, you can allow a user to interrupt normal program execution by typing a character and by providing a mechanism for reading that character. You can also control such things as echoing, time allowed for input, and whether data is read from the type-ahead buffer.
Some of the operations described in the following sections require the use of the SYS$QIO or SYS$QIOW system services. For more information about the QIO system services, see the VSI OpenVMS System Services Reference Manual and Chapter 7, System Service Input/Output Operations.
Call SMG$CREATE_VIRTUAL_KEYBOARD to associate a logical keyboard with a device or file specification (SYS$INPUT by default). SMG$CREATE_VIRTUAL_KEYBOARD returns a keyboard identification number; use that number to identify the device or file to the SMG$ input routines.
Call an SMG$ input routine (SMG$READ_STRING or SMG$READ_COMPOSED_LINE) to read data typed at the device associated with the virtual keyboard.
When using the SMG$ input routines without the SMG$ output routines, do not specify the optional VDID argument of the input routine.
6.5.1. Using Ctrl/C and Ctrl/Y Interrupts
Queue an asynchronous system trap (AST)—Issue the SYS$QIO or SYS$QIOW system service with a function code of IO$_SETMODE modified by either IO$M_CTRLCAST (for Ctrl/C interrupts) or IO$M_CTRLYAST (for Ctrl/Y interrupts). For the
P1
argument, provide the name of a subroutine to be executed when the interrupt occurs. For theP2
argument, you can optionally identify one longword argument to pass to the AST subroutine.Write an AST subroutine—Write the subroutine identified in the
P1
argument of the QIO system service and link the subroutine into your program. Your subroutine can take one longword dummy argument to be associated with theP2
argument in the QIO system service. You must define common areas to access any other data in your program from the AST routine.
ASTs are asynchronous—Since your AST subroutine does not know exactly where you are in your program when the interrupt occurs, you should avoid manipulating data or performing other mainline activities. In general, the AST subroutine should either notify the mainline code (for example, by setting a flag) that the interrupt occurred, or clean up and exit from the program (if that is what you want to do).
ASTs need new channels to the terminal—If you try to access the terminal with language I/O statements using SYS$INPUT or SYS$OUTPUT, you may receive a redundant I/O error. You must establish another channel to the terminal by explicitly opening the terminal.
Ctrl/C and Ctrl/Y ASTs are one-time ASTs—After a Ctrl/C or Ctrl/Y AST is delivered, it is dequeued. You must reissue the QIO system service if you wish to trap another interrupt.
Many ASTs can be queued—You can queue multiple ASTs (for the same or different AST subroutines, on the same or different channels) by issuing the appropriate number of QIO system services. The system delivers the ASTs on a last-in, first-out (LIFO) basis.
Unhandled Ctrl/Cs turn into Ctrl/Ys—If the user enters Ctrl/C and you do not have an AST queued to handle the interrupt, the system turns the Ctrl/C interrupt into a Ctrl/Y interrupt.
- DCL handles Ctrl/Y interrupts—DCL handles Ctrl/Y interrupts by returning the user to DCL command level, where the user has the option of continuing or exiting from your program. DCL takes precedence over your AST subroutine for Ctrl/Y interrupts. Your Ctrl/Y AST subroutine is executed only under the following circumstances:
If Ctrl/Y interrupts are disabled at DCL level (SETNOCONTROL_Y) before your program is executed
If your program disables DCL Ctrl/Y interrupts with LIB$DISABLE_CTRL
If the user elects to continue your program after DCL interrupts it
You can dequeue Ctrl/C and Ctrl/Y ASTs—You can dequeue all Ctrl/C or Ctrl/Y ASTs on a channel by issuing the appropriate QIO system service with a value of 0 for the
P1
argument (passed by immediate value). You can dequeue all Ctrl/C ASTs on a channel by issuing the SYS$CANCEL system service for the appropriate channel. You can dequeue all Ctrl/Y ASTs on a channel by issuing the SYS$DASSGN system service for the appropriate channel.You can use SMG$ routines—You can connect to the terminal using the SMG$routines from either AST level or mainline code. Do not attempt to connect to the terminal from AST level if you do so in your mainline code.
!Main Program . . . INTEGER STATUS ! Accumulated data records CHARACTER*132 STORAGE (255) INTEGER*4 STORAGE_SIZE (255), 2 STORAGE_COUNT ! QIOW and QIO structures INTEGER*2 INPUT_CHAN INTEGER*4 CODE STRUCTURE /IOSTAT_BLOCK/ INTEGER*2 IOSTAT BYTE TRANSMIT, 2 RECEIVE, 2 CRFILL, 2 LFFILL, 2 PARITY, 2 ZERO END STRUCTURE RECORD /IOSTAT_BLOCK/ IOSB ! Flag to notify program of CTRL/C interrupt LOGICAL*4 CTRLC_CALLED ! AST subroutine to handle CTRL/C interrupt EXTERNAL CTRLC_AST ! Subroutines INTEGER SYS$ASSIGN, 2 SYS$QIOW ! Symbols used for I/O operations INCLUDE '($IODEF)' ! Put values into array CALL LOAD_STORAGE (STORAGE, 2 STORAGE_SIZE, 2 STORAGE_COUNT) ! Assign channel and set up QIOW structures STATUS = SYS$ASSIGN ('SYS$INPUT', 2 INPUT_CHAN,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) CODE = IO$_SETMODE .OR. IO$M_CTRLCAST ! Queue an AST to handle CTRL/C interrupt STATUS = SYS$QIOW (, 2 %VAL (INPUT_CHAN), 2 %VAL (CODE), 2 IOSB, 2 ,, 2 CTRLC_AST, ! Name of AST routine 2 CTRLC_CALLED, ! Argument for AST routine 2 ,,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) IF (.NOT. IOSB.IOSTAT) 2 CALL LIB$SIGNAL (%VAL (IOSB.IOSTAT)) ! Display STORAGE array, one element per line DO I = 1, STORAGE_COUNT TYPE *, STORAGE (I) (1:STORAGE_SIZE (I)) ! Additional actions if user types CTRL/C IF (CTRLC_CALLED) THEN CTRLC_CALLED = .FALSE. ! Show user number of lines displayed so far TYPE *, 'Number of lines: ', I ! Requeue AST STATUS = SYS$QIOW (, 2 %VAL (INPUT_CHAN), 2 %VAL (CODE), 2 IOSB, 2 ,, 2 CTRLC_AST, 2 CTRLC_CALLED, 2 ,,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) IF (.NOT. IOSB.IOSTAT) 2 CALL LIB$SIGNAL (%VAL (IOSB.IOSTAT)) END IF END DO END
AST Routine
! AST routine ! Notifies program that user typed CTRL/C SUBROUTINE CTRLC_AST (CTRLC_CALLED) LOGICAL*4 CTRLC_CALLED CTRLC_CALLED = .TRUE. END
6.5.2. Detecting Unsolicited Input
You can detect input from the terminal even if you have not called SMG$READ_COMPOSED_LINE or SMG$READ_STRING by using SMG$ENABLE_UNSOLICITED_INPUT. This routine uses the AST mechanism to transfer control to a subprogram of your choice each time the user types at the terminal; the AST subprogram is responsible for reading any input. When the subprogram completes, control returns to the point in your mainline code where it was interrupted.
The SMG$ENABLE_UNSOLICITED_INPUT routine is not an SMG$ input routine. Before invoking SMG$ENABLE_UNSOLICITED_INPUT, you must invoke SMG$CREATE_PASTEBOARD to associate a pasteboard with the terminal and SMG$CREATE_VIRTUAL_KEYBOARD to associate a virtual keyboard with the same terminal.
The pasteboard identification number (use the value returned by SMG$CREATE_PASTEBOARD)
The name of an AST subprogram
An argument to be passed to the AST subprogram
When SMG$ENABLE_UNSOLICITED_INPUT invokes the AST subprogram, it passes two arguments to the subprogram: the pasteboard identification number and the argument that you specified. Typically, you write the AST subprogram to read the unsolicited input with SMG$READ_STRING. Since SMG$READ_STRING requires that you specify the virtual keyboard at which the input was typed, specify the virtual keyboard identification number as the second argument to pass to the AST subprogram.
! Main Program ! The main program calls DISPLAY_ARRAY once for each array. ! DISPLAY_ARRAY displays the array in a DO loop. ! If the user enters input from the terminal, the loop is ! interrupted and the AST routine takes over. ! If the user types anything beginning with an N, the AST ! sets DO_NEXT and resumes execution -- DISPLAY_ARRAY drops ! out of the loop processing the array (because DO_NEXT is ! set -- and the main program calls DISPLAY_ARRAY for the ! next array. ! If the user types anything not beginning with an N, ! the program exits. . . . INTEGER*4 STATUS, 2 VKID, ! Virtual keyboard ID 2 PBID ! Pasteboard ID ! Storage arrays INTEGER*4 ARRAY1 (256), 2 ARRAY2 (256), 2 ARRAY3 (256) ! System routines INTEGER*4 SMG$CREATE_PASTEBOARD, 2 SMG$CREATE_VIRTUAL_KEYBOARD, 2 SMG$ENABLE_UNSOLICITED_INPUT ! AST routine EXTERNAL AST_ROUTINE ! Create a pasteboard STATUS = SMG$CREATE_PASTEBOARD (PBID, ! Pasteboard ID 2 'SYS$INPUT') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Create a keyboard for the same device STATUS = SMG$CREATE_VIRTUAL_KEYBOARD (VKID, ! Keyboard ID 2 'SYS$INPUT') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Enable unsolicited input STATUS = SMG$ENABLE_UNSOLICITED_INPUT (PBID, ! Pasteboard ID 2 AST_ROUTINE, 2 VKID) ! Pass keyboard ! ID to AST IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . . ! Call display subroutine once for each array CALL DISPLAY_ARRAY (ARRAY1) CALL DISPLAY_ARRAY (ARRAY2) CALL DISPLAY_ARRAY (ARRAY3) END
Array Display Routine
! Subroutine to display one array SUBROUTINE DISPLAY_ARRAY (ARRAY) ! Dummy argument INTEGER*4 ARRAY (256) ! Status INTEGER*4 STATUS ! Flag for doing next array LOGICAL*4 DO_NEXT COMMON /DO_NEXT/ DO_NEXT ! If AST has been delivered, reset IF (DO_NEXT) DO_NEXT = .FALSE. ! Initialize control variable I = 1 ! Display entire array unless interrupted by user ! If interrupted by user (DO_NEXT is set), drop out of loop DO WHILE ((I .LE. 256) .AND. (.NOT. DO_NEXT)) TYPE *, ARRAY (I) I = I + 1 END DO END
AST Routine
! Subroutine to read unsolicited input SUBROUTINE AST_ROUTINE (PBID, 2 VKID) ! dummy arguments INTEGER*4 PBID, ! Pasteboard ID 2 VKID ! Keyboard ID ! Status INTEGER*4 STATUS ! Flag for doing next array LOGICAL*4 DO_NEXT COMMON /DO_NEXT/ DO_NEXT ! Input string CHARACTER*4 INPUT ! Routines INTEGER*4 SMG$READ_STRING ! Read input STATUS = SMG$READ_STRING (VKID, ! Keyboard ID 2 INPUT) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! If user types anything beginning with N, set DO_NEXT ! otherwise, exit from program IF (INPUT (1:1) .EQ. 'N') THEN DO_NEXT = .TRUE. ELSE CALL EXIT END IF END
6.5.3. Using the Type-Ahead Buffer
Normally, if the user types at the terminal before your application is able to read from that device, the input is saved in a special data structure maintained by the system called the type-ahead buffer. When your application is ready to read from the terminal, the input is transferred from the type-ahead buffer to your input buffer. The type-ahead buffer is preset at a size of 78 bytes. If the HOSTSYNC characteristic is on (the usual condition), input to the type-ahead buffer is stopped (the keyboard locks) when the buffer is within 8 bytes of being full. If the HOSTSYNC characteristic is off, the bell rings when the type-ahead buffer is within 8 bytes of being full; if you overflow the buffer, the excess data is lost. The TTY_ALTALARM system parameter determines the point at which either input is stopped or the bell rings.
modifiers
argument.
Clearing the type-ahead buffer has the effect of reading only what the user types on the
terminal after the read operation is invoked. Any characters in the type-ahead buffer are
lost. The following example illustrates how to purge the type-ahead
buffer:INTEGER*4 SMG$CREATE_VIRTUAL_KEYBOARD, 2 SMG$READ_STRING, 2 STATUS, 2 VKID, ! Virtual keyboard ID 2 INPUT_SIZE CHARACTER*512 INPUT INCLUDE '($TRMDEF)' STATUS = SMG$CREATE_VIRTUAL_KEYBOARD (VKID, 2 'SYS$INPUT') ! I/O device IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$READ_STRING (VKID, ! Keyboard ID 2 INPUT, ! Data read 2 'Prompt> ', 2 512, 2 TRM$M_TM_PURGE, 2 ,, 2 INPUT_SIZE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
You can also clear the type-ahead buffer with a QIO read operation modified by IO$M_PURGE (defined in $IODEF). You can turn off the type-ahead buffer for further read operations with a QIO set mode operation that specifies TT$M_NOTYPEAHD as a basic terminal characteristic.
You can examine the type-ahead buffer by issuing a QIO sense mode operation modified by
IO$M_TYPEAHDCNT. The number of characters in the type-ahead
buffer and the value of the first character are returned to the P1
argument.
The size of the type-ahead buffer is determined by the TTY_TYPAHDSZ system parameter. You can specify an alternative type-ahead buffer by turning on the ALTYPEAHD terminal characteristic; the size of the alternative type-ahead buffer is determined by the TTY_ALTYPAHD system parameter.
6.5.4. Using Echo
Normally, the system writes back to the terminal any printable characters that the user types at that terminal. The system also writes highlighted words in response to certain control characters; for example, the system writes EXIT if the user enters Ctrl/Z. If the user types ahead of your read, the characters are not echoed until you read them from the type-ahead buffer.
modifiers
argument.
You can turn off echoing for control characters only by modifying the read operation with
TRM$M_TM_TRMNOECHO. The following example turns off all echoing
for the read
operation:INTEGER*4 SMG$CREATE_VIRTUAL_KEYBOARD, 2 SMG$READ_STRING, 2 STATUS, 2 VKID, ! Virtual keyboard ID 2 INPUT_SIZE CHARACTER*512 INPUT INCLUDE '($TRMDEF)' STATUS = SMG$CREATE_VIRTUAL_KEYBOARD (VKID, ! Keyboard ID 2 'SYS$INPUT') ! I/O device IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$READ_STRING (VKID, ! Keyboard ID 2 INPUT, ! Data read 2 'Prompt> ', 2 512, 2 TRM$M_TM_NOECHO, 2 ,, 2 INPUT_SIZE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
You can also turn off echoing with a QIO read operation modified by IO$M_NOECHO (defined in $IODEF). You can turn off echoing for further read operations with a QIO set mode operation that specifies TT$M_NOECHO as a basic terminal characteristic.
6.5.5. Using Timeout
timeout
argument, the number of
seconds the user has to respond. If the user fails to type a character in the allotted time,
the error condition SS$_TIMEOUT (defined in
$SSDEF) is returned. The following example restricts the user to
8 seconds in which to respond to a read
command:INTEGER*4 SMG$CREATE_VIRTUAL_KEYBOARD, 2 SMG$READ_STRING, 2 STATUS, 2 VKID, ! Virtual keyboard ID 2 INPUT_SIZE CHARACTER*512 INPUT INCLUDE '($SSDEF)' STATUS = SMG$CREATE_VIRTUAL_KEYBOARD (VKID, 2 'SYS$INPUT') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$READ_STRING (VKID, ! Keyboard ID 2 INPUT, ! Data read 2 'Prompt> ', 2 512, 2 , 2 8, 2 , 2 INPUT_SIZE) IF (.NOT. STATUS) THEN IF (STATUS .EQ. SS$_TIMEOUT) CALL NO_RESPONSE () ELSE CALL LIB$SIGNAL (%VAL (STATUS)) END IF
You can cause a QIO read operation to time out after a certain number of seconds by modifying
the operation with IO$M_TIMED and by specifying the number of seconds in the
P3
argument. A message broadcast to a terminal resets a timer that
is set for a timed read operation (regardless of whether the operation was initiated with
QIO or SMG).
Note that the timed read operations work on a character-by-character basis. To set a time limit on an input record rather than an input character, you must use the SYS$SETIMR system service. The SYS$SETIMR executes an AST routine at a specified time. The specified time is the input time limit. When the specified time is reached, the AST routine cancels any outstanding I/O on the channel that is assigned to the user's terminal.
6.5.6. Converting Lowercase to Uppercase
modifiers
argument,
as shown in the following
example:INTEGER*4 SMG$CREATE_VIRTUAL_KEYBOARD, 2 SMG$READ_STRING, 2 STATUS, 2 VKID, ! Virtual keyboard ID 2 INPUT_SIZE CHARACTER*512 INPUT INCLUDE '($TRMDEF)' STATUS = SMG$CREATE_VIRTUAL_KEYBOARD (VKID, ! Keyboard ID 2 'SYS$INPUT') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$READ_STRING (VKID, ! Keyboard ID 2 INPUT, ! Data read 2 'Prompt> ', 2 512, 2 TRM$M_TM_CVTLOW, 2 ,, 2 INPUT_SIZE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
You can also convert lowercase characters to uppercase with a QIO read operation modified by IO$M_CVTLOW (defined in $IODEF).
6.5.7. Performing Line Editing and Control Actions
modifiers
argument. The following example shows how you can inhibit line
editing:INTEGER*4 SMG$CREATE_VIRTUAL_KEYBOARD, 2 SMG$READ_STRING, 2 STATUS, 2 VKID, ! Virtual keyboard ID 2 INPUT_SIZE CHARACTER*512 INPUT INCLUDE '($TRMDEF)' STATUS = SMG$CREATE_VIRTUAL_KEYBOARD (VKID, ! Keyboard ID 2 'SYS$INPUT') IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$READ_STRING (VKID, ! Keyboard ID 2 INPUT, ! Data read 2 'Prompt> ', 2 512, 2 TRM$M_TM_NOFILTR, 2 ,, 2 INPUT_SIZE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
You can also inhibit line editing with a QIO read operation modified by IO$M_NOFILTR (defined in $IODEF).
6.5.8. Using Broadcasts
INTEGER*4 STATUS, 2 SYS$BRKTHRUW INTEGER*2 B_STATUS (4) INCLUDE '($BRKDEF)' STATUS = SYS$BRKTHRUW (, 2 'Accounting system started',, 2 %VAL (BRK$C_ALLUSERS), 2 B_STATUS,,,,,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS))
6.5.8.1. Default Handling of Broadcasts
If the terminal user has taken no action to handle broadcasts, a broadcast is written to the terminal screen at the current position (after a carriage return and line feed). If a write operation is in progress, the broadcast occurs after the write ends. If a read operation is in progress, the broadcast occurs immediately; after the broadcast, any echoed user input to the aborted read operation is written to the screen (same effect as pressing Ctrl/R).
6.5.8.2. How to Create Alternate Broadcast Handlers
You can handle broadcasts to the terminal on which your program is running with SMG$SET_BROADCAST_TRAPPING. This routine uses the AST mechanism to transfer control to a subprogram of your choice each time a broadcast message is sent to the terminal; when the subprogram completes, control returns to the point in your mainline code where it was interrupted.
The SMG$SET_BROADCAST_TRAPPING routine is not an SMG$ input routine. Before invoking SMG$SET_BROADCAST_TRAPPING, you must invoke SMG$CREATE_PASTEBOARD to associate a pasteboard with the terminal. SMG$CREATE_PASTEBOARD returns a pasteboard identification number; pass that number to SMG$SET_BROADCAST_TRAPPING to identify the terminal in question. Read the contents of the broadcast with SMG$GET_BROADCAST_MESSAGE.
. . . INTEGER*4 STATUS, 2 PBID, ! Pasteboard ID 2 VDID, ! Virtual display ID 2 SMG$CREATE_PASTEBOARD, 2 SMG$SET_BROADCAST_TRAPPING 2 SMG$PASTE_VIRTUAL_DISPLAY COMMON /ID/ PBID, 2 VDID INTEGER*2 B_STATUS (4) INCLUDE '($SMGDEF)' INCLUDE '($BRKDEF)' EXTERNAL BRKTHRU_ROUTINE STATUS = SMG$CREATE_PASTEBOARD (PBID) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$CREATE_VIRTUAL_DISPLAY (3, ! Height 2 80, ! Width 2 VDID,, ! Display ID 2 SMG$M_REVERSE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SMG$SET_BROADCAST_TRAPPING (PBID, ! Pasteboard ID 2 BRKTHRU_ROUTINE) ! AST IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . .
SUBROUTINE BRKTHRU_ROUTINE () INTEGER*4 STATUS, 2 PBID, ! Pasteboard ID 2 VDID, ! Virtual display ID 2 SMG$GET_BROADCAST_MESSAGE, 2 SMG$PUT_CHARS, 2 SMG$PASTE_VIRTUAL_DISPLAY COMMON /ID/ PBID, 2 VDID CHARACTER*240 MESSAGE INTEGER*2 MESSAGE_SIZE ! Read the message STATUS = SMG$GET_BROADCAST_MESSAGE (PBID, 2 MESSAGE, 2 MESSAGE_SIZE) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Write the message to the virtual display STATUS = SMG$PUT_CHARS (VDID, 2 MESSAGE (1:MESSAGE_SIZE), 2 1, ! Line 2 1) ! Column IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Make the display visble by pasting it to the pasteboard STATUS = SMG$PASTE_VIRTUAL_DISPLAY (VDID, 2 PBID, 2 22, ! Row 2 1) ! Column END
Chapter 7. System Service Input/Output Operations
This chapter describes how to use system services to perform input and output operations.
Examples are provided to show you how to use the I/O services for simple functions, such as terminal input and output operations. If you plan to write device-dependent I/O routines, see the VSI OpenVMS I/O User's Reference Manual.
On VAX systems, if you want to write your own device driver or connect to a device interrupt vector, see the OpenVMS VAX Device Support Reference Manual. This manual has been archived but is available on the OpenVMS Documentation CD-ROM.
Besides using I/O system services, you can use OpenVMS Record Management Services (RMS). OpenVMS RMS provides a set of routines for general-purpose, device-independent functions such as data storage, retrieval, and modification.
Unlike RMS services, I/O system services permit you to use the I/O resources of the operating system directly in a device-dependent manner. I/O services also provide some specialized functions not available in OpenVMS RMS. Using I/O services requires more programming knowledge than using OpenVMS RMS, but can result in more efficient input/output operations.
7.1. Overview of OpenVMS QIO Operations
The OpenVMS operating system provides QIO operations that perform three basic I/O functions: read, write, and set mode. The read function transfers data from a device to a user-specified buffer. The write function transfers data in the opposite direction—from a user-specified buffer to the device. For example, in a read QIO function to a terminal device, a user-specified buffer is filled with characters received from the terminal. In a write QIO function to the terminal, the data in a user-specified buffer is transferred to the terminal where it is displayed.
The set mode QIO function is used to control or describe the characteristics and operation of a device. For example, a set mode QIO function to a line printer can specify either uppercase or lowercase character format. Not all QIO functions are applicable to all types of devices. The line printer, for example, cannot perform a read QIO function.
7.2. Quotas, Privileges, and Protection
To preserve the integrity of the operating system, the I/O operations are performed under the constraints of quotas, privileges, and protection.
Quotas limit the number and type of I/O operations that a process can perform concurrently and the total size of outstanding transfers. They ensure that all users have an equitable share of system resources and usage.
Privileges are granted to a user to allow the performance of certain I/O-related operations, for example, creating a mailbox and performing logical I/O to a file-structured device. Restrictions on user privileges protect the integrity and performance of both the operating system and the services provided to other users.
Protection controls access to files and devices. Device protection is provided in much the same way as file protection: shareable and nonshareable devices are protected by protection masks.
The Set Resource Wait Mode (SYS$SETRWM) system service allows a process to select either of two modes when an attempt to exceed a quota occurs. In the enabled (default) mode, the process waits until the required resource is available before continuing. In the disabled mode, the process is notified immediately by a system service status return that an attempt to exceed a quota has occurred. Waiting for resources is transparent to the process when resource wait mode is enabled; the process takes no explicit action when a wait is necessary.
The different types of I/O-related quotas, privilege, and protection are described in the following sections.
7.2.1. Buffered I/O Quota
The buffered I/O limit quota (BIOLM) specifies the maximum number of concurrent buffered I/O operations that can be active in a process. In a buffered I/O operation, the user's data is buffered in system dynamic memory. The driver deals with the system buffer and not the user buffer. Buffered I/O is used for terminal, line printer, card reader, network, mailbox, and console medium transfers and file system operations. For a buffered I/O operation, the system does not have to lock the user's buffer in memory.
The system manager, or the person who creates the process, establishes the buffered I/O quota value in the user authorization file. If you use the Set Resource Wait Mode (SYS$SETRWM) system service to enable resource wait mode for the process, the process enters resource wait mode if it attempts to exceed its direct I/O quota.
7.2.2. Buffered I/O Byte Count Quota
The buffered I/O byte count quota (BYTLM) specifies the maximum amount of buffer space that can be consumed from system dynamic memory for buffering I/O requests. All buffered I/O requests require system dynamic memory in which the actual I/O operation takes place.
The system manager, or the person who creates the process, establishes the buffered I/O byte count quota in the user authorization file. If you use the SYS$SETRWM system service to enable resource wait mode for the process, the process enters resource wait mode if it attempts to exceed its direct I/O quota.
7.2.3. Direct I/O Quota
The direct I/O limit quota (DIOLM) specifies the maximum number of concurrent direct (unbuffered) I/O operations that a process can have active. In a direct I/O operation, data is moved directly to or from the user buffer. Direct I/O is used for disk, magnetic tape, most direct memory access (DMA) real-time devices, and nonnetwork transfers, such as DMC11/DMR11 write transfers. For direct I/O, the user's buffer must be locked in memory during the transfer.
The system manager, or the person who creates the process, establishes the direct I/O quota value in the user authorization file. If you use the SYS$SETRWM system service to enable resource wait mode for the process, the process enters resource wait mode if it attempts to exceed its direct I/O quota.
7.2.4. AST Quota
The AST quota specifies the maximum number of outstanding asynchronous system traps that a process can have. The system manager, or the person who creates the process, establishes the quota value in the user authorization file. There is never an implied wait for that resource.
7.2.5. Physical I/O Privilege
Physical I/O privilege (PHY_IO) allows a process to perform physical I/O operations on a device. Physical I/O privilege also allows a process to perform logical I/O operations on a device.
7.2.6. Logical I/O Privilege
Logical I/O privilege (LOG_IO) allows a process to perform logical I/O operations on a device. A process can also perform physical operations on a device if the process has logical I/O privilege, the volume is mounted foreign, and the volume protection mask allows access to the device. (A foreign volume is one volume that contains no standard file structure understood by any of the operating system software.) See Section 7.3.2, “Logical I/O Operations”for further information about logical I/O privilege.
7.2.7. Mount Privilege
Mount privilege (MOUNT) allows a process to use the IO$_MOUNT function to perform mount operations on disk and magnetic tape devices. The IO$_MOUNT function is used in ancillary control process (ACP) interface operations.
7.2.8. Share Privilege
Share privilege (SHARE) allows a process to use the SYS$ASSIGN system service to override another process's exclusive access request on the specified device.
Performing any I/O operations to a device driver coded to expect exclusive access – performing I/O to any device driver not explicitly coded to expect shared multiple-process access – can result in unusual and unexpected device and application behaviour, and can result in problems of device ownership, and failures during the device driver last channel deassign operation.
Using SHARE to override access is useful for a few specific situations, such as user-written device driver debugging and user-written device driver diagnostic tools. General use of SHARE is not recommended.
7.2.9. Volume Protection
Volume protection protects the integrity of mailboxes and both foreign and Files-11 On-Disk Structure Level 2 structured volumes. Volume protection for a foreign volume is established when the volume is mounted. Volume protection for a Files-11 structured volume is established when the volume is initialized. (If the process mounting the volume has the override volume protection privilege, VOLPRO, protection can be overridden when the volume is mounted).
The SYS$CREMBX system service protection mask argument establishes mailbox protection.
Set Protection QIO requests allow you to set volume protection on a mailbox. You must either be the owner of the mailbox or have the BYPASS privilege.
Protection for structured volumes and mailboxes is provided by a volume protection mask that contains four 4-bit fields. These fields correspond to the four classes of user permitted to access the volume. (User classes are based on the volume owner's UIC.)
The 4-bit fields are interpreted differently for volumes that are mounted as structured (that is, volumes serviced by an ACP), volumes that are mounted as foreign, and mailboxes (both temporary and permanent).
Figure 7.1, “Mailbox Protection Fields” shows the 4-bit protection fields for mailboxes. Usually, volume protection is meaningful only for read and write operations.

7.2.10. Device Protection
Device protection protects the allocation of nonshareable devices, such as terminals and card readers.
Protection is provided by a device protection mask similar to that of volume protection. The difference is that only the bit corresponding to read access is checked, and that bit determines whether the process can allocate or assign a channel to the device.
You establish device protection with the DCL command SET PROTECTION/DEVICE. This command sets both the protection mask and the device owner UIC.
7.2.11. System Privilege
System UIC privilege (SYSPRV) allows a process to be eligible for the volume or device protection specified for the system protection class, even if the process does not have a UIC in one of the system groups.
7.2.12. Bypass Privilege
Bypass privilege (BYPASS) allows a process to bypass volume and device protection completely.
7.3. Physical, Logical, and Virtual I/O
I/O data transfers can occur in any one of three device addressing modes:physical, logical, or virtual. Any process with device access allowed by the volume protection mask can perform logical I/O on a device that is mounted foreign; physical I/O requires privileges. Virtual I/O does not require privileges; however, intervention by an ACP to control user access might be necessary if the device is under ACP control. (ACP functions are described in the VSI OpenVMS I/O User's Reference Manual).
7.3.1. Physical I/O Operations
In physical I/O operations, data is read from and written to the actual, physically addressable units accepted by the hardware (for example, sectors on a disk or binary characters on a terminal in the PASSALL mode). This mode allows direct access to all device-level I/O operations.
The issuing process has physical I/O privilege (PHY_IO).
- The issuing process has all of the following characteristics:
The issuing process has logical I/O privilege (LOG_IO).
The device is mounted foreign.
The volume protection mask allows physical access to the device.
If neither of these conditions is met, the physical I/O operation is rejected by the SYS$QIO system service, which returns a condition value of SS$_NOPRIV (no privilege). Figure 7.2, “Physical I/O Access Checks” illustrates the physical I/O access checks in greater detail.
The inhibit error-logging function modifier (IO$M_INHERLOG) can be specified for all physical I/O functions. The IO$M_INHERLOG function modifier inhibits the logging of any error that occurs during the I/O operation.
7.3.2. Logical I/O Operations
n
-1, where n
is the number of blocks on
the device. For record-oriented or non-block-structured devices (such as terminals),
logical addressable units are not pertinent and are ignored. Logical I/O requires
that one of the following conditions be met:The issuing process has physical I/O privilege (PHY_IO).
The issuing process has logical I/O privilege (LOG_IO).
The volume is mounted foreign and the volume protection mask allows access to the device.
If none of these conditions is met, the logical I/O operation is rejected by the SYS$QIO system service, which returns a condition value of SS$_NOPRIV (no privilege). Figure 7.3, “Logical I/O Access Checks” illustrates the logical I/O access checks in greater detail.
7.3.3. Virtual I/O Operations
You can perform virtual I/O operations on both record-oriented (non-file-structured) and block-addressable (file-structured) devices. For record-oriented devices (such as terminals), the virtual function is the same as a logical function; the virtual addressable units of the devices are ignored.
For block-addressable devices (such as disks), data is read from and written to open files. The addressable units in the file are 512-byte blocks. They are numbered starting at 1 and are relative to a file rather than to a device. Block-addressable devices must be mounted and structured and must contain a file that was previously accessed on the I/O channel.
Condition Value |
Meaning |
---|---|
SS$_NOPRIV |
No privilege |
SS$_DEVNOTMOUNT |
Device not mounted |
SS$_DEVFOREIGN |
Volume mounted foreign |
Figure 7.4, “Physical, Logical, and Virtual I/O” shows the relationship of physical, logical, and virtual I/O to the driver.



7.4. I/O Function Encoding
I/O functions fall into three groups that correspond to the three I/O device addressing modes (physical, logical, and virtual) described in Section 7.3, “Physical, Logical, and Virtual I/O”. Depending on the device to which it is directed, an I/O function can be expressed in one, two, or all three modes.
I/O functions are described by 16-bit, symbolically expressed values that specify the particular I/O operation to be performed and any optional function modifiers. Figure 7.5, “I/O Function Format” shows the format of the 16-bit function value.
Symbolic names for I/O function codes are defined by the $IODEF macro.

7.4.1. Function Codes
Physical I/O |
Logical I/O |
Virtual I/O |
---|---|---|
IO$_READPBLK |
IO$_READLBLK |
IO$_READVBLK |
IO$_WRITEPBLK |
IO$_WRITELBLK |
IO$_WRITEVBLK |
The set mode I/O function has a symbolic value of IO$_SETMODE.
Note
You should determine the device class before performing any QIO function, because the requested function might be incompatible with some devices. For example, the SYS$INPUT device could be a terminal, a disk, or some other device. Unless this device is a terminal, an IO$_SETMODE request that enables a Ctrl/C AST is not performed.
7.4.2. Function Modifiers
The high-order 10 bits of the function value are function modifiers. These are individual bits that alter the basic operation to be performed. For example, you can specify the function modifier IO$M_NOECHO with the function IO$_READLBLK to a terminal. When used together, the two values are written in VAX MACRO as IO$_READLBLK!IO$M_NOECHO. This causes data typed at the terminal keyboard to be entered into the user buffer but not echoed to the terminal. Figure 7.6, “Function Modifier Format” shows the format of function modifiers.

As shown in Figure 7.6, “Function Modifier Format”, bits <15:13> are device- or function-independent bits, and bits <12:6>are device- or function-dependent bits. Device- or function-dependent bits have the same meaning, whenever possible, for different device classes. For example, the function modifier IO$M_ACCESS is used with both disk and magnetic tape devices to cause a file to be accessed during a create operation. Device- or function-dependent bits always have the same function within the same device class.
There are two device- or function-independent modifier bits: IO$M_INHRETRY and IO$M_DATACHECK (a third bit is reserved). IO$M_INHRETRY is used to inhibit all error recovery. If any error occurs and this modifier bit is specified, the operation is terminated immediately and a failure status is returned in the I/O status block (see Section 7.10, “I/O Completion Status”). Use IO$M_DATACHECK to compare the data in memory with that on a disk or magnetic tape.
7.5. Assigning Channels
Before any input or output operation can be performed on a physical device, you must assign a channel to the device to provide a path between the process and the device. The Assign I/O Channel (SYS$ASSIGN) system service establishes this path.
When you write a call to the SYS$ASSIGN service, you must supply the name of the device, which can be a physical device name or a logical name, and the address of a word to receive the channel number. The service returns a channel number, and you use this channel number when you write an input or output request.
#include <descrip.h> #include <lib$routines.h> #include <ssdef.h> #include <starlet.h> #include <stdio.h> #include <stsdef.h> main() { unsigned int status; unsigned short ttchan; $DESCRIPTOR(ttname,"TTA2:"); /* Assign a channel to a device */ status = SYS$ASSIGN( &ttname, /* devnam - device name */ &ttchan, /* chan - channel number */ 0, /* acmode - access mode */ 0, /* mbxnam - logical name for mailbox */ 0 ); /* flags */ if (!$VMS_STATUS_SUCCESS(status)) LIB$SIGNAL(status); return SS$_NORMAL; }
To assign a channel to the current default input or output device, use the logical name SYS$INPUT or SYS$OUTPUT.
For more details on how SYS$ASSIGN and other I/O services handle logical names, see Section 7.2.5, “Physical I/O Privilege”.
7.5.1. Using the Share Privilege with the SYS$ASSIGN and SYS$DASSGN Services
Use of SHARE privilege should be made only with caution, as applications, application protocols, and device drivers coded to expect only exclusive access can encounter unexpected and potentially errant behavior when access to the device is unexpectedly shared via use of SHARE privilege.
If you use the SHARE privilege to override the exclusivity requested by another process's call to the system service SYS$ASSIGN, and the original process then attempts to deassign its channels via explicit calls to SYS$DASSGN or via the implicit calls to SYS$DASSGN made during image or process rundown, the OpenVMS last-channel-deassign code may not operate as expected due to the assignment of the additional I/O channels to the device. The presence of these extra channels will prevent the last-channel-deassign code from releasing the ownership of the device, potentially resulting in a device owned by the process identification (PID) of a nonexistent process.
Unless its use is explicitly supported by the application, the application protocol, and the device driver, the use of SHARE privilege is generally discouraged.
7.6. Queuing I/O Requests
All input and output operations in the operating system are initiated with the Queue I/O Request (SYS$QIO) system service. The SYS$QIO system service permits direct interaction with the system's terminal driver. SYS$QIOs permit some operations that cannot be performed with language I/O statements and RTL routines; calls to SYS$QIO reduce overhead and permit asynchronous I/O operations. However, calls to SYS$QIO are device dependent. The SYS$QIO service queues the request and returns immediately to the caller. While the operating system processes the request, the program that issued the request can continue execution.
SYS$QIO ([efn],chan,func[,iosb][,astadr][,astprm][,p1][,p2][,p3][,p4][,p5][,p6])
Required arguments to the SYS$QIO service include the channel number assigned to the device on which the I/O is to be performed, and a function code (expressed symbolically) that indicates the specific operation to be performed. Depending on the function code, one to six additional parameters may be required.
#include <starlet.h> unsigned int status, func=IO$_WRITEVBLK; . . . status = SYS$QIO(0, /* efn - event flag */ ttchan, /* chan - channel number */ func, /* func - function modifier */ 0, /* iosb - I/O status block */ 0, /* astadr - AST routine */ 0, /* astprm - AST parameter */ buffadr, /* p1 - output buffer */ buflen); /* p2 - length of message */
Function codes are defined for all supported device types, and most of the codes are device dependent; that is, they perform functions specific to a particular device. The $IODEF macro defines symbolic names for these function codes. For information about how to obtain a listing of these symbolic names, see Appendix A, Generic Macros for Calling System Services. For details about all function codes and an explanation of the parameters required by each, see the VSI OpenVMS I/O User's Reference Manual.
To read from or write to a terminal with the SYS$QIO or SYS$QIOW system service, you must first associate the terminal name with an I/O channel by calling the SYS$ASSIGN system service, then use the assigned channel in the SYS$QIO or SYS$QIOW system service. To read from SYS$INPUT or write to SYS$OUTPUT, specify the appropriate logical name as the terminal name in the SYS$ASSIGN system service. In general, use SYS$QIO for asynchronous operations, and use SYS$QIOW for all other operations.
7.7. Synchronizing Service Completion
Test whether the operation was queued successfully.
Test whether the operation itself completed successfully.
Specify the number of an event flag to be set when the operation completes.
Specify the address of an AST routine to be executed when the operation completes.
Specify the address of an I/O status block in which the system can place the return status when the operation completes.
I/O status blocks are explained in Section 7.10, “I/O Completion Status”.
#include <lib$routines.h> #include <starlet.h> unsigned int status, efn=0, efn1=1, efn=2; . . . status = SYS$QIO(efn1,...); /* Issue 1st I/O request */ if (!$VMS_STATUS_SUCCESS(status)) LIB$SIGNAL( status ); /* Queued successfully? */. . . status = SYS$QIO(efn2,...); /* Issue second I/O request */
if (!$VMS_STATUS_SUCCESS(status)) /* Queued successfully? */ LIB$SIGNAL( status ); . . .
status = SYS$WFLAND( efn, /* Wait until both are done */ &mask,...
. . .
When you specify an event flag number as an argument, SYS$QIO clears the event flag when it queues the I/O request. When the I/O completes, the flag is set. | |
In this example, the program issues two Queue I/O requests. A different event flag is specified for each request. | |
The Wait for Logical AND of Event Flags
(SYS$WFLAND) system service places the process
in a wait state until both I/O operations are complete. The
| |
Note that the SYS$WFLAND system service (and the other wait system services) wait for the event flag to be set; they do not wait for the I/O operation to complete. If some other event were to set the required event flags, the wait for event flag would complete too soon. You must coordinate the use of event flags carefully. (See Section 7.8, “Recommended Method for Testing Asynchronous Completion” for a discussion of the recommended method for testing I/O completion). |
#include <lib$routines.h> #include <starlet.h> #include <stsdef.h> unsigned int status, astprm=1; . . . status = SYS$QIO(...&ttast, /* I/O request with AST */astprm...); if (!$VMS_STATUS_SUCCESS( status )) /* Queued successfully? */ LIB$SIGNAL( status ); . . . } void ttast ( int astprm ) { /* AST service routine */
/* Handle I/O completion */ . . . return; } /* End of AST routine */
When you specify the The SYS$QIO system service call specifies the address of the AST routine, TTAST, and a parameter to pass as an argument to the AST service routine. When$QIO returns control, the process continues execution. | |
When the I/O completes, the AST routine TTAST is called, and it responds to the I/O completion. By examining the AST parameter, TTAST can determine the origin of the I/O request. When this routine is finished executing, control returns to the process at
the point at which it was interrupted. If you specify the
|
#include <lib$routines.h> #include <stdio.h> #include <ssdef.h> #include <starlet.h> #include <stsdef.h> . . . /* I/O status block */ struct { unsigned short iostat, iolen; unsigned int dev_info; }ttiosb;unsigned int status; . . . status = SYS$QIO(,..., &ttiosb, ...);
if( !$VMS_STATUS_SUCCESS( status )) /* Queued successfully? */ LIB$SIGNAL( status ); . . . while(ttiosb.iostat == 0) { /* Loop -- with delay -- until done */
} if( !$VMS_STATUS_SUCCESS( ttiosb.iostat )) { /* Perform error handling */ . . . }
An I/O status block is a quadword structure that the system uses to post
the status of an I/O operation. You must define the quadword area in your
program. TTIOSB defines the I/O status block for this I/O operation. The
| |
Instead of polling the low-order word of the I/O status block for the completion status, the program uses the preferred method of using an event flag and calling SYS$SYNCH to determine I/O completion. | |
The process polls the I/O status block. If the low-order word still contains zero, the I/O operation has not yet completed. In this example, the program loops until the request is complete. |
7.8. Recommended Method for Testing Asynchronous Completion
VSI recommends that you use the Synchronize (SYS$SYNCH) system service to wait for completion of an asynchronous event. The SYS$SYNCH service correctly waits for the actual completion of an asynchronous event, even if some other event sets the event flag.
To use the SYS$SYNCH service to wait for the completion of an asynchronous event, you must specify both an event flag number and the address of an I/O status block (IOSB) in your call to the asynchronous system service. The asynchronous service queues the request and returns control to your program. When the asynchronous service completes, it sets the event flag and places the final status of the request in the IOSB.
In your call to SYS$SYNCH, you must specify the same
efn
and I/O status block that you specified in your call to
the asynchronous service. The SYS$SYNCH service waits for the
event flag to be set by means of the SYS$WAITFR system service.
When the specified event flag is set, SYS$SYNCH checks the
specified I/O status block. If the I/O status block is nonzero, the system service has
completed and SYS$SYNCH returns control to your program. If the
I/O status block is zero, SYS$SYNCH clears the event flag by
means of the SYS$CLREF service and calls the
$WAITFR service to wait for the event flag to be
set.
The SYS$SYNCH service sets the event flag before returning control to your program. This ensures that the call to SYS$SYNCH does not interfere with testing for completion of another asynchronous event that completes at approximately the same time and uses the same event flag to signal completion.
. . . #include <lib$routines.h> #include <starlet.h> unsigned int status, event_flag = 1; struct { short int iostat, iolen; unsigned int dev_info; }ttiosb; . . . /* Request I/O */ status = SYS$QIO (event_flag, ..., &ttiosb ...); if (!$VMS_STATUS_SUCCESS(status)) LIB$SIGNAL( status ); . . . /* Wait until I/O completes */ status = SYS$SYNCH (event_flag, &ttiosb ); if (!$VMS_STATUS_SUCCESS(status)) LIB$SIGNAL( status ); . . .
Note
The SYS$QIOW service provides a combination of SYS$QIO and SYS$SYNCH.
7.9. Synchronous and Asynchronous Forms of Input/Output Services
You can execute some input/output services either synchronously or asynchronously. A “W” at the end of a system service name indicates the synchronous version of the system service.
The synchronous version of a system service combines the functions of the asynchronous version of the service and the Synchronize (SYS$SYNCH) system service. The synchronous version acts exactly as if you had used the asynchronous version of the system service followed immediately by a call to SYS$SYNCH; it queues the I/O request, and then places the program in a wait state until the I/O request completes. The synchronous version takes the same arguments as the asynchronous version.
Asynchronous Name |
Synchronous Name |
Description |
---|---|---|
$BRKTHRU |
$BRKTHRUW |
Breakthrough |
$GETDVI |
$GETDVIW |
Get Device/Volume Information |
$GETJPI |
$GETJPIW |
Get Job/Process Information |
$GETLKI |
$GETLKIW |
Get Lock Information |
$GETQUI |
$GETQUIW |
Get Queue Information |
$GETSYI |
$GETSYIW |
Get Systemwide Information |
$QIO |
$QIOW |
Queue I/O Request |
$SNDJBC |
$SNDJBCW |
Send to Job Controller |
$UPDSEC |
$UPDSECW |
Update Section File on Disk |
7.9.1. Reading Operations with SYS$QIOW
The SYS$QIO and SYS$QIOW system services move one record of data from a terminal to a variable. For synchronous I/O, use SYS$QIOW. Complete information about the SYS$QIO and SYS$QIOW system services is presented in the VSI OpenVMS System Services Reference Manual.
The SYS$QIO and SYS$QIOW system
services place the data read in the variable specified in the
1
argument. The second word of the status block contains
the offset from the beginning of the buffer to the terminator—hence, it equals
the size of the data read. Always reference the data as a substring, using the
offset to the terminator as the position of the last character (that is, the size of
the substring). If you reference the entire buffer, your data will include the
terminator for the operation (for example, the CR character) and any excess
characters from a previous operation using the buffer. (The only exception to the
substring guideline is if you deliberately overflow the buffer to terminate the I/O
operation).
. . . INTEGER STATUS ! QIOW structures INTEGER*2 INPUT_CHAN ! I/O channel INTEGER CODE, ! Type of I/O operation 2 INPUT_BUFF_SIZE, ! Size of input buffer 2 PROMPT_SIZE, ! Size of prompt 2 INPUT_SIZE ! Size of input line as read PARAMETER (PROMPT_SIZE = 13, 2 INPUT_BUFF_SIZE = 132) CHARACTER*132 INPUT CHARACTER*(*) PROMPT PARAMETER (PROMPT = 'Input value: ') ! Define symbols used in I/O operations INCLUDE '($IODEF)' ! Status block for QIOW STRUCTURE /IOSTAT_BLOCK/ INTEGER*2 IOSTAT, ! Return status 2 TERM_OFFSET, ! Location of line terminator 2 TERMINATOR, ! Value of terminator 2 TERM_SIZE ! Size of terminator END STRUCTURE RECORD /IOSTAT_BLOCK/ IOSB ! Subprograms INTEGER*4 SYS$ASSIGN, 2 SYS$QIOW . . . ! Assign an I/O channel to SYS$INPUT STATUS = SYS$ASSIGN ('SYS$INPUT', 2 INPUT_CHAN,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Read with prompt CODE = IO$_READPROMPT STATUS = SYS$QIOW (, 2 %VAL (INPUT_CHAN), 2 %VAL (CODE), 2 IOSB, 2 ,, 2 %REF (INPUT), 2 %VAL (INPUT_BUFF_SIZE), 2 ,, 2 %REF (PROMPT), 2 %VAL (PROMPT_SIZE)) ! Check QIOW status IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Check status of I/O operation IF (.NOT. IOSB.IOSTAT) CALL LIB$SIGNAL (%VAL (IOSB.IOSTAT)) ! Set size of input string INPUT_SIZE = IOSB.TERM_OFFSET . . .
7.9.2. Reading Operations with SYS$QIO
. . . INTEGER STATUS ! QIO structures INTEGER*2 INPUT_CHAN ! I/O channel INTEGER CODE, ! Type of I/O operation 2 INPUT_BUFF_SIZE, ! Size of input buffer 2 PROMPT_SIZE, ! Size of prompt 2 INPUT_SIZE ! Size of input line as read PARAMETER (INPUT_BUFF_SIZE = 132, 2 PROMPT = 13) CHARACTER*132 INPUT CHARACTER*(*) PROMPT PARAMETER (PROMPT = 'Input value: ') INCLUDE '($IODEF)' ! Symbols used in I/O operations ! Status block for QIO STRUCTURE /IOSTAT_BLOCK/ INTEGER*2 IOSTAT, ! Return status 2 TERM_OFFSET, ! Location of line terminator 2 TERMINATOR, ! Value of terminator 2 TERM_SIZE ! Size of terminator END STRUCTURE RECORD /IOSTAT_BLOCK/ IOSB ! Event flag for I/O INTEGER INPUT_EF ! Subprograms INTEGER*4 SYS$ASSIGN, 2 SYS$QIO, 2 SYS$SYNCH, 2 LIB$GET_EF . . . ! Assign an I/O channel to SYS$INPUT STATUS = SYS$ASSIGN ('SYS$INPUT', 2 INPUT_CHAN,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Get an event flag STATUS = LIB$GET_EF (INPUT_EF) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Read with prompt CODE = IO$_READPROMPT STATUS = SYS$QIO (%VAL (INPUT_EF), 2 %VAL (INPUT_CHAN), 2 %VAL (CODE), 2 IOSB, 2 ,, 2 %REF (INPUT), 2 %VAL (INPUT_BUFF_SIZE), 2 ,, 2 %REF (PROMPT), 2 %VAL (PROMPT_SIZE)) ! Check status of QIO IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) . . . STATUS = SYS$SYNCH (%VAL (INPUT_EF), 2 IOSB) ! Check status of SYNCH IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) ! Check status of I/O operation IF (.NOT. IOSB.IOSTAT) CALL LIB$SIGNAL (%VAL (IOSB.IOSTAT)) ! Set size of input string INPUT_SIZE = IOSB.TERM_OFFSET . . .
Be sure to check the status of the I/O operation as returned in the I/O status block. In an asynchronous operation, you can check this status only after the I/O operation is complete (that is, after the call to SYS$SYNCH).
7.9.3. Write Operations with SYS$QIOW
The SYS$QIO and SYS$QIOW system services move one record of data from a character value to the terminal. Do not use these system services, as described here, for output to a file or nonterminal device.
For synchronous I/O, use SYS$QIOW and omit the first argument (the event flag number). For complete information about SYS$QIO and SYS$QIOW, refer to the VSI OpenVMS System Services Reference Manual.
INTEGER STATUS, 2 ANSWER_SIZE CHARACTER*31 ANSWER INTEGER*2 OUT_CHAN ! Status block for QIO STRUCTURE /IOSTAT_BLOCK/ INTEGER*2 IOSTAT, 2 BYTE_COUNT, 2 LINES_OUTPUT BYTE COLUMN, 2 LINE END STRUCTURE RECORD /IOSTAT_BLOCK/ IOSB ! Routines INTEGER SYS$ASSIGN, 2 SYS$QIOW ! IO$ symbol definitions INCLUDE '($IODEF)' . . . STATUS = SYS$ASSIGN ('SYS$OUTPUT', 2 OUT_CHAN,,) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) STATUS = SYS$QIOW (, 2 %VAL (OUT_CHAN), 2 %VAL (IO$_WRITEVBLK), 2 IOSB, 2 , 2 , 2 %REF ('Answer: '//ANSWER(1:ANSWER_SIZE)), 2 %VAL (8+ANSWER_SIZE), 2 , 2 %VAL (32),,) ! Single spacing IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) IF (.NOT. IOSB.IOSTAT) CALL LIB$SIGNAL (%VAL (IOSB.IOSTAT)) END
7.10. I/O Completion Status
When an I/O operation completes, the system posts the completion status in the I/O status block, if one is specified. The completion status indicates whether the operation completed successfully, the number of bytes that were transferred, and additional device-dependent return information.
Figure 7.7, “I/O Status Block” illustrates the format for the SYS$QIO system service of the information written in the IOSB.

The first word contains a system status code indicating the success or failure of the operation. The status codes used are the same as for all returns from system services; for example, SS$_NORMAL indicates successful completion.
The second word contains the number of bytes actually transferred in the I/O operation. Note that for some devices this word contains only the low-order word of the count. For information about specific devices, see the VSI OpenVMS I/O User's Reference Manual.
The second longword contains device-dependent return information.
System services other than SYS$QIO use the quadword I/O status block, but the format is different. See the description of each system service in the VSI OpenVMS System Services Reference Manual for the format of the information written in the IOSB for that service.
To ensure successful I/O completion and the integrity of data transfers, you should check the IOSB following I/O requests, particularly for device-dependent I/O functions. For complete details about how to use the I/O status block, see the VSI OpenVMS I/O User's Reference Manual.
7.11. Deassigning I/O Channels
$DASSGN_S CHAN=TTCHAN
This service call releases the terminal channel assignment acquired in the SYS$ASSIGN example shown in Section 7.5, “Assigning Channels”. The system automatically deassigns channels for a process when the image that assigned the channel exits.
7.12. Using Complete Terminal I/O
#include <descrip.h> #include <iodef.h> #include <lib$routines.h> #include <ssdef.h> #include <starlet.h> #include <stdio.h> #include <string.h> #define BUFSIZ 80 /* I/O status block */ struct {unsigned short iostat, ttiolen; unsigned int dev_info; }ttiosb; main() { unsigned int status ,outlen, inlen = BUFSIZ; unsigned short ttchan; char buffer[BUFSIZ];
$DESCRIPTOR(ttname,"SYS$INPUT");
/* Assign a channel */ status = SYS$ASSIGN(&ttname, /* devnam - device number */
&ttchan, /* chan - channel number */ 0, 0, 0); if (!$VMS_STATUS_SUCCESS(status)) LIB$SIGNAL( status ); /* Request I/O */ status = SYS$QIOW(0, /* efn - event flag */ ttchan, /* chan - channel number */ IO$_READVBLK, /* func - function modifier */ &ttiosb, /* iosb - I/O status block */ 0, /* astadr - AST routine */ 0, /* astprm - AST parameter */ buffer, /* p1 - buffer */ inlen, /* p2 - length of buffer */ 0, 0, 0, 0);
if (!$VMS_STATUS_SUCCESS( status ))
LIB$SIGNAL( status ); /* Get length from IOSB */ outlen = ttiosb.ttiolen;
status = SYS$QIOW(0, ttchan, IO$_WRITEVBLK, &ttiosb, 0, 0, buffer, outlen, 0, 0, 0, 0); if (!$VMS_STATUS_SUCCESS( status )) LIB$SIGNAL( status );
/* Deassign the channel */ status = SYS$DASSGN( ttchan ); /* chan - channel */
if (!$VMS_STATUS_SUCCESS( status )) LIB$SIGNAL( status ); }
The IOSB for the I/O operations is structured so that the program can easily check for the completion status (in the first word) and the length of the input string returned (in the second word). | |
The string will be read into the buffer BUFFER; the longword OUTLEN will contain the length of the string for the output operation. | |
The TTNAME label is a character string descriptor for the logical device SYS$INPUT, and TTCHAN is a word to receive the channel number assigned to it. | |
The $ASSIGN service assigns a channel and writes the channel number at TTCHAN. | |
If the $ASSIGN service completes successfully, the $QIOW macro reads a line from the terminal, and requests that the completion status be posted in the I/O status block defined at TTIOSB. | |
The process waits until the I/O is complete, then checks the first word in the I/O status block for a successful return. If unsuccessful, the program takes an error path. | |
The length of the string read is moved into the longword at OUTLEN, because the $QIOW macro requires a longword argument. However, the length field of the I/O status block is only 1 word long. The $QIOW macro writes the line just read to the terminal. | |
The program performs error checks. First, it ensures that the $OUTPUT macro successfully queued the I/O request; then, when the request is completed, it ensures that the I/O was successful. | |
When all I/O operations on the channel are finished, the channel is deassigned. |
7.13. Canceling I/O Requests
If a process must cancel I/O requests that have been queued but not yet completed, it can issue the Cancel I/O On Channel (SYS$CANCEL) system service. All pending I/O requests issued by the process on that channel are canceled; you cannot specify a particular I/O request.
The SYS$CANCEL system service performs an asynchronous cancel operation. This means that the application must wait for each I/O operation issued to the driver to complete before checking the status for that operation.
unsigned int status, efn1=3, efn2=4; . . . status = SYS$QIO(efn1, ttchan, &iosb1, ...); status = SYS$QIO(efn2, ttchan, &iosb2, ...); . . . status = SYS$CANCEL(ttchan); status = SYS$SYNCH(efn1, &iosb1); status = SYS$SYNCH(efn2, &iosb2);
In this example, the SYS$CANCEL system service initiates the cancellation of all pending I/O requests to the channel whose number is located at TTCHAN.
The SYS$CANCEL system service returns after initiating the cancellation of the I/O requests. If the call to SYS$QIO specified either an event flag, AST service routine, or I/O status block, the system sets either the flag, delivers the AST, or posts the I/O status block as appropriate when the cancellation is completed.
7.14. Logical Names and Physical Device Names
When you specify a device name as input to an I/O system service, it can be a physical device name or a logical name. If the device name contains a colon (:), the colon and the characters after it are ignored. When an underscore character (_) precedes a device name string, it indicates that the string is a physical device name string, for example, _TTB3:.
System Service |
Definition |
---|---|
SYS$ALLOC |
Allocate Device |
SYS$ASSIGN |
Assign I/O Channel |
SYS$BRDCST |
Broadcast |
SYS$DALLOC |
Deallocate Device |
SYS$DISMOU |
Dismount Volume |
SYS$GETDEV |
Get I/O Device Information |
|