HP Fortran for OpenVMS
User Manual


Previous Contents Index


Chapter 11
Using OpenVMS Record Management Services

This chapter describes:

11.1 Overview of OpenVMS Record Management Services

You can call OpenVMS Record Management Services (RMS) directly from HP Fortran programs. RMS is used by all utilities and languages for their I/O processing, allowing files to be accessed efficiently, flexibly, with device independence, and taking full advantage of the capabilities of the OpenVMS operating system.

You need to know the basic concepts concerning files on OpenVMS systems and system-service calling conventions before reading this chapter. Basic file concepts are covered in the Guide to OpenVMS File Applications, and system-service calling conventions are covered in Chapter 10.

You should also have access to the OpenVMS Record Management Services Reference Manual. Although not written specifically for HP Fortran programmers, it is the definitive reference source for all information on the use of RMS.

This chapter will help you understand the material in the OpenVMS Record Management Services Reference Manual in terms of Fortran concepts and usage. You should also be able to more fully understand the material in the Guide to OpenVMS File Applications, which covers more areas of RMS in greater detail than this chapter.

The easiest way to call RMS services directly from HP Fortran is to use a USEROPEN routine, which is a subprogram that you specify in an OPEN statement. The HP Fortran Run-Time Library (RTL) I/O support routines call the USEROPEN routine in place of the RMS services at the time a file is first opened for I/O.

The HP Fortran RTL sets up the RMS data structures on your behalf with initial field values that are based on parameters specified in your OPEN statement. This initialization usually eliminates most of the code needed to set up the proper input to RMS Services. If you specify the USEROPEN keyword in the OPEN statement, control transfers to the specified USEROPEN routine that can further change RMS data structures and then call the appropriate RMS services, including SYS$OPEN (or SYS$CREATE) and SYS$CONNECT.

When you use USEROPEN routines, you can take advantage of the power of RMS without most of the declarations and initialization code normally required. Section 11.4 describes how to use USEROPEN routines and gives examples. You should be familiar with the material in Section 11.2 before reading Section 11.4.

11.2 RMS Data Structures

RMS system services have so many options and capabilities that it is impractical to use anything other than several large data structures to provide their arguments. You should become familiar with all of the RMS data structures before using RMS system services.

The RMS data structures are:

The RMS data structures are used both to pass arguments to RMS services and to return information from RMS services to your program. In particular, an auxiliary structure, such as a NAM or XAB block, is commonly used explicitly to obtain information optionally returned from RMS services.

The OpenVMS Record Management Services Reference Manual describes how each of these data structures is used in calls to RMS services. In this section, a brief overview of each block is given, describing its purpose and how it is manipulated in HP Fortran programs.

In general, there are six steps to using the RMS control blocks in calls to RMS system services:

  1. Declare the structure of the blocks and the symbolic parameters used in them by including the appropriate definition library modules from the Fortran default library FORSYSDEF.TLB.
  2. Declare the memory allocation for the blocks that you need with a RECORD statement.
  3. Declare the system service names by including the library module $SYSSRVNAM from FORSYSDEF.TLB.
  4. Initialize the values of fields needed by the service you are calling. The structure definitions provided for these blocks in the FORSYSDEF library modules provide only the field names and offsets needed to reference the RMS data structures. You must assign all of the field values explicitly in your HP Fortran program.
    Two fields of each control block are mandatory; they must be filled in with the correct values before they are used in any service call. These are the block id (BID, or COD in the case of XABs) and the block length (BLN). These are checked by all RMS services to ensure that their input blocks have proper form.
    These fields must be assigned explicitly in your HP Fortran programs, unless you are using the control blocks provided by the Fortran RTL I/O routines, which initialize all control block fields. See Table 11-1 for a list of the control field values provided by the Fortran RTL I/O routines.
  5. Invoke the system service as a function reference, giving the control blocks as arguments according to the specifications in the RMS reference manual.
  6. Check the return status to ensure that the service has completed successfully.

Steps 1-4 are described for each type of control block in Section 11.2.2 to Section 11.2.5. See Section 11.3 for descriptions of steps 5 and 6.

11.2.1 Using FORSYSDEF Library Modules to Manipulate RMS Data Structures

The definition library FORSYSDEF.TLB contains the required Fortran declarations for all of the field offsets and symbolic values of field contents described in the OpenVMS Record Management Services Reference Manual. The appropriate INCLUDE statement needed to access these declarations for each structure is described wherever appropriate in the text that follows.

In general, you need to supply one or more RECORD statements to allocate the memory for the structures that you need. See the OpenVMS Record Management Services Reference Manual for a description of the naming conventions used in RMS service calls. Only the convention for the PARAMETER declarations is described here.

