Chapter 3
The File System
This chapter discusses the use of files for input and output (I/O) in PL/I and describes the aspects of the operating system that relate to PL/I I/O. The chapter includes the following topics:
Declaring, opening, and closing files
The relationship between the I/O statements in PL/I and the I/O procedures of the operating system
POSIX file-naming and file-defining conventions
File system error handling at run time
Chapter 4, File Organizations and Input/Output, Chapter 5, Options of the ENVIRONMENT Attribute, Chapter 6, Input/Output Statement Options, and Chapter 7, File-Handling Built-In Subroutines give additional information on the file system, such as stream and record I/O, options (ENVIRONMENT and I/O statement options), and built-in subroutines for file handling.
3.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 that describe 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 that refers 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 Chapter 4, File Organizations and Input/Output, "Chapter 4, File Organizations and Input/Output ".
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 on the CLOSE statement; the ENVIRONMENT options are summarized in Chapter 5, Options of the ENVIRONMENT Attribute.
Declaring, opening, and closing files are discussed in more detail in the Endless PL/I for POSIX Systems Reference Manual.
3.2. Using the UNIX 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 PL/I run-time library routine. These routines in turn make calls to the appropriate operating system services.
Note that, although you can call operating system services directly from a PL/I program, it is not normally necessary to do so. A PL/I program executed on a POSIX system has full access to I/O capabilities through the following language elements:
Options of the ENVIRONMENT attribute
Keyword options on I/O statements in PL/I
Built-in subroutines
3.2.1. PL/I Files and UNIX 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.
By default, 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 the PL/I file with a UNIX file. The default file would be F. To change the name, use the title option of the DEFAULT_FILE_NAME environment option. Refer to Section 5.6, “DEFAULT_FILE_NAME Option” for more information.
The following sections describe in more detail how PL/I associates a file constant with a device or file.
3.2.2. Using the TITLE Option
When you specify the TITLE option on an OPEN statement, you can include all or part of a POSIX 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.
This file specification completely defines a file on the local system. When accessing the file OUTFILE, the
program will be written to the file /usr/payroll/january.
OPEN FILE (OUTFILE) TITLE ('/usr/payroll/january');
The following is an example of using a variable to specify the title:
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.
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.
If the value of the specified title begins with a dollar sign ($) the value is interpreted as an environment variable and substituted accordingly. If the substituted value contains a dollar sign ($) it is also interpreted as an environment variable. This process terminates when no further substitutions can be made or there are no more dollar signs.
Upon completion of the translation phase, if the DEFAULT_FILE_NAME option of the ENVIRONMENT attribute is used, the name associated with the file is merged with the DEFAULT_FILE_NAME option.
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. Note that the final file specification cannot exceed the value of MAXPATHLEN as defined in <sys/param.h>.
3.2.3. Using Environment Variables
Before executing a program at the shell level, you can create an environment variable to assign a UNIX 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 OUTPUT;
The local file specification created on the local system is INFILE.
3.2.3.1. Environment Variables in TITLE Values
The value specified in a TITLE option can represent a environment variable when it starts with a dollar sign ($) For example:
OPEN FILE(INFILE) TITLE ('$NEWFILE');
If, before running the program, you define an environment variable called $NEWFILE, the OPEN statement
would use the value of NEWFILE as the title. For example:
% setenv NEWFILE /usr/users/you/databases/phonebook
(This command may differ on your shell.) The file opened would be:
/usr/users/you/databases/phonebook
3.2.3.2. Process Standard System File Names
The system provides every process with a default set of standard name assignments, as listed in Table 3.1, “Default Process Stream Names”. Because the files associated with these assignments exist for the life of the process, and because they are permanently open, they are called process permanent files.
| Stream Name | Default Equivalence Name |
|---|---|
| stdin | Standard input. For an interactive user, this is the terminal or, if redirected, the input command file. |
| stdout | Standard output. For an interactive user, this is the terminal or, if redirected, the output file name specified. |
The default files associated with the GET and PUT statements, SYSIN and SYSPRINT, are defined by PL/I as follows:
| Statement | Default PL/I File | Default Title |
|---|---|---|
| GET | SYSIN | stdin |
| PUT | SYSPRINT | stdout |
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 reads from standard input.
A similar set of associations occurs when a program executes a PUT statement without the FILE option: the resulting output is written to standard output, stdout.
In the dec and ansi dialects, the process permanent file SYSOUT is also mapped to stdout.
The file symbols "SYSPRINT", "SYSIN", and "SYSOUT" are always case insensitive regardless of the specified compiler
-m or --case option. In other words, whether you specify "sysprint", "Sysprint", or
"SYSPRINT", you will always refer to the pre-declared PL/I files.
The file symbols "SYS$PRINT", "SYS$INPUT", and "SYS$OUTPUT" are not predeclared. However, if you declare any of these, they map to the same files as the predeclared process permanent files, "SYSPRINT", "SYSIN", and "SYSOUT".
3.2.4. Expanding File Specifications
The following examples enumerate the steps in completing a file specification. All examples assume that the following environment variable assignments are in effect:
STATE_NAME = NEBRASKA
STATES = /usr/BACKUP
They also assume the following current default device and directory:
/usr/users/malcolm
Example 1:
DECLARE STATES FILE RECORD OUTPUT; OPEN FILE(STATES) TITLE ('/usr/STATE.DATA/NEVADA');
Steps:
Obtain the value in the TITLE option. This value represents the complete file specification.
Final Specification: /usr/STATE.DATA/NEVADA
Example 2:
DECLARE STATES FILE RECORD OUTPUT; OPEN FILE(STATES) TITLE ('$STATE_NAME');
Steps:
Obtain the value from the TITLE option, $STATE_NAME.
Translate the environment variable STATE_NAME to obtain the equivalence, NEBRASKA.
Final Specification: /usr/users/malcolm/NEBRASKA
Example 3:
DCL $STATES FILE RECORD OUTPUT; OPEN FILE ($STATES);
Steps:
Apply the default title, STATES.
Translate the environment variable STATES to obtain the equivalence name,
/usr/BACKUP.
Final Specification: /usr/BACKUP
3.3. Error Handling
Endless PL/I for POSIX Systems 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.
In the IBM dialect only, the following ON conditions are also used:
See the Endless PL/I for POSIX Systems Reference Manual for more information on these conditions.
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 ('input');
The ON statement provides a default title for the file INFILE.
3.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 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 file system or from the PL/I run-time system. Note that file system errors are mapped to RMS (VAX Record Management Services) errors by the PL/I run-time library for compatibility with VAX PL/I.
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.
3.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 the system include file $RMSDEF
(/usr/lib/cmplrs/pli100/usr/include/rmsdef.in).
3.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 UNIX 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:
PL/I unhandled exception at 0x00401380: PL/I ERROR condition. PL/I UNDEFINEDFILE condition on file 'INFILE'. FILENAME: '/usr/users/tim/databases/myfile.dat'. FILENAME, FNF, File not found.
In this example, the error occurred because an OPEN statement could not find the specified file. This fatal error terminates the program.