HP OpenVMS Systems Documentation

Content starts here

HP Fortran for OpenVMS
User Manual


Previous Contents Index

10.8.2 Calling System Services by Function Reference

In most cases, you should check the return status after calling a system service. Therefore, you should invoke system services by function reference rather than by issuing a call to a subroutine.

For example:


  INCLUDE '($SSDEF)'
  INCLUDE '($SYSSRVNAM)'
  INTEGER (KIND=2) CHANNEL
     .
     .
     .
  MBX_STATUS = SYS$CREMBX(,CHANNEL,,,,,'MAILBOX')
  IF (MBX_STATUS .NE. SS$_NORMAL) GO TO 100

In this example, the system service referenced is the Create Mailbox system service. An INTEGER (KIND=2) variable (CHANNEL) is declared to receive the channel number.

The function reference allows a return status value to be stored in the variable MBX_STATUS, which can then be checked for correct completion on return. If the function's return status is not SS$_NORMAL, failure is indicated and control is transferred to statement 100. At that point, some form of error processing can be undertaken.

You can also test the return status of a system service as a logical value. The status codes are defined so that when they are tested as logical values, successful codes have the value true and error codes have the value false. The last line in the preceding example could then be changed to the following:


IF (.NOT. MBX_STATUS) GO TO 100

Refer to the HP OpenVMS System Services Reference Manual for information concerning return status codes. The return status codes are included in the description of each system service.

10.8.3 Calling System Services as Subroutines

Subroutine calls to system services are made like other subroutine calls. For example, to call the Create Mailbox system service, issue a call to SYS$CREMBX, passing the appropriate arguments to it, as follows:


CALL SYS$CREMBX(,CHANNEL,,,,,'MAILBOX')

This call corresponds to the function reference described in Section 10.8.2. The main difference is that the status code returned by the system service is not tested. For this reason, you should avoid this method and use a function reference when calling system services whenever the service could fail for any reason.

10.8.4 Passing Arguments to System Services

The description of each system service in the HP OpenVMS System Services Reference Manual specifies the argument-passing method for each argument. Four methods are supported:

  • By immediate value
  • By address: this is the HP Fortran default and is termed "by reference"
  • By descriptor: this is the HP Fortran default for CHARACTER arguments, Fortran 90 pointers, and certain types of arrays (see Section 10.2.7)
  • By data structure

These methods are discussed separately in Section 10.8.4.1 through Section 10.8.4.4.

You can determine the arguments required by a system service from the service description in the HP OpenVMS System Services Reference Manual. Each system service description indicates the service name, the number of arguments required, and the positional dependency of each argument.

Table 10-6 lists the HP Fortran declarations that you can use to pass any of the standard OpenVMS data types as arguments. OpenVMS data types are defined in OpenVMS Programming Interfaces: Calling a System Routine.

Instead of using record structure declarations for most standard OpenVMS data types, you can consider using derived-type structures if you use the SEQUENCE statement and are careful of alignment. However, RMS control block structures must be declared as record structures (STRUCTURE statement).

Table 10-6 HP Fortran Implementation of OpenVMS Data Types
OpenVMS Data Type HP Fortran Declaration
access_bit_names INTEGER (KIND=4) (2,32)
or
STRUCTURE /access_bit_names/
INTEGER (KIND=4) access_name_len
INTEGER (KIND=4) access_name_buf
END STRUCTURE !access_bit_names
RECORD /access_bit_names/ my_names(32)
access_mode BYTE or INTEGER (KIND=1)
address INTEGER (KIND=4)
address_range INTEGER (KIND=4) (2)
or
STRUCTURE /address_range/
INTEGER (KIND=4) low_address
INTEGER (KIND=4) high_address
END STRUCTURE
arg_list INTEGER (KIND=4)(n)
ast_procedure EXTERNAL
boolean LOGICAL (KIND=4)
byte_signed BYTE or INTEGER (KIND=1)
byte_unsigned BYTE or INTEGER (KIND=1) 1
channel INTEGER (KIND=2)
char_string CHARACTER (LEN= n) 2
complex_number COMPLEX (KIND=4) 3
COMPLEX (KIND=8) 3
cond_value INTEGER (KIND=4)
context INTEGER (KIND=4)
date_time INTEGER (KIND=8)
device_name CHARACTER (LEN= n)
ef_cluster_name CHARACTER (LEN= n)
ef_number INTEGER (KIND=4)
exit_handler_block STRUCTURE /exhblock/
INTEGER (KIND=4) flink
INTEGER (KIND=4) exit_handler_addr
BYTE(3) %FILL
BYTE arg_count
INTEGER (KIND=4) cond_value
! .
! .(optional arguments ...
! . one argument per longword)
!
END STRUCTURE !cntrlblk

