Compaq Fortran
User Manual for
OpenVMS Alpha Systems


Previous Contents Index

10.7 Calling OpenVMS System Services

You can invoke system services in a Compaq Fortran program with a function reference or a subroutine CALL statement that specifies the system service you want to use. To specify a system service, use the form:

SYS$service-name(arg,...,arg)

You pass arguments to the system services according to the requirements of the particular service you are calling; the service may require an immediate value, an address, the address of a descriptor, or the address of a data structure. Section 10.7.4 describes the Compaq Fortran syntax rules for each of these cases. See the OpenVMS System Services Reference Manual for a full definition of individual services.

The basic steps for calling system services are the same as those for calling any external routine. However, when calling system services (or Run-Time Library routines), additional information is often required. The sections that follow describe these requirements.

10.7.1 Obtaining Values for System Symbols

OpenVMS uses symbolic names to identify the following values or codes for system services:

The values chosen determine the specific action performed by the service.

The OpenVMS System Services Reference Manual describes the symbols that are used with each system service. The VMS I/O User's Reference Volume describes the symbols that are used with I/O-related services.

The Compaq Fortran symbolic definition library FORSYSDEF contains Compaq Fortran source definitions for related groups of system symbols. Each related group of system symbols is stored in a separate text library module; for example, the library module $IODEF in FORSYSDEF contains PARAMETER statements that define the I/O function codes.

The library modules in FORSYSDEF correspond to the symbolic definition macros that OpenVMS MACRO programmers use to define system symbols. The library modules have the same names as the macros and contain Compaq Fortran source code, which is functionally equivalent to the MACRO source code. To determine whether you need to include other symbol definitions for the system service you want to use, refer to the documentation for that particular system service. If the documentation states that values are defined in a macro, you must include those symbol definitions in your program.

For example, the description for the flags argument in the SYS$MGBLSC (Map Global Section) system service states that "Symbolic names for the flag bits are defined by the $SECDEF macro." Therefore, when you call SYS$MGBLSC, you must include the definitions provided in the $SECDEF macro.

Library module $SYSSRVNAM in FORSYSDEF contains declarations for all system-service names. It contains the necessary INTEGER and EXTERNAL declarations for the system-service names. (The library module, once extracted from FORSYSDEF.TLB, also contains comments describing the arguments for each of the system services.) Also, library module $SSDEF contains system-service return status codes and is generally required whenever you access any of the services.

The library modules in FORSYSDEF contain definitions for constants, bit masks, and data structures. See Section 10.7.4.4 for a description of how to create data structure arguments in Compaq Fortran. Refer to Appendix D for a list of library modules that are in FORSYSDEF.

You can access the library modules in the FORSYSDEF library with the INCLUDE statement, using the following format:

INCLUDE '(library-module-name)'

The notation library-module-name represents the name of a library module contained in FORSYSDEF. The library FORSYSDEF is searched if the specified library module was not found in a previously searched library.

10.7.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 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.7.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.7.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.7.4 Passing Arguments to System Services

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

These methods are discussed separately in Section 10.7.4.1 through Section 10.7.4.4.

You can determine the arguments required by a system service from the service description in the 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 Compaq Fortran declarations that you can use to pass any of the standard OpenVMS data types as arguments. OpenVMS data types are defined in the 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 Compaq Fortran Implementation of OpenVMS Data Types
OpenVMS Data Type Compaq 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 1 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.5.)
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 Compaq 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. When passing character constant actual arguments in older Compaq Fortran 77 for OpenVMS VAX programs, see Section 2.3.8.
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.7.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.3.2.3) or the %VAL built-in function (see Section 10.2.3) whenever this method is required.

Immediate value arguments are used for input arguments only.

10.7.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.7.4.3 to determine what to do when "the address of a descriptor" is specified.) In Compaq Fortran, this argument-passing method is called "by reference."