The FORSYSDEF library modules contain several different kinds of PARAMETER declarations. The declarations are distinguished from each other by the letter following the dollar sign ($) in their symbolic names. Each is useful in manipulating field values, but the intended use of the different kinds of PARAMETER declarations is as follows:

For most of the FAB, RAB, NAM, and XAB fields that are not supplied with symbolic values, you will need to supply sizes or pointers. For sizes, you can use ordinary numeric constants or other numeric scalar quantities. To set the maximum record number into the FAB$L_MRN field, you could use the following statement:


  MYFAB.FAB$L_MRN = 5000 

To supply the required pointers, usually from one block to another, you must use the %LOC built-in function to retrieve addresses. To fill in the FAB$L_NAM field in a FAB block with the address of the NAM block that you want to use, you can use the following program fragment:


INCLUDE '($FABDEF)' 
INCLUDE '($NAMDEF)' 
...
RECORD /FABDEF/ MYFAB, /NAMDEF/ MYNAM 
...
MYFAB.FAB$L_NAM = %LOC(MYNAM) 

11.2.2 File Access Block (FAB)

The File Access Block (FAB) is used for calling the following services:
SYS$CLOSE
SYS$CREATE
SYS$DISPLAY
SYS$ENTER
SYS$ERASE
SYS$EXTEND
SYS$OPEN
SYS$PARSE
SYS$REMOVE
SYS$RENAME
SYS$SEARCH

The purpose of the FAB is to describe the file being manipulated by these services. In addition to the fields that describe the file directly, there are pointers in the FAB structure to auxiliary blocks used for more detailed information about the file. These auxiliary blocks are the NAM block and one or more of the XAB blocks.

To declare the structure and parameter values for using FAB blocks, include the $FABDEF library module from FORSYSDEF. For example:


INCLUDE '($FABDEF)' 

To examine the fields and values declared, use the /LIST qualifier after the right parenthesis. Each field in the FAB is described at length in the OpenVMS Record Management Services Reference Manual.

If you are using a USEROPEN procedure, the actual allocation of the FAB is performed by the Fortran Run-Time Library I/O support routines, and you only need to declare the first argument to your USEROPEN routine to be a record with the FAB structure. For example:

Calling program:


...
EXTERNAL MYOPEN 
...
OPEN (UNIT=8, ..., USEROPEN=MYOPEN) 
...

USEROPEN routine:


INTEGER FUNCTION MYOPEN(FABARG, RABARG, LUNARG) 
INCLUDE '($FABDEF)' 
...
RECORD /FABDEF/ FABARG 
...

Usually, you need to declare only one FAB block, but some situations you need to use two. For example, the SYS$RENAME service requires one FAB block to describe the old file name and another to describe the new file name. In any of these cases, you can declare whatever FAB blocks you need with a RECORD statement. For example:


INCLUDE '($FABDEF)' 
...
RECORD /FABDEF/ OLDFAB, NEWFAB 

If you use any of the above service calls without using a USEROPEN routine, you must initialize the required FAB fields in your program. The FAB fields required for each RMS service are listed in the descriptions of the individual services in the OpenVMS Record Management Services Reference Manual. Most services also fill in output values in the FAB or one of its associated blocks. Descriptions of these output fields are also provided with the service descriptions.

In the example programs in the OpenVMS Record Management Services Reference Manual, these initial field values are described as they would be used in MACRO programs, where the declaration macros allow initialization arguments. In each case where the MACRO example shows a field being initialized in a macro, you must have a corresponding initialization at run time in your program.

The OpenVMS Record Management Services Reference Manual contains an example that shows the use of the ALQ parameter for specifying the initial allocation size of the file in blocks:


  !    Program that uses XABDAT and XABDAT_STORE 
   . 
   . 
   . 
 
  MYFAB: $FAB ALQ=500, FOP=CBT, FAC=<PUT>, - 
              FNM=<DISK$:[PROGRAM]SAMPLE_FILE.DAT>, - 
              ORG=SEQ, RAT=CR, RFM=VAR, SHR=<NIL>, MRS=52, XAB=MYXDAT 
 
   .
   .
   .

As described in the section on the XAB$L_ALQ field (in the same manual), this parameter sets the FAB field FAB$L_ALQ. To perform the same initialization in HP Fortran, you must supply a value to the FAB$L_ALQ field using a run-time assignment statement. For example:


MYFAB.FAB$L_ALQ = 500 