RECORD /exhblock/ myexh_block
fab INCLUDE '($FABDEF)'
RECORD /FABDEF/ myfab
file_protection INTEGER (KIND=4)
floating_point REAL (KIND=4) 3
REAL (KIND=8) 3
DOUBLE PRECISION 3
REAL (KIND=16) 3
function_code INTEGER (KIND=4)
identifier INTEGER (KIND=4)
invo_context_blk INCLUDE '($LIBICB)'
RECORD /INVO_CONTEXT_BLK/ invo_context_blk
invo_handle INTEGER (KIND=4)
io_status_block STRUCTURE /iosb/
INTEGER (KIND=2) iostat, ! return status
INTEGER (KIND=2) term_offset, ! Loc. of terminator
INTEGER (KIND=2) terminator, ! terminator value
INTEGER (KIND=2) term_size ! terminator size
END STRUCTURE

RECORD /iosb/ my_iosb
item_list_2 STRUCTURE /itmlst/
UNION
MAP
INTEGER (KIND=2) buflen,code
INTEGER (KIND=4) bufadr
END MAP
MAP
INTEGER (KIND=4) end_list /0/
END MAP
END UNION
END STRUCTURE !itmlst

RECORD /itmlst/ my_itmlst_2(n)
(Allocate n records, where n is the number item codes plus an extra element for the end-of-list item.)
item_list_3 STRUCTURE /itmlst/
UNION
MAP
INTEGER (KIND=2) buflen,code
INTEGER (KIND=4) bufadr,retlenadr
END MAP
MAP
INTEGER (KIND=4) end_list /0/
END MAP
END UNION
END STRUCTURE !itmlst

RECORD /itmlst/ my_itmlst_3(n)
(Allocate n records where n is the number item codes plus an extra element for the end-of-list item.)
item_list_pair STRUCTURE /itmlist_pair/
UNION
MAP
INTEGER (KIND=4) code
INTEGER (KIND=4) value
END MAP
MAP
INTEGER (KIND=4) end_list /0/
END MAP
END UNION
END STRUCTURE !itmlst_pair

RECORD /itmlst_pair/ my_itmlst_pair(n)
(Allocate n records where n is the number item codes plus an extra element for the end-of-list item.)
item_quota_list STRUCTURE /item_quota_list/
MAP
BYTE quota_name
INTEGER (KIND=4) quota_value
END MAP
MAP
BYTE end_quota_list
END MAP
END STRUCTURE !item_quota_list
lock_id INTEGER (KIND=4)
lock_status_block STRUCTURE/lksb/
INTEGER (KIND=2) cond_value
INTEGER (KIND=2) unused
INTEGER (KIND=4) lock_id
BYTE(16)
END STRUCTURE !lksb

RECORD /lksb/ my_lksb
lock_value_block BYTE(16)
logical_name CHARACTER (LEN= n)
longword_signed INTEGER (KIND=4)
longword_unsigned INTEGER (KIND=4) 1
mask_byte INTEGER (KIND=1) ! (or BYTE)
mask_longword INTEGER (KIND=4)
mask_quadword INTEGER (KIND=8)
mask_word INTEGER (KIND=2)
mechanism_args INCLUDE '($CHFDEF)'
RECORD /CHFDEF2/ mechargs
! (For more information, see Section 14.6.)
null_arg %VAL(0) ! (or an unspecified optional argument)
octaword_signed INTEGER (KIND=4)(4)
octaword_unsigned INTEGER (KIND=4)(4) 1
page_protection INTEGER (KIND=4)
procedure INTEGER (KIND=4)
process_id INTEGER (KIND=4)
process_name CHARACTER (LEN= n)
quadword_signed INTEGER (KIND=8)
quadword_unsigned INTEGER (KIND=8) 1
rights_holder STRUCTURE /rights_holder/
INTEGER (KIND=4) rights_id
INTEGER (KIND=4) rights_mask
END STRUCTURE !rights_holder