Because this method is the Compaq Fortran default for passing numeric arguments, you need to specify the cDEC$ ATTRIBUTES REFERENCE directive (see Section 10.3.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.

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.7.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 Compaq 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:

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.7.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 Compaq 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.2.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.7.1.

10.7.4.5 Examples of Passing Arguments

Example 10-4 shows a complete subroutine that uses a data structure argument to the SYS$GETJPIW system service:

Example 10-4 Subroutine Using a Data Structure Argument

!  Subroutine to obtain absolute and incremental values of process parameters: 
!  CPU time, Buffered I/O count, Direct I/O count, Page faults. 
 
      SUBROUTINE PROCESS_INFO(ABS_VALUES, INCR_VALUES) 
 
!  Declare the arguments and working storage 
 
      INTEGER (KIND=4) ABS_VALUES(4), INCR_VALUES(4), LCL_VALUES(4) 
      INTEGER (KIND=4) STATUS, I 
 
!  Declare the SYS$GETJPIW item list data structure in a structure declaration 
 
      STRUCTURE /GETJPI_STR/ 
              INTEGER (KIND=2)  BUFLEN /4/, ITMCOD /0/ 
              INTEGER (KIND=4)  BUFADR, RETLEN /0/ 
      END STRUCTURE 
 
!  Create a record with the fields defined in the structure declaration 
 
      RECORD /GETJPI_STR/ LIST(5) 
 
!  Declare the structure of an I/O Status Block 
 
      STRUCTURE /IOSB_STR/ 
           INTEGER (KIND=4) STATUS, RESERVED 
      END STRUCTURE 
 
!  Declare the I/O Status Block 
 
      RECORD /IOSB_STR/ IOSB         
 
!  Assign all static values in the item list 
 
      LIST(1).ITMCOD = JPI$_CPUTIM 
      LIST(2).ITMCOD = JPI$_BUFIO 
      LIST(3).ITMCOD = JPI$_DIRIO 
      LIST(4).ITMCOD = JPI$_PAGEFLTS 
 
!  Assign all item fields requiring addresses 
 
      LIST(1).BUFADR = %LOC(LCL_VALUES(1)) 
      LIST(2).BUFADR = %LOC(LCL_VALUES(2)) 
      LIST(3).BUFADR = %LOC(LCL_VALUES(3)) 
      LIST(4).BUFADR = %LOC(LCL_VALUES(4)) 
 
      STATUS = SYS$GETJPIW(,,,LIST,IOSB,,)  ! Perform system service call 
 
      IF (STATUS) STATUS = IOSB.STATUS      ! Check completion status 
      IF (.NOT. STATUS) CALL EXIT (STATUS) 
 
!  Assign the new values to the arguments 
 
      DO I=1,4 
         INCR_VALUES(I) = LCL_VALUES(I) - ABS_VALUES(I) 
         ABS_VALUES(I)  = LCL_VALUES(I) 
      END DO 
      RETURN 
 
      END SUBROUTINE PROCESS_INFO 

Example 10-5 is an example of the typical use of an I/O system service. The program invokes SYS$QIOW to enable Ctrl/C trapping. When the program runs, it prints an informational message whenever it is interrupted by a Ctrl/C, and then it continues execution:

Example 10-5 Ctrl/C Trapping Example

   PROGRAM TRAPC 
   INCLUDE '($SYSSRVNAM)' 
   INTEGER (KIND=2) TT_CHAN 
   COMMON TT_CHAN 
   CHARACTER (LEN=40) LINE 
 
!  Assign the I/O channel.  If unsuccessful stop; otherwise 
!  initialize the trap routine. 
 
   ISTAT = SYS$ASSIGN ('TT',TT_CHAN,,) 
   IF (.NOT. ISTAT) CALL LIB$STOP(%VAL(ISTAT)) 
   CALL ENABLE_CTRLC 
 
!     Read a line of input and echo it 
 
 10 READ (5,'(A)',END=999) LINE 
    TYPE *, 'LINE READ: ', LINE 
    GO TO 10 
999 END 
 
    SUBROUTINE ENABLE_CTRLC 
    INTEGER (KIND=2) TT_CHAN 
    COMMON TT_CHAN 
    EXTERNAL CTRLC_ROUT 
 
!   Include I/O symbols 
 
    INCLUDE '($IODEF)' 
    INCLUDE '($SYSSRVNAM)' 
 
!     Enable Ctrl/C trapping and specify CTRLC_ROUT 
!     as routine to be called when Ctrl/C occurs 
 
    ISTAT = SYS$QIOW( ,%VAL(TT_CHAN), %VAL(IO$_SETMODE .OR. IO$M_CTRLCAST),& 
        ,,,CTRLC_ROUT,,%VAL(3),,,) 
    IF (.NOT. ISTAT) CALL LIB$STOP(%VAL(ISTAT)) 
    RETURN 
    END SUBROUTINE ENABLE_CTRLC 
 
    SUBROUTINE CTRLC_ROUT 
    PRINT *, 'Ctrl/C pressed' 
    CALL ENABLE_CTRLC 
    RETURN 
 
    END SUBROUTINE CTRLC_ROUT 

For more examples of calling system services and RTL routines, see Appendix E.


Previous Next Contents Index