OpenVMS Programming Concepts Manual
18.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, 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.
A VAX BLISS program calls a procedure using the by-reference mechanism
as follows:
The equivalent VAX MACRO code is as follows:
ONE: .LONG 1 ; Longword value 1
.
.
.
PUSHAL ONE ; Push address of longword
CALLS #1,G^LIB$FLT_UNDER ; Call LIB$FLT_UNDER
|
A C language program calls a procedure using the by-reference mechanism
as follows:
/* 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. */
.
.
.
}
}
|
18.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 Chapter 11.
On Alpha processors, the address is sign-extended from 32 bits to 64
bits.
This mechanism is used to pass more complicated data. For both Alpha
and VAX systems, a descriptor includes at least the following fields:
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 OpenVMS Calling Standard describes these fields in greater detail.
OpenVMS high-level languages include extensions for passing arguments
by descriptor. When you specify by descriptor in these languages, the
compiler creates the descriptor, defines its fields, and passes the
address of the descriptor to the OpenVMS system routine. In some
languages, by descriptor is the default passing mechanism for certain
types of arguments, such as character strings. For example, the default
mechanism for passing strings in BASIC is by descriptor.
100 COMMON STRING GREETING = 30
200 CALL LIB$PUT_SCREEN(GREETING)
|
The default mechanism for passing strings in COBOL, however, is by
reference. Therefore, when passing a string argument to an OpenVMS
system routine from a COBOL program, you must specify BY DESCRIPTOR for
the string argument in the CALL statement.
CALL LIB$PUT_OUTPUT USING BY DESCRIPTOR GREETING
|
In VAX MACRO or BLISS, you must define the descriptor's fields
explicitly and push its address onto the stack. Following is the VAX
MACRO code that corresponds to the previous examples.
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
|
The equivalent BLISS code looks like this:
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
|
A C language program calls a procedure using the by-descriptor
mechanism as follows:
/* 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);
.
.
.
}
|
18.6 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.
18.7 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.
18.8 Passing Strings as Arguments
Strings are passed by descriptor to OpenVMS system routines.
Table 18-5 lists the string-passing descriptors recognized by a
system routine.
Table 18-5 String-Passing Descriptors
Descriptor Function |
Descriptor Class Code |
Numeric Value |
Unspecified
|
DSC$K_CLASS_Z
|
0
|
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
|
An OpenVMS system routine writes strings according to the following
types of semantics:
- 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
18.9 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 18-9, 18-10, and 18-11
show all possible combinations of descriptor classes and data types.
For example, Figure 18-9 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.
Figure 18-9 Atomic Data Types and Descriptor Classes
Figure 18-10 String Data Types and Descriptor Classes
Figure 18-11 Miscellaneous Data Types and Descriptor
Classes
18.10 Return of the Function Value
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.
On VAX systems, if the actual function value returned is greater than
32 bits, then both R0 and R1 should be used.
On 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.
A standard function must return its function value by one of the
following mechanisms:
- 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 18.11.
18.11 Return of the Condition Value
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
or by error signaling.
A condition value in R0, 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 18-12). 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.
Figure 18-12 Condition Value Format
When the completion code is signaled, the calling program must
establish a handler to get control and take appropriate action. (See
the OpenVMS Programming Concepts Manual or the OpenVMS Calling Standard for a description of signaling
and condition handling and for more information about the condition
value.)
Chapter 19 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 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.
19.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 Compaq 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 19-1 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.
Figure 19-1 Calling the Run-Time Library
Although library routines can always call either other library routines
or the operating system, they can call user procedures only in the
following cases:
- 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
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.
19.2 Call Instructions
Each run-time library routine requires a specific calling sequence.
This calling sequence indicates the elements that you must include when
calling the routine, and the order of those elements. The form of a
calling sequence first specifies the type of call being made. A library
routine can be invoked either by a CALL instruction or possibly by a
JSB instruction (for VAX systems only) as follows:
- 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)
On VAX systems, the following restrictions apply to the different types
of calls:
- 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.
19.2.1 Facility Prefix and Routine Name
Each routine is identified by a unique entry point name consisting of
the facility prefix (for example, MTH$) and the procedure name (for
example, MTH$SIN). Run-time library entry points follow the OpenVMS
conventions for naming global symbols. A global entry point takes the
following general form:
The elements that make up this format represent the following:
|
fac
|
A 2- or 3-character facility name
|
|
symbol
|
A 1- to 27-character symbol
|
The facility names are maintained in a systemwide Compaq 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 Compaq
and 1 for those assigned by Application Project Services (APS) and
customers. For further information, refer to the OpenVMS Calling Standard.
The run-time library facility names are as follows:
|
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
|
|