Chapter 4
The File System
This chapter discusses the use of files for input and output (I/O) in the OpenVMS operating system and describes the aspects of OpenVMS that relate to PL/I I/O. The chapter includes the following topics:
Declaring, opening, and closing files
The relationship between PL/I I/O statements and OpenVMS I/O procedures
OpenVMS file-naming and file-defining conventions, including a description of logical names and process permanent files
File system error handling at run time
Chapters 5, 6, 7, 8, 9 give additional information on the file system, covering stream and record I/O, options (ENVIRONMENT and I/O statement options), and built-in subroutines for file handling.
4.1. File Control
File constants and variables provide your program with access to files. Your program first declares a file constant or variable, and then associates the constant or variable with a file when it opens the file.
A file declaration specifies an identifier and the FILE attribute, and optionally specifies one or more file description attributes describing the type of I/O operation that will be used to process the file. Subsequent I/O statements denote the file by a FILE option.
The OPEN statement explicitly opens a PL/I file with a specified set of attributes that describe the file and the method for accessing it. A file can also be opened implicitly by a READ, WRITE, REWRITE, DELETE, PUT, or GET statement issued for a file that is not open, or by a built-in subroutine referring to a file that is not open.
When PL/I opens a file, the initial positioning depends on the type of file (record or stream), the access mode, and certain ENVIRONMENT options. File positioning for stream files and record files is described in Chapters 5 and 6, respectively.
The CLOSE statement dissociates a PL/I file from the physical file with which it was associated when it was opened. Some ENVIRONMENT options are valid in the CLOSE statement. ENVIRONMENT options are summarized in Chapter 7.
Declaring, opening, and closing files are described in more detail in the Endless PL/I for OpenVMS Reference Manual.
4.2. Using the OpenVMS File System for I/O
When a PL/I program contains an I/O statement, for example, OPEN or READ, the compiler translates the request into a call to the appropriate OpenVMS operating system procedure.
In the OpenVMS system, I/O is performed by the following services:
OpenVMS Record Management Services (RMS). RMS provides complete file and record-handling capabilities.
I/O system services. System services provide direct control over data transfer between the process executing an image and a peripheral device.
Note that, although you can call RMS procedures and OpenVMS system services directly from a PL/I program, it is not normally necessary to do so. A PL/I program executed on the OpenVMS operating system has full access to RMS capabilities through the following language elements:
Options of the ENVIRONMENT attribute
Keyword options on PL/I I/O statements
Built-in subroutines that invoke RMS file-handling services
RMS, in turn, manages the details of communicating with the OpenVMS I/O system to transfer data and to organize and arrange data on physical devices.
4.2.1. PL/I Files and OpenVMS File Specifications
In a PL/I program, all I/O operations are performed on a file, using the name of a file constant or file variable. When the file is opened, PL/I associates the name of the file constant with a specific device or file on the computer system.
When a file variable is specified in an OPEN statement or in an I/O statement, the name used is that of the file constant with which the variable is currently associated. For example:
DECLARE F FILE, G FILE VARIABLE; G = F; OPEN FILE(G);
In this example, F is a file constant and G is a file variable assigned the value of F. In the OPEN statement, PL/I uses the name F to associate PL/I file with an OpenVMS file. The default file would be F.DAT.
The following sections describe in more detail how Endless PL/I associates a file constant with a device or file.
4.2.2. Using the TITLE Option
When you specify the TITLE option on an OPEN statement, you can include all or part of an OpenVMS file specification to indicate the file or device to be associated with the PL/I file. The following examples illustrate the use of the TITLE option.
OPEN FILE (OUTFILE) TITLE('DB1:[PAYROLL.DAT]JANUARY.LOG;2');
This file specification completely defines a file on the local OpenVMS system.
OPEN FILE (PRINTFILE) PRINT TITLE('LPC0:SAMPLE.DAT');
This output file will be directed to LPC0:, the system printer device. The listing file will have the title SAMPLE.DAT on its burst page. OpenVMS spools low-speed I/O devices such as printers by accumulating data for the device in a file, and then queuing the file for processing when it is closed.
NAME = 'TEST'||COUNT; ⋮ OPEN FILE(NEWFILE) OUTPUT TITLE(NAME);
The specification of this file is determined by the value of COUNT. For example, if COUNT is 5 when this OPEN statement executes, the file created is TEST5.DAT.
When no TITLE option is specified, PL/I supplies a default value for the file's title. The default title is the name of the file constant associated with the PL/I file. Whenever a title does not completely specify a file, PL/I takes the following steps, in order:
It performs logical name translation. If there is a colon (:) present in the TITLE option, the file system attempts to find an equivalence name for the portion of the file specification on the left of the colon. If there are no punctuation marks in the TITLE option, the file system attempts to find an equivalence name for the entire specification.
It supplies missing fields from the value specified in the DEFAULT_FILE_NAME option of the ENVIRONMENT attribute, if that option is specified.
It applies system defaults to complete the file specification.
If the file specification that is finally achieved is invalid or represents an illegal device or file (for example, an input file cannot be found), the UNDEFINEDFILE condition is signaled.
4.2.3. Using Logical Names
At DCL command level before executing a program, you can create a logical name to assign an OpenVMS file specification to the identifier of a PL/I file constant or to a value specified in a TITLE option. For example, suppose your PL/I program declares and opens a file as follows:
DECLARE INFILE FILE; ⋮ OPEN FILE (INFILE) RECORD INPUT;
Before running the program, you might associate an OpenVMS file with the identifier INFILE:
$ DEFINE INFILE DB1:[TEMP]A.DATThe DEFINE command assigns the PL/I file INFILE the OpenVMS file specification DB1:[TEMP]A.DAT. In OpenVMS terms, the name INFILE is a logical name, and the name DB1:[TEMP]A.DAT is an equivalence name for the logical name.
You can also use the DEFINE command to specify alternate device or file equivalents for the PL/I default file constants SYSIN and SYSPRINT. For example, to redirect output for the default file SYSPRINT, you could issue the following command:
$ DEFINE SYSPRINT TEST.OUTWhile this assignment is in effect, any PL/I procedure that outputs data to SYSPRINT (without opening SYSPRINT with an explicit title) will create a file named TEST.OUT on the current default device.
Logical names can also be established by other commands. For example, you can specify a logical name for a device when you enter an ALLOCATE or MOUNT command while placing the device on line. For example:
$ALLOCATE$_Device:MT:$_Log_Name:INFILE_MTA1: ALLOCATED
This ALLOCATE command allocates a tape drive and establishes the logical name INFILE for it. When a PL/I program reads from the file INFILE, the system translates the name INFILE and uses the tape MTA1: as the input device.
Logical Names in TITLE Values
The value specified in a TITLE option can represent a logical name. For example:
OPEN FILE(INFILE) TITLE ('NEWFILE');
This file might be defined as follows:
$ DEFINE NEWFILE LARGO.TXTWhen the OPEN statement opens the file INFILE, the file's title (NEWFILE) is translated to LARGO.TXT. If NEWFILE is not defined when the OPEN statement is executed, the OPEN statement opens the file NEWFILE.DAT.
If instead of containing a colon a file specification in the TITLE option contains any of the punctuation marks that are used in OpenVMS file specifications, the file system does not translate that portion of the specification. For example:
TITLE ('STATES.')
In this example, the file system assumes that 'STATES.' is the specification of a file name and a file type (the presence of the period indicates a null file type). It does not perform any translation.
When you enter a complete file specification for the TITLE option and you do not want the file system to attempt logical name translation, you can precede the file specification with an underscore (_). For example:
TITLE ('_DBB1:[APPLIC.FILES]MASTER.SRC')
The system does not perform translation if an underscore precedes either a device name or a file name that is specified with no punctuation.
Process Permanent Logical Names
The system provides every user and every batch job with a default set of process logical name assignments, which are listed in Table 4.1, “Default Process Logical Names”. Because the files associated with these assignments exist for the life of the process or job, and because they are permanently open, they are called process permanent files.
The default files associated with the GET and PUT statements, SYSIN and SYSPRINT, are defined by PL/I as follows:
| Statement | PL/I File | Default Title |
|---|---|---|
| GET | SYSIN | SYS$INPUT |
| PUT | SYSPRINT | SYS$OUTPUT |
Thus, when your program executes a GET statement that does not specify the FILE option, and if SYSIN was not explicitly opened with a title, the run-time system and the file system perform the following translations:
PL/I attempts to translate the logical name SYSIN. If no logical name assignment exists for it, PL/I replaces the name SYSIN with the name SYS$INPUT.
The system translates the logical name SYS$INPUT. The resulting file specification is your current input device.
A similar set of associations occurs when a program executes a PUT statement without the FILE option: the resulting output is written to the current output file, SYS$OUTPUT.
4.2.4. Using the DEFAULT_FILE_NAME Option
Use the DEFAULT_FILE_NAME option of the ENVIRONMENT attribute to specify default values for a file specification when a file is opened.
For example:
OPEN FILE (REPORT) RECORD OUTPUT ENVIRONMENT ( DEFAULT_FILE_NAME('.LIS'));
The default file type LIS will be applied in the following cases:
No logical name assignment exists for the name REPORT when the program containing this statement is executed. In this case, the file will be named REPORT.LIS, and it will be cataloged in the current default directory.
The equivalence name for the logical name REPORT does not contain a file type. In this case, the file type LIS will be supplied by default to the translated equivalence of the logical name REPORT.
PL/I uses the punctuation in the DEFAULT_FILE_NAME option to determine which portion of the file specification is specified. Thus, the period (.) in the preceding example indicates that the value is a file type. An unpunctuated name is treated as a file name; a name terminated by a colon (:) is treated as a device name (and can therefore be a logical name).
When the DEFAULT_FILE_NAME option is not specified for a file, and no file type is specified, PL/I supplies the default file type DAT.
PL/I applies the value of the DEFAULT_FILE_NAME option after it establishes the file's title. Thus, in the preceding example, the title, REPORT, is established before the value '.LIS' is applied. Note that the only time a file name in a DEFAULT_FILE_NAME option is used is when the TITLE option specifies a null string; that is, the TITLE option is specified as follows:
TITLE('')
A DEFAULT_FILE_NAME option can specify any portion of a file specification. For example:
DECLARE REMOTE_FILE FILE RECORD INPUT ENV(DEFAULT_FILE_NAME( 'RONDO::DBB2:[MALCOLM].TXT'));
This option specifies a node name, device, directory, and file type. The file name must be supplied when the file is opened. For example:
OPEN FILE(REMOTE_FILE) TITLE('ALLEGRO');
This statement opens the file RONDO::DBB2:[MALCOLM]ALLEGRO.TXT.
Another OPEN statement for the file can specify a different TITLE option, for example, TITLE('ANDANTE'), to open a different file.
4.2.5. Expanding File Specifications
After logical name translation and after values supplied by the DEFAULT_FILE_NAME option, if any, are applied, the defaults that the file system applies are as follows:
| Field | System Default Provided |
|---|---|
| Node | Local system |
| Device | Current default device |
| Directory | Current default directory |
| File name | None |
| File type | DAT |
| Version number | For an input file, the most recent version; for an output file, the highest existing version number, plus 1 |
The following examples enumerate the steps in completing a file specification. All examples assume that the following logical name assignments are in effect:
| TAPEFILE | = MTA0: |
| STATE_NAME | = NEBRASKA |
| STATES | = DMA2:[BACKUP] |
They also assume the following current default device and directory:
DBB1:[MALCOLM]
In the following example, the value in the TITLE option represents the complete file specification:
DECLARE STATES FILE RECORD OUTPUT; OPEN FILE(STATES) TITLE ('_DMA2:[STATE.DATA]NEVADA.DAT;2');
Thus, the final specification is: _DMA2:[STATE.DATA]NEVADA.DAT;2
The following example uses several steps to obtain the file specification:
DCL STATES FILE INPUT ENVIRONMENT( DEFAULT_FILE_NAME ('[STATE.FILES].DAT')); OPEN FILE(STATES) TITLE ('MISSOURI');
The steps are:
Obtain the value specified in the TITLE option, MISSOURI.
Since there is no logical name assignment for MISSOURI, use MISSOURI as the file name.
Apply the value in the DEFAULT_FILE_NAME option, which includes a default directory, [STATE.FILES], and a default file type, DAT.
Apply system defaults for device and version number (for an input file).
The final specification is: DBB1:[STATE.FILES]MISSOURI.DAT;n where n is the highest existing version of the file.
The following example includes the translation of a logical name:
DECLARE STATES FILE RECORD OUTPUT; OPEN FILE(STATES) TITLE ('STATE_NAME');
The steps are:
Obtain the value from the TITLE option, STATE_NAME.
Translate the logical name STATE_NAME to obtain the equivalence, NEBRASKA.
Apply default device, directory, file type, and version number (for an output file).
The final specification is: DBB1:[MALCOLM]NEBRASKA.DAT;n where n is 1 higher than the number of any existing version of the file.
In the following example, no title is specified and the default title is applied:
DCL STATES FILE RECORD OUTPUT; OPEN FILE (STATES);
The steps are:
Apply the default title, STATES.
Translate the logical name STATES to obtain the equivalence name, DMA2:[BACKUP].
Apply default file type DAT and the default version number (for an output file). Note that no default is supplied for the file name.
The final specification is: DMA2:[BACKUP].DAT;n where n is 1 higher than the number of any existing version of the file.
The following example specifies a tape file:
DCL TAPEFILE FILE RECORD ENVIRONMENT( DEFAULT_FILE_NAME('TAPEFILE:')); OPEN FILE(TAPEFILE) OUTPUT TITLE('TAPE1.FIL');
The steps are:
Apply the title TAPE1.FIL.
Translate the logical name TAPEFILE in the DEFAULT_FILE_NAME option to MTA0:, its equivalent.
Use the system default version number for tape files, 0. Tape files do not have directories.
The final specification is: MTA0:TAPE1.FIL;0
4.3. Error Handling
PL/I uses the standard PL/I ON condition names to signal run-time errors that occur for file operations. The ON conditions and the circumstances under which they are signaled are as follows:
The UNDEFINEDFILE condition is signaled whenever a file cannot be opened.
The ENDFILE condition is signaled when the end-of-file is reached during an input operation.
The ENDPAGE condition is signaled for a file with the PRINT attribute when the current line number exceeds the page size specified for the file.
The KEY condition is signaled for a file with the KEYED attribute when any error involving the interpretation, writing, or specification of a key occurs.
The ERROR condition is signaled for all other file-related errors.
To handle any of these conditions in a PL/I procedure, you can establish an ON-unit to receive control if the specified condition is signaled. For example:
ON UNDEFINEDFILE (INFILE) OPEN FILE (INFILE) TITLE ('SYS$INPUT');
The ON statement provides a default title for the file INFILE.
4.3.1. Values Returned by PL/I Built-In Functions for Error Handling
An ON-unit can be a generalized error-handling routine, written so that it responds to specific errors or prints an error message. Following are the PL/I built-in functions that provide meaningful information in an ON-unit to handle a file system error:
ONCODE
ONFILE
ONKEY
Whenever an error is signaled, the built-in function ONCODE makes available the condition value associated with the specific error. When a PL/I program is executing under control of the OpenVMS operating system, the value returned by the ONCODE built-in function is a unique 32-bit condition value that indicates the reason for the error. This value is from the system, from RMS, or from the PL/I run-time system.
The built-in function ONFILE returns a character string giving the name of the file constant on which the error occurred.
If the file was being accessed by key, the ONKEY built-in function returns the key value that caused the error to be signaled.
4.3.2. Writing an Error Handler
You can write an ON-unit to detect and correct errors that occur during file operations. The following example shows an ON-unit that detects whether a record with a given key value was not found or whether an attempt was made to write a record whose key duplicates the value of an existing key.
ON KEY(STATE_FILE) BEGIN; %INCLUDE $RMSDEF; /* Check for a record not found */ IF ONCODE() = RMS$_RNF /* if record not found */ THEN DO; PUT SKIP EDIT(STATENAME,'Not found.') (A,X,A); STOP; END; /* Check for duplicate key */ ELSE IF ONCODE = RMS$_DUP THEN DO; PUT SKIP EDIT('Record already exists for', STATENAME) (A,X,A); STOP; END; END;
In this example, the ON-unit declares symbolic names for two specific status values returned by ONCODE:
The value RMS$_RNF indicates that no record exists with the specified key value.
The value RMS$_DUP indicates that a record already exists with the specified key in an index for which duplicate keys are not allowed.
In an ON-unit for the KEY condition, ONCODE may also return the value associated with the status code RMS$_KEY. This code indicates that a key value is invalid; for example, it is an incorrect data type.
The symbolic names for RMS status codes are declared as %REPLACE constants in module $RMSDEF of PLI$STARLET.
4.3.3. Default Error Handling for the File System
If a file system error occurs during the execution of a PL/I statement, the PL/I run-time system signals either the specific PL/I condition name or the ERROR condition. If no user-specified ON-units exist to handle either the specific PL/I condition or the ERROR condition, PL/I performs its default condition handling.
If any active procedure specified OPTIONS (MAIN), a default PL/I condition handler is present and executed. It prints a PL/I run-time error message. If there is no default PL/I handler, the error signal is passed to the default condition handler established by the OpenVMS system, which prints the message associated with the RMS error. If the error was a fatal error, the handler terminates the program; otherwise, the program continues.
The following example illustrates the type of message that the PL/I run-time system displays when an error occurs during an I/O operation:
%PLI-F-ERROR, PL/I ERROR condition. -PLI-I-IOERROR, I/O error on file 'STATE_FILE' -PLI-I-FILENAME, File name:'_DB7:[PROJECT]STDATA.DAT;' -PLI-I-NOTKEYD, Not a KEYED file. %TRACE-F-TRACEBACK, symbolic stack dump follows module name routine line relative PC absolute PC FLOWERS BEGIN%35 35 00000085 00000C88 FLOWERS BEGIN%29 29 000000BD 00000C02 FLOWERS FLOWERS 25 000000D3 00000B42
In this example, the error occurred because a keyed I/O statement was specified for a file lacking the KEYED attribute.