The FAB$B_BID and FAB$B_BLN fields must be filled in by your program prior to their use in an RMS service call, unless they have already been supplied by the HP Fortran RTL I/O routines. You should always use the symbolic names for the values of these fields; for example:


INCLUDE '($FABDEF)' 
...
RECORD /FABDEF/ MYFAB 
...
MYFAB.FAB$B_BID = FAB$C_BID 
MYFAB.FAB$B_BLN = FAB$C_BLN 
...
STATUS = SYS$OPEN( ... ) 
...

11.2.3 Record Access Block (RAB)

The Record Access Block (RAB) is used for calling the following services:
SYS$CONNECT SYS$READ
SYS$DELETE SYS$RELEASE
SYS$DISCONNECT SYS$REWIND
SYS$FIND SYS$SPACE
SYS$FLUSH SYS$TRUNCATE
SYS$FREE SYS$UPDATE
SYS$GET SYS$WAIT
SYS$NXTVOL SYS$WRITE
SYS$PUT  

The purpose of the RAB is to describe the record being manipulated by these services. The RAB contains a pointer to the FAB used to open the file being manipulated, making it unnecessary for these services to have a FAB in their argument lists. Also, a RAB can point to certain types of XABs.

Using the FOR$RAB Intrinsic Function

To declare the structure and parameter values for using RAB blocks, include the $RABDEF library module from FORSYSDEF. For example:


INCLUDE '($RABDEF)' 

To examine the fields and values declared, use the /LIST qualifier after the right parenthesis. Each field in the RAB is described at length in the OpenVMS Record Management Services Reference Manual.

If you are using a USEROPEN procedure, the actual allocation of the RAB is performed by the HP Fortran Run-Time Library I/O support routines, and you only need to declare the second argument to your USEROPEN routine to be a record with the RAB structure. For example:

Calling program:


  ...
  EXTERNAL MYOPEN 
  ...
  OPEN (UNIT=8, ..., USEROPEN=MYOPEN) 
  ...

USEROPEN routine:


INTEGER FUNCTION MYOPEN(FABARG, RABARG, LUNARG) 
...
INCLUDE '($RABDEF)' 
...
RECORD /RABDEF/ RABARG 
...

If you need to access the RAB used by the Fortran I/O system for one of the open files in your program, you can use the FOR$RAB intrinsic function (do not declare it as EXTERNAL). You can use FOR$RAB even if you did not use a USEROPEN routine to open the file. The FOR$RAB intrinsic function takes a single INTEGER*4 variable (or constant) argument, the unit number of the open file for which you want to obtain the RAB address. The function result is the address of the RAB for that unit.

If you use the FOR$RAB function in your program, you should declare it to be INTEGER*4 if you assign the result value to a variable. If you do not, your program will assume that it is a REAL function and will perform an improper conversion to INTEGER.

To use the result of the FOR$RAB call, you must pass it to a subprogram as an actual argument using the %VAL built-in function. This allows the subprogram to access it as an ordinary HP Fortran record argument. For example, the main program for calling a subroutine to print the RAB fields could be coded as follows:


  INTEGER (KIND=4) RABADR, FOR$RAB 
  ...
  OPEN(UNIT=14, FILE='TEST.DAT', STATUS='OLD') 
  ...
  RABADR = FOR$RAB(14) 
  ...
  CALL DUMPRAB(%VAL(RABADR)) 
  ...

If you need to access other control blocks in use by the RMS services for that unit, you can obtain their addresses using the link fields they contain. For example:


SUBROUTINE DUMPRAB(RAB) 
...
INTEGER (KIND=4)  FABADR 
INCLUDE '($RABDEF)' 
RECORD /RABDEF/ RAB 
...
FABADR = RAB.RAB$L_FAB 
...
CALL DUMPFAB(%VAL(FABADR)) 
...

In this example, the routine DUMPRAB obtains the address of the associated FAB by referencing the RAB$L_FAB field of the RAB. Other control blocks associated with the FAB, such as the NAM and XAB blocks, can be accessed using code similar to this example.

Usually, you need to declare only one RAB block. Sometimes, however, you may need to use more than one. For example, the multistream capability of RMS allows you to connect several RABs to a single FAB. This allows you to simultaneously access several records of a file, keeping a separate context for each record. You can declare whatever RAB blocks you need with a RECORD statement. For example:


INCLUDE '($RABDEF)' 
...
RECORD /RABDEF/ RAB1, RABARRAY(10) 

If you use any of the above service calls without using a USEROPEN routine, you must initialize the required RAB fields in your program. The RAB fields required for each RMS service are listed in the descriptions of individual services in the OpenVMS Record Management Services Reference Manual. Most services also fill in output values in the RAB. Descriptions of these output fields are provided with the service descriptions.