RECORD /rights_holder/ my_rights_holder
rights_id INTEGER (KIND=4)
rab INCLUDE '($RABDEF)'
RECORD /RABDEF/ myrab
section_id INTEGER (KIND=4)(2) or INTEGER (KIND=8)
section_name CHARACTER (LEN= n)
system_access_id INTEGER (KIND=4)(2) or INTEGER (KIND=8)
time_name CHARACTER (LEN=23)
transaction_id INTEGER (KIND=4)(4)
uic INTEGER (KIND=4)
user_arg Any longword quantity
varying_arg Any appropriate type
vector_byte_signed BYTE(n)
vector_byte_unsigned BYTE(n) 1
vector_longword_signed INTEGER(KIND=4) (n)
vector_longword_unsigned INTEGER(KIND=4) (n) 1
vector_quadword_signed INTEGER(KIND=8) (n)
vector_quadword_unsigned INTEGER (KIND=8) (n) 1
vector_word_signed INTEGER (KIND=2) (n)
vector_word_unsigned INTEGER (KIND=2) (n) 1
word_signed INTEGER (KIND=2) (n)
word_unsigned INTEGER (KIND=2) (n) 1

1Unsigned data types are not directly supported by HP Fortran. However, in most cases you can substitute the signed equivalent, provided you do not exceed the range of the signed data structure.
2Where n can range from 1 to 65535.
3The format used by floating-point (KIND=4) and (KIND=8) data in memory is determined by the FORTRAN command qualifier /FLOAT.

Many arguments to system services are optional. However, if you omit an optional argument, you must include a comma (,) to indicate the absence of that argument. For example, the SYS$TRNLNM system service takes five arguments. If you omit the first and the last two arguments, you must include commas to indicate their existence, as follows:


ISTAT = SYS$TRNLNM(,'LNM$FILE_DEV','LOGNAM',,)

An invalid reference results if you specify the arguments as follows:


ISTAT = SYS$TRNLNM('LOGNAM',LENGTH,BUFFA)

This reference provides only three arguments, not the required five.

When you omit an optional argument by including an extra comma, the compiler supplies a default value of zero (passed by immediate value).

10.8.4.1 Immediate Value Arguments

Value arguments are typically used when the description of the system service specifies that the argument is a "number," "mask," "mode," "value," "code," or "indicator." You must use either the cDEC$ ATTRIBUTES VALUE (see Section 10.4.2.3) or the %VAL built-in function (see Section 10.3.3) whenever this method is required.

Immediate value arguments are used for input arguments only.

10.8.4.2 Address Arguments

Use address arguments when the description of the system service specifies that the argument is "the address of." (However, refer to Section 10.8.4.3 to determine what to do when "the address of a descriptor" is specified.) In HP Fortran, this argument-passing method is called "by reference."

Because this method is the HP Fortran default for passing numeric arguments, you need to specify the cDEC$ ATTRIBUTES REFERENCE directive (see Section 10.4.2.3) or the %REF built-in function only when the data type of the argument is character.

The argument description also gives the hardware data type required.

For arguments described as "address of an entry mask" or "address of a routine," declare the argument value as an external procedure. For example, if a system service requires the address of a routine and you want to specify the routine HANDLER3, include the following statement in the declarations portion of your program:


EXTERNAL HANDLER3
This specification defines the address of the routine for use as an input argument.

Address arguments are used for both input and output:

  • For input arguments that refer to byte, word, longword, or quadword values, you can specify either constants or variables. If you specify a variable, you must declare it to be equal to or longer than the data type required. Table 10-7 lists the variable data type requirements for both input and output arguments.
  • For output arguments you must declare a variable of exactly the length required to avoid including extraneous data. If, for example, the system returns a byte value in a word-length variable, the leftmost eight bits of the variable are not overwritten on output. The variable, therefore, might not contain the data you expect.
    To store output produced by system services, you must allocate sufficient space to contain the output. You make this allocation by declaring variables of the proper size. For an illustration, refer to the Translate Logical Name system service example in Section 10.8.4.3. This service returns the length of the equivalent name string as a 2-byte value.
    If the output is a quadword value, you must declare a variable of the proper dimensions. For example, to use the Get Time system service (SYS$GETTIM), which returns the time as a quadword binary value, declare the following:


    INCLUDE '($SYSSRVNAM)'
    INTEGER (KIND=8)  SYSTIM
       .
       .
       .
    ISTAT = SYS$GETTIM(SYSTIM)
    

    The type declaration INTEGER (KIND=8) SYSTIM establishes a variable consisting of one quadword, which is then used to store the time value.

