Previous | Contents | Index |
This chapter describes how to call OpenVMS Record Management Services (RMS) directly from Compaq 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 Compaq Fortran programmers, that manual 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 Compaq Fortran is to use a USEROPEN routine, which is a subprogram that you specify in an OPEN statement. The Compaq 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 Compaq 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.3 describes how to use USEROPEN routines and
gives examples. You should be familiar with the material in
Section 11.1 before reading Section 11.3.
11.1 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 as follows:
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 Compaq 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.1.2 to Section 11.1.5. See Section 11.2 for descriptions
of steps 5 and 6.
11.1.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 Compaq 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 Compaq 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.1.3 The Record Access Block
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 Compaq 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 Compaq 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.1.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 Compaq 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.7.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 Compaq 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 ... |
Extended Attribute Blocks (XABs) are a family of related structures for passing and receiving additional information about files. There are different kinds of XABs:
The XABs are described in the OpenVMS Record Management Services Reference Manual. XABs are generally smaller and simpler than the FAB, RAB, and NAM blocks because each describes information about a single aspect of the file. You do not have to use all of them; for any given call to an RMS service routine, use only those that are required.
Often the XAB fields override the corresponding fields in the FAB. For example, the allocation XAB describes the file's block allocation in more detail than the FAB$L_ALQ field can. For this reason, XAB$L_ALQ (the allocation field in the XABALL structure) always overrides the FAB$L_ALQ value.
The XABs used for any given RMS service call are connected to the FAB in a linked list. The head of the list is the FAB$L_XAB field in the FAB. This field contains the address of the first XAB to be used. Each successive XAB in the list links to the next using the XAB$L_NXT field. This field contains the address of the next XAB in the list. The order of the XABs in the list does not matter, but each kind of XAB must not appear more than once in the list.
The only kind of XAB that can be connected to a RAB instead of a FAB is the terminal XAB. It is linked to the RAB with the RAB$L_XAB field. This is needed because the terminal control information is dynamic and potentially changes with each record operation performed.
To declare the structure and parameter values for using the different XAB blocks, include the appropriate XAB definition library module from FORSYSDEF. (The names of the XAB definition library modules are listed previously in this section.) Also, because the XABs are a family of related control blocks, you need to include the $XABDEF library module from FORSYSDEF.TLB in order to declare the fields common to all XABs. For example, to declare the fields used in the Date and Time XAB, use the following declarations:
INCLUDE '($XABDATDEF)' INCLUDE '($XABDEF)' |
To examine the fields and values declared, use the /LIST qualifier after the right parenthesis. All of the fields in the XABs are described in the OpenVMS Record Management Services Reference Manual.
If you are using a USEROPEN procedure, the actual allocation of the XABs used by the open operation is performed by the Compaq Fortran Run-Time Library I/O support routines. Because the XAB blocks are linked to the FAB, the XAB block addresses are not explicitly given in the USEROPEN routine argument list.
To access the XABs, you need to call a subprogram and pass a pointer to it using the %VAL built-in function or a pointer argument. For an example of this method, see Section 11.1.3.
To allocate space for an XAB block in your program, you need to declare it with a RECORD statement. For example:
INCLUDE '($XABDATDEF)' INCLUDE '($XABPRODEF)' ... RECORD /XABDATDEF/ MYXABDAT, /XABPRODEF/ MYXABPRO ... |
For each XAB that you declare in your program, you must supply the correct COD and BLN fields explicitly. These field offsets are common to all XABs and are contained in the $XABDEF library module in FORSYSDEF.TLB. The block id and length are unique for each kind of XAB and the symbolic values for them are contained in the separate XAB declaration library modules in FORSYSDEF.TLB. For example, to properly initialize a Date and Time XAB, you could use the following code segment:
INCLUDE '($XABDEF)' INCLUDE '($XABDATDEF)' RECORD /XABDEF/ MYXABDAT ... MYXABDAT.XAB$B_COD = XAB$C_DAT MYXABDAT.XAB$B_BLN = XAB$C_DATLEN ... |
In general, you need to do the same things when calling an RMS service that you need to do when calling any OpenVMS service: declare the name, pass arguments, and check status values. However, RMS services have some additional conventions and ease-of-use features that you should be aware of.
As with the other system services, you should use the $SYSSRVNAM library module in FORSYSDEF to declare the names of all of the RMS services. For example:
INCLUDE '($SYSSRVNAM)' |
This library module contains comments describing each OpenVMS system
service, including all of the RMS services, and INTEGER*4 and EXTERNAL
declarations for each. Including the library module allows you to use
the names of the RMS services in your programs without further
declaration.
11.2.2 Arguments to RMS Services
Most RMS services require three arguments:
Some RMS services take other arguments, but these services are rarely needed. You should always refer to the documentation for the specific service that you are calling for detailed information on its arguments.
Most RAB and FAB fields are ignored by most RMS services. The documentation of each service in the OpenVMS Record Management Services Reference Manual describes which fields are input for that service and which are output, for each control block used. Services that take a FAB as an argument are called the File Control services. Services that take a RAB as an argument are called the Record Control services. Typically, you need to use both when doing RMS I/O in your program.
In general, fields that are not documented as required for input to a service are ignored and can be left uninitialized. The exceptions are the Block Id (BID or COD) and Block Length (BLN) fields; these must always be initialized. See the preceding sections about the respective blocks for examples of how to initialize these fields.
The output of many RMS services provides the values required for input to other RMS services. For this reason, you usually only need to initialize a few fields in each block to their nondefault values. This is especially true when using RMS blocks declared with the Compaq Fortran RTL I/O routines as when using USEROPEN routines or the FOR$RAB function.
About passing arguments to system services, see Section 10.7.4.
11.2.3 Checking Status from RMS Services
You should always invoke RMS services as functions, rather than calling them as subroutines (see Section 10.7.2 for a general discussion of this topic). It is particularly important to check the status of RMS services because they usually do not cause an error when they fail. If the status is not checked immediately, the failure will go undetected until later in the program where it will be difficult to diagnose.
In most cases, you only need to check for success or failure by testing whether the returned status is true or false. Some services have alternate success-status possibilities. You should always check for these in cases where the program depends on the correct operation of the services.
The RMS services have a unique set of status return symbols not used by any of the other OpenVMS system services. You should always use these symbols whenever you check the individual status values returned. To obtain the declarations for these symbols, include the $RMSDEF library module from FORSYSDEF.TLB. For example:
INCLUDE '($RMSDEF)' |
This statement includes in your program the declarations for all of the symbolic RMS return values.
The OpenVMS Record Management Services Reference Manual documents the symbolic values, both success and failure, that can be returned from each of the services. Your program should always test each service-result status against these symbolic values and take appropriate action when a failure status is detected. You should always declare status variables as INTEGER*4 type in order to avoid unexpected numeric conversions. The recommended action depends on whether you are using RMS services in a USEROPEN routine.
The Compaq Fortran RTL I/O routines that invoke your USEROPEN routine are expecting an RMS status as an output value. For this reason, you need to return the RMS status value as the function value for both failure and success conditions. For example:
INTEGER FUNCTION MYOPEN(FAB,RAB,LUN) ... INCLUDE '($SYSSRVNAM)' ! Declare RMS service names ... MYOPEN = SYS$OPEN(FAB) IF (.NOT. MYOPEN) RETURN ... RETURN END |
In this case, if the SYS$OPEN service fails, it returns an error status into the function result variable MYOPEN. If the test of MYOPEN does not indicate success, the function returns the actual RMS status as its value. Then the RTL I/O routines will signal the appropriate Fortran error normally, as if a USEROPEN routine had not been used.
If the SYS$OPEN call succeeds, the program continues, and the RMS$_NORMAL success status will ultimately be returned to the Fortran RTL. This value will cause the OPEN statement that specifies MYOPEN to complete successfully.
If you are not using a USEROPEN routine, your program must indicate the error status directly, unless it is prepared to deal with it. Often, the easiest way to indicate an error and issue a helpful message is to signal the RMS condition directly with LIB$SIGNAL or LIB$STOP. For example:
... INCLUDE '($SYSSRVNAM)' ! Declare RMS service names INTEGER (KIND=4) STATUS ! Declare a status variable ... STATUS = SYS$GET(MYRAB) IF (.NOT. STATUS) CALL LIB$STOP(%VAL(STATUS)) |
On the use of LIB$SIGNAL and LIB$STOP, see Chapter 14.
11.2.4 Opening a File
To perform input or output operations on a file, your program must first open the file and establish an active RMS I/O stream. To open a file, your program generally needs to call either the SYS$CREATE or SYS$OPEN services, followed by the SYS$CONNECT service. When your program uses an OPEN statement without a USEROPEN routine, the Compaq Fortran RTL I/O routines call these RMS services.
Options related to opening a file follow:
The value of the FAB$B_FAC field of the FAB indicates to RMS what record operations are to be done on the file being opened. If a record operation that was not indicated by the FAC field (such as a SYS$PUT) is attempted, the record service will not perform the operation and will return a failure status. This file protection feature prevents you from accidentally corrupting a file when you use the wrong RMS service.
The SYS$CONNECT service establishes an active I/O stream, using a RAB, to a file that has been previously opened by your program. RMS identifies all active I/O streams by a unique identifier, called the Internal Stream Identifier (ISI). This value is stored in the RAB$W_ISI field of the RAB for each active stream being processed.
This field must always be zero when calling SYS$CONNECT.
The SYS$CONNECT service initializes this field, so that subsequent
operations using that RAB can be uniquely identified. Under some
circumstances, you can establish more than one simultaneously active
I/O stream to the same file. See the OpenVMS Record Management Services Reference Manual for more
information on this topic.
11.2.5 Closing a File
To close a file, use the SYS$CLOSE service.
This terminates all active I/O streams under way on that file and frees
all RMS resources being used for processing that file. Use the
SYS$DISCONNECT service if you want to end one active I/O stream, but
continue processing the file using another stream. This service sets
the RAB$W_ISI value to zero so that the RAB can be reused for another
stream.
11.2.6 Writing Data
To write data to a file, use the SYS$PUT or SYS$WRITE service. Your program must set the PUT bit in the FAB$B_FAC field when the file is opened; otherwise, the service attempting the write operation will fail.
Use the SYS$PUT service when you want to write data in record mode (the default). In record mode, RMS buffers data automatically and performs the actual output operation for a whole group of records at a time. This is the mode used for all Compaq Fortran WRITE statements. Because most programs and utilities can read data written in record mode, this mode should be used when the data being written is to be read and processed by a general program or utility.
Use the SYS$WRITE service when you want to bypass the record management capabilities of RMS and write blocks of data directly to the device without additional buffering. This mode is called block mode I/O and is generally much faster and uses less CPU resources than record mode. For this reason, it is the preferred mode for writing large amounts of unformatted data to a device.
Block mode should only be used when the program that needs to read the
data can also use block mode. If the program that is to read the data
cannot use block mode, you must use some other means to guarantee that
the data being written can be accessed. For instance, it is not
generally possible to read data written with SYS$WRITE using ordinary
Compaq Fortran READ statements. Before using SYS$WRITE, read the
special restrictions on using block mode in the OpenVMS Record Management Services Reference Manual, because
SYS$WRITE (block mode) may have different device dependencies than
SYS$PUT (record mode).
11.2.7 Reading Data
To read data from a file, use the SYS$GET or SYS$READ service. Your program must set the GET bit in the FAB$B_FAC field when the file is opened; otherwise, the service attempting the read operation will fail.
Use the SYS$GET service when you want to read data in record mode (the default). In this mode, RMS buffers data automatically and performs the actual input operation for a whole group of records at a time. This is the mode used for all Compaq Fortran READ statements. This mode should be used whenever the program or utility that wrote the data used record mode, unless your reading program can buffer and deblock the data itself.
Use the SYS$READ service when you want to read data using block mode I/O (see Section 11.2.6. Using SYS$READ is the preferred mode for reading large amounts of unformatted data from a device, but it should only be used when the data was written by a utility or program that wrote the data in block mode.
If the file was written using record mode, RMS control information may
be intermixed with the data, making it difficult to process. Before
using SYS$READ, read the special restrictions on using block mode in
the OpenVMS Record Management Services Reference Manual, because SYS$READ (block mode) may have different
device dependencies than SYS$GET (record mode).
11.2.8 Other Services
RMS provides many other file and record processing services beyond just Opening, Closing, Reading and Writing. Other file processing services include the following:
Other record processing services include the following:
On the RMS services, see the OpenVMS Record Management Services Reference Manual.
11.3 User-Written Open Procedures
The USEROPEN keyword in an OPEN statement provides you with a way to access RMS facilities that are otherwise not available to Compaq Fortran programs. It specifies a user-written external procedure (USEROPEN procedure) that controls the opening of a file. The USEROPEN keyword has the form:
USEROPEN = procedure-name |
The procedure-name represents the symbolic name of a user-written open procedure. The procedure must be declared in an EXTERNAL statement, and should be a FUNCTION that returns an INTEGER*4 result.
When an OPEN statement---with or without the USEROPEN keyword---is executed, the Run-Time Library uses the OPEN statement keywords to establish the RMS File Access Block (FAB) and the Record Access Block (RAB), as well as its own internal data structures. If a USEROPEN keyword is included in the OPEN statement, the Run-Time Library then calls your USEROPEN procedure instead of opening the file according to its normal defaults. The procedure can then provide additional parameters to RMS and can obtain results from RMS.
The three arguments passed to a user-written open procedure by the Run-Time Library are as follows:
Using this information, your USEROPEN procedure can then perform the following operations:
A USEROPEN routine can set FAB fields before the corresponding file is opened (or created). However, once the file is open (except if the FAB$V_UFO bit is set), the user should not alter any of the FAB fields.
A USEROPEN routine can likewise set RAB fields before the record stream has been connected (SYS$CONNECT). However, once the file is connected to the record stream, the user should not alter any of the RAB fields.
Once a FAB or RAB is used by the Fortran RTL, it should be treated as read-only by the user, because the Fortran RTL may need to set and alter those fields as needed to complete the user Fortran I/O statements. Any user modification of a FAB or RAB after its initial use may not have the intended effect for subsequent Fortran I/O statements.
About the FAB and RAB, see the OpenVMS Record Management Services Reference Manual.
11.3.1 Examples of USEROPEN Routines
The following OPEN statement either creates a 1000-block contiguous file or returns an error. (The default Compaq Fortran interpretation of the INITIALSIZE keyword is to allocate the file contiguously on a best-effort basis, but not to generate an error if the space is not completely contiguous.)
EXTERNAL CREATE_CONTIG OPEN (UNIT=10, FILE='DATA', STATUS='NEW', INITIALSIZE=1000, & USEROPEN=CREATE_CONTIG) |
User-written open procedures are often coded in BLISS or MACRO; however, they can also be coded in Compaq Fortran using Compaq Fortran's record handling capability.
The following function creates a file after setting the RMS FOP bit (FAB$V_CTG) to specify contiguous allocation.
! UOPEN1 ! ! Program to demonstrate the use of a simple USEROPEN routine ! PROGRAM UOPEN1 EXTERNAL CREATE_CONTIG ! OPEN the file specifying the USEROPEN routine OPEN (UNIT=10, FILE='DATA', STATUS='NEW', INITIALSIZE=1000, & USEROPEN=CREATE_CONTIG) STOP END PROGRAM UOPEN1 ! CREATE_CONTIG ! Sample USEROPEN function to force RMS to allocate contiguous ! blocks for the initial creation of a file. INTEGER FUNCTION CREATE_CONTIG(FAB,RAB,LUN) ! Required declarations INCLUDE '($FABDEF)' ! FAB Structure INCLUDE '($RABDEF)' ! RAB Structure INCLUDE '($SYSSRVNAM)' ! System service name declarations RECORD /FABDEF/ FAB, /RABDEF/ RAB ! Clear the "Contiguous-best-try" bit, set the "Contiguous" bit FAB.FAB$L_FOP = FAB.FAB$L_FOP .AND. .NOT. FAB$M_CBT FAB.FAB$L_FOP = FAB.FAB$L_FOP .OR. FAB$M_CTG ! Perform the create and connect, and return status CREATE_CONTIG = SYS$CREATE(FAB) IF (.NOT. CREATE_CONTIG) RETURN CREATE_CONTIG = SYS$CONNECT(RAB) RETURN END FUNCTION CREATE_CONTIG |
Use of the USEROPEN keyword has some restrictions. The Run-Time Library constructs the following RMS control structures before calling the USEROPEN procedure:
FAB | File Access Block |
RAB | Record Access Block |
NAM | Name Block |
XAB | Extended Attributes Blocks |
ESA | Expanded String Area |
RSA | Resultant String Area |
A USEROPEN procedure should not alter the allocation of these structures, although it can modify the contents of many of the fields. Your procedure can also add additional XAB control blocks by linking them anywhere into the XAB chain. You must exercise caution when changing fields that have been set as a result of Compaq Fortran keywords, because the Run-Time Library may not be aware of the changes. For example, do not attempt to change the record size in your USEROPEN procedure; instead, use the Compaq Fortran keyword RECL. Always use an OPEN statement keyword if one is available.
Although the FAB, RAB, and NAM blocks remain defined during the time that the unit is opened, the XAB blocks are present only until the file has been successfully opened. The locations of the ESA and RSA strings are changed after the file is opened, so your USEROPEN procedure should not store the addresses of the RMS control structures. Instead, have your program call FOR$RAB to obtain the address of the RAB once the file is opened and then access the other structures through the RAB.
Future releases of the Run-Time Library may alter the use of some RMS fields. Therefore, you may have to alter your USEROPEN procedures accordingly. |
Table 11-1 shows which FAB and RAB fields are either initialized before your USEROPEN procedure is called or examined upon return from your USEROPEN procedure. All fields are initialized in response to OPEN statement keywords or default to zero. Fields labeled with a hyphen (-) are initialized to zero. Fields labeled with an asterisk (*) are returned by RMS.
Field Name | Description | Compaq Fortran OPEN Keyword and Value | |
---|---|---|---|
FAB$B_ACMODES | File access modes | Contains FAB$V_CHAN_MODE and FAB$V_LNM_MODE. | |
FAB$L_ALQ | Allocation quantity | n if INITIALSIZE=n | |
FAB$B_BKS | Bucket size | (BLOCKSIZE + 511)/512 | |
FAB$W_BLS | Block size | n if BLOCKSIZE=n | |
FAB$V_CHAN_MODE | Channel access mode protection (2-bit subfield in FAB$B_ACMODES) | 0=usermode | |
FAB$L_CTX | Context | -- | |
FAB$W_DEQ | Default file extension quantity | n if EXTENDSIZE=n | |
FAB$L_DEV | Device characteristics | * | |
FAB$L_DNA |
Default file specification string
address |
UNIT=
nnn
Set to FOR nnn.DAT or FORREAD.DAT, FORACCEPT.DAT, FORTYPE.DAT, or FORPRINT.DAT or to default file specification string |
|
FAB$B_DNS | Default file specification string size | Set to length of default file specification string | |
FAB$B_FAC | File access |
READONLY
Set to 0 if READONLY (RMS default), else set to FAB$M_GET + FAB$M_PUT + FAB$M_UPD + FAB$M_TRN + FAB$M_DEL |
|
FAB$L_FNA | File specification string address | FILE=filename if FILE present, else set to FOR nnn, FOR$READ, FOR$ACCEPT, FOR$TYPE, FOR$PRINT, SYS$INPUT, or SYS$OUTPUT | |
FAB$B_FNS | File specification string size | Set to length of file specification string | |
FAB$L_FOP | File processing options | ||
FAB$V_ASY | Asynchronous operation | -- (not used) | |
FAB$V_CBT | Contiguous best try | 1 if INITIALSIZE=n | |
FAB$V_CIF | Create if nonexistent | 1 if READONLY not specified and STATUS='UNKNOWN' or STATUS omitted | |
FAB$V_CTG | Contiguous allocation | -- | |
FAB$V_DFW | Deferred write | 1 | |
FAB$V_DLT | Delete on close service | Set at Fortran close, depending upon DISP keyword in OPEN or CLOSE, or STATUS keyword in CLOSE | |
FAB$V_KFO | Known file open | -- | |
FAB$V_MXV | Maximize version number | -- | |
FAB$V_NAM | Name block inputs | -- | |
FAB$V_NEF | Not positioned at end of file | 1 unless ACCESS= 'APPEND' | |
FAB$V_NFS | Not file structured | -- | |
FAB$V_OFP | Output file parse | -- | |
FAB$V_POS | Current position (after closed file) | -- | |
FAB$V_PPF | Process permanent file | -- | |
FAB$V_RCK | Read check | -- | |
FAB$V_RWC | Rewind on close service | -- | |
FAB$V_RWO | Rewind on open service | -- | |
FAB$V_SCF | Submit command (when closed) | Set at Fortran close, depending upon DISP keyword in OPEN or CLOSE, or STATUS keyword in CLOSE | |
FAB$V_SPL | Spool to printer | Set at Fortran close, depending upon DISP keyword in OPEN or CLOSE, or STATUS keyword in CLOSE | |
FAB$V_SQO | Sequential only | 1 if a network file and ACCESS='SEQUENTIAL' or 'APPEND', else 0 | |
FAB$V_SUP | Supersede | -- | |
FAB$V_SYNCSTS | Immediate asynchronous completion | * (not used) | |
FAB$V_TEF | Truncate at end-of-file | -- | |
FAB$V_TMD | Temporary, marked for delete | 1 if STATUS= 'SCRATCH', else 0 | |
FAB$V_TMP |
Temporary (file with no directory
entry) |
-- | |
FAB$V_UFO | User file open or create file only | -- | |
FAB$V_WCK | Write check | -- | |
FAB$B_FSZ | Fixed control area size | -- | |
FAB$W_IFI | Internal file identifier | * | |
FAB$W_GBC | Global buffer count | -- | |
FAB$B_JOURNAL | Journal flags status | -- | |
FAB$V_LNM_MODE | Logical name translation access mode (subfield in FAB$B_ACMODES) | -- | |
FAB$L_MRN | Maximum record number | n if MAXREC=n | |
FAB$W_MRS | Maximum record size | n if RECORDTYPE='FIXED' or ORGANIZATION='RELATIVE' or ='INDEXED', else 0 | |
FAB$L_NAM | Name block address | Set to address of name block; both the expanded and resultant string areas are set up, but the related filename string is not | |
FAB$B_ORG | File organization |
FAB$C_IDX if ORGANIZATION='INDEXED'
FAB$C_REL if ORGANIZATION='RELATIVE' FAB$C_SEQ if ORGANIZATION='SEQUENTIAL' or omitted |
|
FAB$B_RAT | Record attributes | ||
FAB$V_FTN | Fortran carriage control | 1 if CARRIAGECONTROL='FORTRAN' or not specified | |
FAB$V_CR | Print LF and CR | 1 if CARRIAGECONTROL='LIST' | |
FAB$V_BLK | Do not cross block boundaries | -- (1 if NOSPANBLOCKS) | |
FAB$B_RFM | Record format |
FAB$C_FIX if RECORDTYPE='FIXED'
FAB$C_VAR if RECORDTYPE='VARIABLE' FAB$C_VAR if RECORDTYPE='SEGMENTED' FAB$C_STM if RECORDTYPE='STREAM' FAB$C_STMCR if RECORDTYPE='STREAM_CR' FAB$C_STMLF if RECORDTYPE='STREAM_LF' |
|
FAB$B_RTV | Retrieval window size | -- | |
FAB$L_SDC | Spooling device characteristics | * | |
FAB$B_SHR | File sharing | ||
FAB$V_SHRPUT | Allow other PUTs | 1 if SHARED | |
FAB$V_SHRGET | Allow other GETs | 1 if SHARED | |
FAB$V_SHRDEL | Allow other DELETEs | 1 if SHARED | |
FAB$V_SHRUPD | Allow other UPDATEs | 1 if SHARED | |
FAB$V_NIL | Allow no other operations | -- | |
FAB$V_UPI | User-provided interlock | -- | |
FAB$V_MSE | Multistream allowed | -- | |
FAB$L_STS | Completion status code | * | |
FAB$L_STV | Status value | * | |
FAB$L_XAB | Extended attribute block address | The XAB chain always has a File Header Characteristics (FHC) extended attribute block in order to get longest record length (XAB$W_LRL). If the KEY=keyword is specified, key index definition blocks will also be present. Compaq may add additional XABs in the future. Your USEROPEN procedure may insert XABs anywhere in the chain. | |
RAB$L_BKT | Bucket code | -- | |
RAB$L_CTX | Context | -- | |
RAB$L_FAB | FAB address | Set to address of FAB | |
RAB$W_ISI | Internal stream ID | * | |
RAB$L_KBF | Key buffer address | Set to address of longword containing logical record number if ACCESS='DIRECT' | |
RAB$B_KRF | Key of reference | 0 | |
RAB$B_KSZ | Key size | -- | |
RAB$B_MBC | Multiblock count | If BLOCKSIZE=n, use (n + 511)/512 | |
RAB$B_MBF | Multibuffer count | n if BUFFERCOUNT=n | |
RAB$L_PBF | Prompt buffer address | -- | |
RAB$B_PSZ | Prompt buffer size | -- | |
RAB$B_RAC | Record access mode | ||
RAB$C_KEY | If ACCESS='DIRECT' or 'KEYED' | ||
RAB$C_SEQ | If ACCESS='SEQUENTIAL' or 'APPEND', or ACCESS omitted | ||
RAB$C_RFA | -- | ||
RAB$L_RBF | Record buffer address | Set later | |
RAB$L_RFA | Record file address | Set later | |
RAB$L_RHB | Record header buffer | -- | |
RAB$L_ROP | Record processing options | ||
RAB$V_ASY | Asynchronous | -- | |
RAB$V_BIO | Block I/O | -- | |
RAB$V_CCO | Cancel CTRL/O | -- | |
RAB$V_CVT | Convert to uppercase | -- | |
RAB$V_EOF | End-of-file | 1 if ACCESS='APPEND' | |
RAB$V_ETO | Extended terminal (XABTRM) operation | -- | |
RAB$V_FDL | Fast delete | -- | |
RAB$V_KGE or
RAB$V_EQNXT |
Key greater than or equal to | -- | |
RAB$V_KGT or
RAB$V_NXT |
Key greater than | -- | |
RAB$V_LIM | Limit | -- | |
RAB$V_LOA | Load buckets according to fill size | -- | |
RAB$V_LOC | Locate mode | 1 | |
RAB$V_NLK | No lock | -- | |
RAB$V_NXR | Nonexistent record | -- | |
RAB$V_PMT | Prompt | -- | |
RAB$V_PTA | Purge type-ahead | -- | |
RAB$V_RAH | Read-ahead | 1 | |
RAB$V_REA | Lock record for read | -- | |
RAB$V_RLK | Lock record for write | -- | |
RAB$V_RNE | Read no echo | -- | |
RAB$V_RNF | Read no filter | -- | |
RAB$V_RRL | Read regardless of lock | -- | |
RAB$V_SYNCSTS | Immediate asynchronous completion | * (not used) | |
RAB$V_TMO | Timeout | -- | |
RAB$V_TPT | Truncate on PUT | 1 | |
RAB$V_UIF | Update if | 1 if ACCESS='DIRECT' | |
RAB$V_ULK | Manual unlocking | -- | |
RAB$V_WAT | Wait for locked record | -- | |
RAB$V_WBH | Write-behind | 1 | |
RAB$W_RSZ | Record size | Set later | |
RAB$L_STS | Completion status code | * | |
RAB$L_STV | Status value | * | |
RAB$B_TMO | Timeout period | -- | |
RAB$L_UBF | User record area address | Set later | |
RAB$W_USZ | User record area size | Set later | |
RAB$L_XAB | Extended attribute block address | The XAB chain allows you to set or obtain additional information about an I/O operation. |
RMS does not allow multiple instances of the same type XAB. To be
compatible with future releases of the Run-Time Library, your procedure
should scan the XAB chain for XABs of the type to be inserted. If one
is found, it should be used instead.
11.4 Example of Block Mode I/O
The following example shows a complete application that calls the RMS block I/O services SYS$WRITE and SYS$READ directly from Compaq Fortran. A complete program called BIO.F90 writes out an array of REAL*8 values to a file using SYS$WRITE, closes the file, and then reads the data back in using SYS$READ operations with a different I/O transfer size. This program consists of five routines:
BIO | Main control program |
BIOCREATE | USEROPEN routine to create the file |
BIOREAD | USEROPEN routine to open the file for READ access |
OUTPUT | Function that actually outputs the array |
INPUT | Function that actually reads the array and checks it |
The following main program specifies the USEROPEN specifier in its OPEN statements.
! File: BIO.F90 ! ! Program to demonstrate the use of RMS Block I/O operations ! from Compaq Fortran PROGRAM BIO ! Declare the Useropen routines as external EXTERNAL BIOCREATE, BIOREAD ! Declare status variable, functions, and unit number LOGICAL (KIND=4) STATUS, OUTPUT, INPUT INTEGER (KIND=4) IUN/1/ ! Open the file (1) OPEN(UNIT=IUN, FILE='BIODEMO.DAT', FORM='UNFORMATTED', & STATUS='NEW', RECL=128, BLOCKSIZE=512, ORGANIZATION='SEQUENTIAL', & IOSTAT=IOS, ACCESS='SEQUENTIAL', RECORDTYPE='FIXED', & USEROPEN=BIOCREATE, INITIALSIZE=100) IF (IOS .NE. 0) STOP 'Create failed' (2) ! Now perform the output STATUS = OUTPUT(%VAL(FOR$RAB(IUN))) (3) IF (.NOT. STATUS) STOP 'Output failed' (2) ! Close the file for output CLOSE (UNIT=IUN) ! Confirm output complete TYPE *, 'Output complete, file closed' ! Now open the file for input (2) OPEN(UNIT=IUN, FILE='BIODEMO.DAT', FORM='UNFORMATTED', & STATUS='OLD', IOSTAT=IOS, USEROPEN=BIOREAD, DISP='DELETE') IF (IOS .NE. 0) STOP 'Open for read failed' (2) ! Now read the file back STATUS = INPUT(%VAL(FOR$RAB(IUN))) (3) IF (.NOT. STATUS) STOP 'Input failed' (2) ! Success, output that all is well STOP 'Correct completion of Block I/O demo' END PROGRAM BIO |
The only condition required for block I/O is the setting of the BIO bit in the File Access field of the FAB, using the normal declarations needed to define the symbols properly. If you wish to perform both block and record I/O on the file without closing it, you need to set the BRO bit as well. For more information on mixing block and record mode I/O, see the OpenVMS Record Management Services Reference Manual. Note that the only difference between BIOCREATE and BIOREAD is the use of SYS$CREATE and SYS$OPEN services, respectively.
! Procedure name: BIOCREATE ! USEROPEN routine to set the Block I/O bit and create the BLOCK I/O file. INTEGER FUNCTION BIOCREATE(FAB, RAB, LUN) INTEGER LUN ! Declare the necessary interface names INCLUDE '($FABDEF)' INCLUDE '($RABDEF)' INCLUDE '($SYSSRVNAM)' ! Declare the FAB and RAB blocks RECORD /FABDEF/ FAB, /RABDEF/ RAB ! Set the Block I/O bit in the FAC (GET and PUT bits set by RTL) FAB.FAB$B_FAC = FAB.FAB$B_FAC .OR. FAB$M_BIO ! Now do the Create and Connect BIOCREATE = SYS$CREATE(FAB) IF (.NOT. BIOCREATE) RETURN BIOCREATE = SYS$CONNECT(RAB) IF (.NOT. BIOCREATE) RETURN ! Nothing more to do at this point, just return RETURN END FUNCTION BIOCREATE ! Procedure name: BIOREAD ! USEROPEN routine to set the Block I/O bit and open the Block I/O demo ! file for reading INTEGER FUNCTION BIOREAD(FAB, RAB, LUN) INTEGER LUN ! Declare the necessary interface names INCLUDE '($FABDEF)' INCLUDE '($RABDEF)' INCLUDE '($SYSSRVNAM)' ! Declare the FAB and RAB blocks RECORD /FABDEF/ FAB, /RABDEF/ RAB ! Set the Block I/O bit in the FAC (GET and PUT bits set by RTL) FAB.FAB$B_FAC = FAB.FAB$B_FAC .OR. FAB$M_BIO ! Now do the Open and Connect BIOREAD = SYS$OPEN(FAB) IF (.NOT. BIOREAD) RETURN BIOREAD = SYS$CONNECT(RAB) IF (.NOT. BIOREAD) RETURN ! Nothing more to do at this point, just return RETURN END FUNCTION BIOREAD |
The following routine initializes the array A and performs the SYS$WRITE operations. Beyond the normal RTL initialization, only the RSZ and RBF fields in the RAB need to be initialized in order to perform the SYS$WRITE operations. The %LOC function is used to create the address value required in the RBF field.
One of the main reasons that block mode I/O is so efficient is that it avoids copy operations by using the data areas of the program directly for the output buffer. When writing to a disk device, the program must specify a value for RSZ that is a multiple of 512 or else the final block would be only partly filled.
! Procedure name: OUTPUT ! Function to output records in block I/O mode LOGICAL FUNCTION OUTPUT(RAB) ! Declare RMS names INCLUDE '($RABDEF)' INCLUDE '($SYSSRVNAM)' ! Declare the RAB RECORD /RABDEF/ RAB ! Declare the Array to output REAL(KIND=8) A(6400) ! Declare the status variable INTEGER(KIND=4) STATUS ! Initialize the array DO I=6400,1,-1 A(I) = I ENDDO ! Now, output the array, two 512-byte (64 elements) blocks at a time OUTPUT = .FALSE. RAB.RAB$W_RSZ = 1024 DO I=0,99,2 ! For each block, set the buffer address to the proper array element RAB.RAB$L_RBF = %LOC(A(I*64+1)) STATUS = SYS$WRITE(RAB) IF (.NOT. STATUS) RETURN ENDDO ! Successful output completion OUTPUT = .TRUE. RETURN END FUNCTION OUTPUT |
The following routine reads the array A from the file and verifies its values. The USZ and UBF fields of the RAB are the only fields that need to be initialized. The I/O transfer size is twice as large as the OUTPUT routine. This can be done because the OUTPUT routine writes an integral number of 512-byte blocks to a disk device. This method cannot be used if the writing routine either specifies an RSZ that is not a multiple of 512 or attempts to write to a magnetic tape device.
! Procedure name: INPUT ! ! Function to input records in block I/O mode LOGICAL FUNCTION INPUT(RAB) ! Declare RMS names INCLUDE '($RABDEF)' INCLUDE '($SYSSRVNAM)' ! Declare the RAB RECORD /RABDEF/ RAB ! Declare the Array to output REAL(KIND=8) A(6400) ! Declare the status variable INTEGER(KIND=4) STATUS ! Now, read the array, four 512-byte (64 elements) blocks at a time INPUT = .FALSE. RAB.RAB$W_USZ = 2048 DO I=0,99,4 ! For each block, set the buffer address to the proper array element RAB.RAB$L_UBF = %LOC(A(I*64+1)) STATUS = SYS$READ(RAB) IF (.NOT. STATUS) RETURN ENDDO ! Successful input completion if data is correct DO I=6400,1,-1 IF (A(I) .NE. I) RETURN ENDDO INPUT = .TRUE. RETURN END FUNCTION INPUT |
Previous | Next | Contents | Index |