In the example programs supplied in the OpenVMS Record Management Services Reference Manual, these initial field values are described as they would be used in MACRO programs, where the declaration macros allow initialization arguments. Thus, in each case where the MACRO example shows a field being initialized in a declaration macro, you must have a corresponding initialization at run time in your program.

For example, the OpenVMS Record Management Services Reference Manual contains an example that shows the use of the RAC parameter for specifying the record access mode to use:


  . 
  . 
  . 
  
  SRC_FAB: 
          $FAB    FAC=<GET>,-           ; File access for GET only 
                  FOP=<SQO>,-           ; DAP file transfer mode 
                  FNM=<SRC:>            ; Name of input file 
  SRC_RAB: 
          $RAB    FAB=SRC_FAB,-         ; Address of associated FAB 
                  RAC=SEQ,-             ; Sequential record access 
                  UBF=BUFFER,-          ; Buffer address 
                  USZ=BUFFER_SIZE       ; Buffer size 
 
  .
  .
  .

In this example, sequential access mode is used. As described in the section on the RAC field (in the same manual), this parameter sets the RAB$B_RAC field to the value RAB$C_SEQ. This means that to perform the same initialization in Fortran, you must supply RAC field values by a run-time assignment statement. For example:


  MYRAB.RAB$B_RAC = RAB$C_SEQ 

The RAB$B_BID and RAB$B_BLN fields must be filled in by your program prior to their use in an RMS service call, unless they have been supplied by the Fortran RTL I/O routines. You should always use the symbolic names for the values of these fields. For example:


INCLUDE '($RABDEF)' 
...
RECORD /RABDEF/ MYRAB 
...
MYRAB.RAB$B_BID = RAB$C_BID 
MYRAB.RAB$B_BLN = RAB$C_BLN 
...
STATUS = SYS$CONNECT(MYRAB) 
...

11.2.4 Name Block (NAM)

The Name Block (NAM) can be used with the FAB in most FAB-related services in order to supply to or receive from RMS more detailed information about a file name. The NAM block is never given directly as an argument to an RMS service; to supply it you must link to it from the FAB. See Section 11.2.1 for an example of this.

To declare the structure and parameter values for using NAM blocks, include the $NAMDEF library module from FORSYSDEF. For example:


INCLUDE '($NAMDEF)' 

To examine the fields and values declared, use the /LIST qualifier after the right parenthesis. Each field in the NAM is described in the OpenVMS Record Management Services Reference Manual.

If you are using a USEROPEN procedure, the actual allocation of the NAM is performed by the HP Fortran Run-Time Library I/O support routines. Because the NAM block is linked to the FAB, it is not explicitly given in the USEROPEN routine argument list.

To access the NAM, you need to call a subprogram, passing the pointer by value and accessing the NAM in the subprogram as a structure. For example:

Calling program:


  ...
  EXTERNAL MYOPEN 
  ...
  OPEN (UNIT=8, ..., USEROPEN=MYOPEN) 
  ...

USEROPEN routine:


INTEGER FUNCTION MYOPEN(FABARG, RABARG, LUNARG) 
...
INCLUDE '($FABDEF)' 
...
RECORD /FABDEF/ FABARG 
...
CALL NAMACCESS(%VAL(FABARG.FAB$L_NAM)) 
...

NAM accessing routine:


SUBROUTINE NAMACCESS(NAMARG) 
...
INCLUDE '($NAMDEF)' 
...
RECORD /NAMDEF/ NAMARG 
...
IF (NAMARG.NAM$B_ESL .GT. 132) GO TO 100 
...

Usually, you only need to declare one NAM block. You can declare whatever NAM blocks you need with a RECORD statement. For example:


INCLUDE '($NAMDEF)' 
...
RECORD /NAMDEF/ NAM1, NAM2 

Most often, you use the NAM block to pass and receive information about the components of the file specification, such as the device, directory, file name, and file type. For this reason, most of the fields of the NAM block are CHARACTER strings and lengths. When using the NAM block, you should be familiar with the argument passing mechanisms for CHARACTER arguments described in Section 10.8.4.3.

Your program must fill in the NAM$B_BID and NAM$B_BLN fields prior to their use in an RMS service call, unless they have been supplied by the HP Fortran RTL I/O routines. You should always use the symbolic names for the values of these fields. For example:


INCLUDE '($NAMDEF)' 
...
RECORD /NAMDEF/ MYNAM 
...
MYNAM.NAM$B_BID = NAM$C_BID 
MYNAM.NAM$B_BLN = NAM$C_BLN 
...


Previous Next Contents Index