|
OpenVMS Programming Concepts Manual
20.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
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.
20.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 C data structures and definitions. For more information
about SYS$LIBRARY:SYS$LIB_C.TLB, refer to Chapter 21.
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.
If your language does not have such a method, you can do the following:
- 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.
For example, to use the Get Job/Process Information ($GETJPI) system
service to find out the accumulated CPU time (in 10-millisecond ticks)
for a specified process, you must obtain the value associated with the
item identifier JPI$_CPUTIM. You can do this in the following way:
- 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
|
- 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. 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.
20.4.6 Testing the Return Condition Value for Assembly Languages
To check for successful completion after a system service call, the
program can test the low-order bit of R0 and branch to an
error-checking routine if this bit is not set, as follows:
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.
The error-checking routine may check for specific values or for
specific severity levels. For example, the following VAX MACRO
instruction checks for an illegal event flag number error condition:
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.
20.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.
The following VAX MACRO code fragment shows a simple error-checking
procedure in a main program:
$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.
If the event flag cluster requested in this call to $READEF is not
currently available to the process, the program exits and the command
interpreter displays the following message:
%SYSTEM-F-UNASEFC, unassociated event flag cluster
|
The keyword UNASEFC in the message corresponds to the condition value
SS$_UNASEFC.
The following three severe errors generated by the calls, not the
services, can be returned from calls to system services:
Error |
Meaning |
SS$_ACCVIO
|
The argument list cannot be read by the caller (using the $
name_G macro), and the service is not called.
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.
|
20.5 Program Examples with System Service Calls
This section provides code examples that illustrate the use of a system
service call in the following programming languages:
Ada --- Example 20-2
BASIC --- Example 20-3
BLISS --- Example 20-4
C --- Example 20-5
COBOL --- Example 20-6
FORTRAN --- Example 20-7
Pascal --- Example 20-8
VAX MACRO --- Example 20-9
Example 20-2 System Service Call in Ada |
with SYSTEM, TEXT_IO, STARLET, CONDITION_HANDLING; (1)
procedure ORION is
-- Declare variables to hold equivalence name and length
--
EQUIV_NAME: STRING (1..255); (2)
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) := (3)
(1 =>
(ITEM_CODE => STARLET.LNM_STRING, (4)
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; (5)
begin
-- Translate the logical name
--
STARLET.TRNLNM ( (6)
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 (7)
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 fac$ names by
removing the dollar sign.
- 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.
Example 20-3 System Service Call in BASIC |
10 SUB ORION (1) ! 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, (2) ! Word to receive length
LONG SYS_STATUS ! Longword to receive status
COMMON (BUF) STRING NAME_STRING = 255 (3)
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
(4)
SYS_STATUS = SYS$TRNLNM( , 'LNM$FILE_DEV', 'CYGNUS',, ITEMS) (5)
IF (SYS_STATUS AND 1%) = 0% (6)
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.
Example 20-4 System Service Call in BLISS |
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); (1)
IF NOT .STATUS THEN ERROR_PROC(.STATUS); (2)
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 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.
Example 20-5 System Service Call in C |
#include <starlet.h> (1)
#include <lib$routines.h>
#include <ssdef.h>
#include <lnmdef.h>
#include <descrip.h>
#include <stdio.h>
typedef struct { (2)
unsigned short buffer_length;
unsigned short item_code;
char *buffer_addr;
short *return_len_addr;
unsigned terminator;
} item_list_t;
main ()
{ (3)
$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); (4)
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); (5)
if (!(status & 1)) (6)
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
starlet.h
defines OpenVMS system services entry points. The file
lib$routines.h
declares the LIB$ Run-Time Library routines.
- 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
sys$trnlnm
system service.
- The function
sizeof
is used to obtain the size of the string. The returned length will be
stored as a short integer in
return_length
.
- The
sys$trnlnm
routine is defined in
starlet.h
.
- 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.
Example 20-6 System Service Call in COBOL |
IDENTIFICATION DIVISION.
PROGRAM-ID. ORION. (1)
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. (2)
01 NAMLEN PIC S9(4) COMP.
01 ITMLIS.
02 BUFLEN PIC S9(4) COMP VALUE 225.
02 ITMCOD PIC S9(4) COMP VALUE 2. (3)
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. (4)
PROCEDURE DIVISION.
START-ORION.
CALL "SYS$TRNLNM" (5)
USING OMITTED
BY DESCRIPTOR TABNAM
BY DESCRIPTOR CYGDES (6)
OMITTED
BY REFERENCE ITMLIS
GIVING RESULT.
IF RESULT IS FAILURE (7)
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 20.4.5 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.
Example 20-7 System Service Call in
FORTRAN |
SUBROUTINE ORION
IMPLICIT NONE ! Require declaration of all symbols
INCLUDE '($SYSSRVNAM)' ! Declare system service names (1)
INCLUDE '($LNMDEF)' ! Declare $TRNLNM item codes
INCLUDE '(LIB$ROUTINES)' ! Declare LIB$ routines
STRUCTURE /ITEM_LIST_3_TYPE/ ! Structure of item list (2)
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 (3)
INTEGER*4 STATUS ! For returned service status (4)
! Fill in itemlist
!
ITEMLIST(1).ITMCOD = LNM$_STRING
ITEMLIST(1).BUFLEN = LEN(EQUIV_NAME) (5)
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 (6)
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 (7)
CALL LIB$SIGNAL(%VAL(STATUS))
ELSE
WRITE (*,*) 'CYGNUS translates to: "',
1 EQUIV_NAME(1:NAMLEN), '"'
END IF
END
|
FORTRAN Notes
|