Table 10-7 Variable Data Type Requirements
OpenVMS Type Required Input Argument Declaration Output Argument Declaration
Byte BYTE, INTEGER (KIND=1), INTEGER (KIND=2), INTEGER (KIND=4) BYTE, INTEGER (KIND=1)
Word INTEGER (KIND=2), INTEGER (KIND=4) INTEGER (KIND=2)
Longword INTEGER (KIND=4) INTEGER (KIND=4)
Quadword INTEGER (KIND=8) or INTEGER (KIND=4) (2) or properly dimensioned array INTEGER (KIND=8) or INTEGER (KIND=4) (2) or properly dimensioned array
Indicator LOGICAL  
Character string descriptor CHARACTER (LEN= n) CHARACTER (LEN= n)
Entry mask or routine EXTERNAL  

10.8.4.3 Descriptor Arguments

Descriptor arguments are used for input and output of character strings. Use a descriptor argument when the argument description specifies "address of a descriptor." Because this method is the HP Fortran default for character arguments, you need to specify the %DESCR built-in function only when the data type of the argument is not character.

On input, a character constant, variable, array element, or expression is passed to the system service by descriptor. On output, two items are needed:

  • The character variable or array element to hold the output string
  • An INTEGER (KIND=2) variable that is set to the actual length of the output string

In the following example of the Translate Logical Name system service (SYS$TRNLNM), the logical name LOGNAM is translated to its associated name or file specification. The output string and string length are stored in the variables EQV_BUFFER and W_NAMELEN, respectively:


INCLUDE '($LNMDEF)'
INCLUDE '($SYSSRVNAM)'

STRUCTURE /LIST/
  INTEGER (KIND=2) BUF_LEN/255/
  INTEGER (KIND=2) ITEM_CODE/LNM$_STRING/
  INTEGER (KIND=4) TRANS_LOG
  INTEGER (KIND=4) TRANS_LEN
  INTEGER (KIND=4) END_ENTRY/0/
END STRUCTURE    !LIST

CHARACTER (LEN=255) EQV_BUFFER
INTEGER (KIND=2)  W_NAMELEN

RECORD/LIST/ ITEM_LIST
ITEM_LIST.TRANS_LOG = %LOC(EQV_BUFFER)
ITEM_LIST.TRANS_LEN = %LOC(W_NAMELEN)

ISTAT = SYS$TRNLNM(, 'LNM$FILE_DEV', 'FOR$SRC', ,ITEM_LIST)
IF (ISTAT) PRINT *, EQV_BUFFER(:W_NAMELEN)
END

10.8.4.4 Data Structure Arguments

Data structure arguments are used when the argument description specifies "address of a list," "address of a control block," or "address of a vector." The data structures required for these arguments are constructed in HP Fortran with structure declaration blocks and the RECORD statement. The storage declared by a RECORD statement is allocated in exactly the order given in the structure declaration, with no space between adjacent items. For example, the item list required for the SYS$GETJPI (or SYS$GETJPIW) system service requires a sequence of items of two words and two longwords each. By declaring each item as part of a structure, you ensure that the fields and items are allocated contiguously:


STRUCTURE /GETJPI_STR/
        INTEGER (KIND=2) BUFLEN, ITMCOD
        INTEGER (KIND=4) BUFADR, RETLEN
END STRUCTURE
...
RECORD /GETJPI_STR/ LIST(5)

If a given field is provided as input to the system service, the calling program must fill the field before the system service is called. You can accomplish this with data initialization (for fields with values that are known at compile time) and with assignment statements (for fields that must be computed).

When the data structure description requires a field that must be filled with an address value, use the %LOC built-in function to generate the desired address (see Section 10.3.2). When the description requires a field that must be filled with a symbolic value (system-service function code), you can define the value of the symbol by the method described in Section 10.8.1.


Previous Next Contents Index