Previous | Contents | Index |
This chapter describes:
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 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:
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:
INCLUDE '($RABDEF)' RECORD /RABDEF/ MYRAB ... MYRAB.RAB$B_RAC = RAB$C_SEQ ... |
INCLUDE '($FABDEF)' RECORD /FABDEF/ MYFAB ... MYFAB.FAB$L_FOP = MYFAB.FAB$L_FOP .OR. FAB$M_MXV |
INCLUDE '($FABDEF)' RECORD /FABDEF/ MYFAB ... MYFAB.FAB$L_FOP = IBSET(MYFAB.FAB$L_FOP,FAB$V_MXV) ... |
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) |
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( ... ) ... |
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) ... |
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 |