User's Manual for Digital UNIX
This manual gives an overview of the PL/I language and an explanation
of PL/I program development. It describes the operation of the
Kednos PL/I for UNIX compiler and the features of the Digital UNIX
operating system environment that are important to the PL/I
programmer.
Operating System and Version: Digital UNIX Version 3.2 and
higher
Kednos Systems, Inc., makes no representations that the use of its products in the manner described in this publication will not infringe on existing or future patent rights, nor do the descriptions contained in this publication imply the granting of licenses to make, use, or sell equipment or software in accordance with the description.
Possession, use, or copying of the software described in this publication is authorized only pursuant to a valid written license from Kednos or an authorized sublicensor.
No responsibility is assumed for the use or reliability of software on equipment that is not listed as supported in the Product Description.
Restricted Rights: Use, duplication or disclosure by the U.S. Government is subject to restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in Technical Data and Computer Software clause at DFARS 252.227-7013.
© Kednos Corporation, 1995, 1996, All Rights Reserved.
Kednos Corporation, Kednos PL/I, and Kednos VPO are trademarks of Kednos Corporation.
Alpha AXP, AXP, CDD, DEC,DEC 4000, DECwindows, Digital, OpenVMS AXP, ULTRIX, VAX, OpenVMS, VT102, VT220, VT240, VT320, VT330, VT340, and the DIGITAL logo are trademarks of Digital Equipment Corporation.
SAA and IBM are trademarks of International Business Machine Inc.
Stratus is a trademark of Stratus Computer Inc.
Kednos PL/I for UNIX includes the GNU readline and assembler software. See See for the entire text of the Free Software Foundation's GNU Copyleft.
Portions Copyright 1984-1990 FairCom Corporation. All Rights Reserved.
Kednos requests your critical evaluation to assist in preparing future documentation. Please send any comments to comments@Kednos.com or by physical mail to:
Compiling and Linking a PL/I Program 2-1
Compiling Multi-Language Programs 2-4
Linking Objects using the pl1 Command 2-8
Preprocessor Compilation Control 2-11
Passing Command Line Parameters to a PL/I Program 2-20
Accessing Automatic and Parameter Data 3-7
Qualifying Structure References 3-7
Referring to Arrays and Structures 3-8
Preparing to Use the Debugger 3-8
Compiling for the dbg Debugger 3-8
Debugging Optimized Programs 3-9
Starting and Ending a Debugging Session 3-10
Ending the Debugging Session 3-11
Using the dbg Command Line Editing Features 3-11
Getting Started with Command Line Editing 3-12
Using the UNIX File System for I/O 4-2
PL/I Files and UNIX File Specifications 4-2
Using Environment Variables 4-4
Environment Variables in TITLE Values 4-4
Process Standard System File Names 4-5
Expanding File Specifications 4-6
Values Returned by PL/I Built-In Functions for Error Handling 4-8
Access Modes for Record I/O 5-3
Direct and Sequential Access 5-4
Access by Record Identification 5-4
IBM Dialect Fixed Length Environment Options 5-5
IBM Dialect Variable Length Environment Options 5-6
Appending Records to an Existing File 5-8
Superseding an Existing File 5-8
Relative File Organization 5-8
Populating a Relative File 5-11
Specifying and Using Environment Options 6-1
Arguments for Environment Options 6-1
Interpretation of ENVIRONMENT Options for Existing Files 6-3
Conflicting and Invalid ENVIRONMENT Options 6-3
Summary of ENVIRONMENT Options 6-4
FIXED_LENGTH_RECORDS Option 6-16
MAXIMUM_RECORD_SIZE Option 6-17
ENVIRONMENT Options for File Protection and File Sharing 6-26
FLUSH Built-In Subroutine (DEC Dialect Only) 8-1
REWIND Built-In Subroutine (DEC Dialect Only) 8-2
How the Sort Program Interface Works 9-2
Determining Which Entry Point to Use 9-3
Calling the Sort Subroutines 9-4
General Format of the Sort Interface Call 9-4
Specifying the Sort Fields 9-5
Specifying Record Information 9-7
Specifying Input and Output Routines 9-10
Input and Output Routines 9-11
Using the PLIRETC Built-In Subroutine 9-11
RESIGNAL Built-In Subroutine 10-1
Resignaling the Condition 10-5
Executing a Nonlocal GOTO 10-6
Relationship of UNIX Signals to PL/I ON-Units 10-8
Accessing the Signal Values 10-10
Modifying the ONCODE Values 10-11
Search Path for ON-Units 10-13
Default Handling for Main Procedures 10-14
Default Handling for Non-Main Procedures 10-15
Condition-Handling Built-In Functions 10-22
ONCODE Built-In Function 10-22
The UNIX Procedure Calling and Condition Handling Standard 11-2
Parameter-Passing Mechanisms 11-2
Passing Parameters by Reference 11-3
Dummy Arguments for Arguments Passed by Reference 11-4
Using Pointer Values for Arguments Passed by Reference 11-5
Passing Arrays to a FORTRAN Routine by Reference 11-5
Passing Parameters by Value 11-5
Dummy Arguments for Arguments Passed by Value 11-7
Special Parameter Attributes 11-7
Determining the Type of Call 11-10
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION A-2
How to Apply These Terms to Your New Programs A-8
Figure 3-1. Specifying Environments 3-5
Figure 10-1. Resignaling a Condition 10-6
Figure 10-2. Unwinding the Call Stack 10-7
Figure 10-3. Execution of an ON-Unit 10-14
Table P-1. Documentation Conventions Table xi
Table 2-1. Alphabetic List of PL/I Driver Options 2-4
Table 3-1. dbg Command Line Options 3-10
Table 3-2. Debugger Command Summary 3-17
Table 4-1. Default Process Stream Names 4-5
Table 4-2. System File Names for Get and Put Statements 4-5
Table 6-1. Description of Columns in Table 6-2 6-4
Table 6-2. Summary of DEC and ANSI Dialect ENVIRONMENT Options 6-5
Table 6-3. Summary of IBM Dialect ENVIRONMENT Options 6-6
Table 6-4. ENVIRONMENT Options That Are Ignored 6-7
Table 6-5. Default Record Sizes 6-18
Table 6-6. Default Record Sizes 6-20
Table 7-1. Summary of Input/Output Statement Options 7-2
Table 9-1. Entry Points for the Sort Program 9-3
Table 10-1. Corresponding Values 10-10
Table 10-2. ONCODE Values for PL/I ON Conditions 10-23
Table 11-1. Converted Data Types of Arguments Passed by Reference 11-4
Figure 3-1. Specifying Environments 3-5
Figure 10-1. Resignaling a Condition 10-6
Figure 10-2. Unwinding the Call Stack 10-7
Figure 10-3. Execution of an ON-Unit 10-14
Table P-1. Documentation Conventions Table xv
Table 2-1. Alphabetic List of PL/I Driver Options 2-4
Table 3-1. dbg Command Line Options 3-10
Table 3-2. Debugger Command Summary 3-17
Table 4-1. Default Process Stream Names 4-5
Table 4-2. System File Names for Get and Put Statements 4-5
Table 6-1. Description of Columns in Table 6-2 6-4
Table 6-2. Summary of DEC and ANSI Dialect ENVIRONMENT Options 6-5
Table 6-3. Summary of IBM Dialect ENVIRONMENT Options 6-6
Table 6-4. ENVIRONMENT Options That Are Ignored 6-7
Table 6-5. Default Record Sizes 6-18
Table 6-6. Default Record Sizes 6-20
Table 7-1. Summary of Input/Output Statement Options 7-2
Table 9-1. Entry Points for the Sort Program 9-3
Table 10-1. Corresponding Values 10-10
Table 10-2. ONCODE Values for PL/I ON Conditions 10-23
Table 11-1. Converted Data Types of Arguments Passed by Reference 11-4
This manual describes how to use theKednos PL/I for UNIX compiler on the Digital UNIX operating system, and contains detailed explanations of the extensions made to the standard PL/I language for this implementation. To aid in program development, it includes information on some UNIX commands and utilities. It also includes information to assist in writing PL/I programs that use features of the file system and the operating system.
This manual is designed for programmers who have a working knowledge of PL/I and some familiarity with the Digital UNIX operating system and the C shell (csh).
This manual is divided into the following sections:
See contains the Free Software Foundation's Copyleft.
The Kednos PL/I for UNIX Reference Manual contains a complete definition of PL/I for RISC ULTRIX and the VAX PL/I languages, with detailed reference information on all standard PL/I language elements.
The Kednos PL/I for UNIX Installation Guide gives instructions on how to install the PL/I for RISC ULTRIX compiler.
The manpages contain information on PL/I built-in functions and pseudovariables. For an introduction to manpages, type the following:
The Digital UNIX documentation set gives complete information on the operating system.
For the purposes of this manual, the term PL/I refers to Kednos PL/I for UNIX, which runs on the DEC OSF/1 and Digital UNIX systems.
All descriptions of the effects of executing statements and evaluating expressions assume that the initial procedure activation of the program is through an entry point with OPTIONS(MAIN).
It is further assumed that any non-PL/I procedures called by the program follow all conventions of the PL/I run-time environment.
Overview of Kednos PL/I for UNIX
Kednos PL/I for UNIX is a comprehensive and powerful programming language useful for systems programming, scientific computation, and commercial data handling and data organization. It is a block-structured language that lends itself to the creation of efficient and maintainable structured programs. It has extensive string-handling capabilities.
Kednos PL/I for UNIX is Kednos's implementation, with extensions, of the American National Standard PL/I General-Purpose Subset, ANSI X3.74-1981. The General-Purpose Subset is a subset of full PL/I, ANSI X3.53-1976.
The General-Purpose Subset was designed for scientific, commercial, and systems programming on small and medium-size computer systems. The subset excludes features of PL/I that are prone to error, not often used, or that greatly increase the complexity of run-time support required by the compiler.
Over and above its conformity to the General-Purpose Subset,Kednos PL/I for UNIX offers many enhancements that extend the functionality of the subset. Some of these extensions are features of full PL/I, and some are features for compatibility with other PL/I implementations in the industry, especially VAX PL/I. Other extensions integrate Kednos PL/I for UNIX into the Digital UNIX common language environment and into a complete programming environment. Kednos PL/I for UNIX extensions are intended for programs that will execute exclusively under the control of the UNIX operating system.
The Kednos PL/I for UNIX extensions provide support for the UNIX Procedure Calling and Condition Handling Standard, allowing PL/I procedures to call procedures written in other languages. Another notable extension is the preprocessor, which allows for conditional compilation of programs and for compile-time source transformation; it enables users to write procedures that will be executed at compile time.
Kednos PL/I for UNIX can be used with a number of tools in a complete programming environment. For example, the compiler system provides a source level, interactive debugger called dbg. This enables you to debug programs as they execute. Use of the debugger is described in See of this manual.
TheKednos PL/I for UNIX language is fully described in the Kednos PL/I for UNIX Reference Manual. This reference manual contains further information on the General-Purpose Subset, the UNIX extensions, and the differences between Kednos PL/I for UNIX and other implementations of the PL/I language.
Kednos PL/I for UNIX is compatible with other versions of Kednos PL/I (Open VMS and RISC ULTRIX) with some exceptions. VMS specific options that are not compatible are emulated, flagged at compile-time, or ignored, depending on the VMS specific option. See the appendix on language differences in the Kednos PL/I for UNIX Reference Manual for more information.
This chapter describes how to create, compile, link, and run a Kednos PL/I for UNIX program.
A PL/I source file is a UNIX file that contains PL/I code, as defined in the Kednos PL/I for UNIX Reference Manual.
To create a source file, use the text editor of your preference, such as the vi editor. You can also use any of the UNIX file management tools available on your system to generate source files. For example:
The following sections discuss the pl1 command and the command options.
A program called a driver invokes the major components of the compiler system. The components are:
The pl1 command runs the driver that compiles, optimizes, assembles, and link edits your programs. The command may be followed immediately by one or more options, by one or more filenames, or both.
A driver option. Driver options specify instructions to all the processing phases. You can specify either the long or short version of the options, as shown in See . Alphabetic List of PL/I Driver Options .
An input source file containing the program or module to be compiled. You must specify a file suffix. Valid suffixes are:
You can include more than one file specification on the same command line by separating the file specifications with a space as follows:
The driver command, pl1, invokes the following processing phases to compile and optionally link edit the source file:
By default, the pl1 command both compiles and link edits a source module. If you specify the -c driver option, processing stops after the assembler phase, producing a linkable object file. You can then use the pl1 or ld command to link edit the linkable object(s) into one executable binary. By default, the linkable object file has the same name as the source file, but with the suffix .o.
This produces the linkable object file.o.
The default name of the executable binary is a.out. For example:
This command line produces the executable binary a.out.
You can specify a different name for the executable binary by using the driver option -o and supplying the desired file name. For example:
This command line compiles and link edits the source module file.pli and produces an executable binary, file.
If you have previously compiled the source module and used the -c option to produce the linkable object file.o, the following command line links edit the object module:
This command link edits the object module file.o and produces the executable binary file. You can link edit several object modules together to produce a single executable binary, as follows:
This command link edits the object modules file1.o and file2.o and produces the executable binary file.
When specifying a name for your executable binary or object module, note that the full file name (file name and extension) must differ from the name of the source file(s). In other words, when compiling file.pli, do not supply file.pli as the full file name of your executable binary or object module.
When your application has two or more source programs written in different languages, including C, Pascal, and Fortran, compile each program module separately with the appropriate driver and then link them in a separate step. To create the linkable objects, use the pl1 command option -c. The following example compiles a PL/I program and a C program:
When you compile the routines, the drivers produce the linkable object files plifile.o and cfile.o. Use the pl1 command to perform the link edit, which loads and initializes the appropriate run-time libraries for PL/I.
See . Alphabetic List of PL/I Driver Options lists the options for the pl1 command line. The UNIX manpage pl1(1) also describes the pl1 command options if the manual pages are installed on the system.
Specifies natural alignment. On Alpha processors, -a is equivalent to -a8 |
||
Aligns to the specified byte boundary. n must be a power of two. The default value is -a1, which causes the compiler to align so there are no pad bytes in structures. |
||
Suppresses the loading phase of the compilation. Produces an object file even when you compile only one program. |
||
Defines the dialect of the compiler, where dialect is one of the following: ibm, dec, ansi. The default dialect is ansi. |
||
Produces debugger symbol table information. This option implies the -N option. |
||
Defines an additional directory for the PL/I preprocessor to search when looking for %INCLUDE modules You can specify this option multiple times to define several directories. |
||
Enables range and subscript checking. Turns on signalling of the STRINGRANGE and SUBSCRIPTRANGE conditions. Use this option to generate code to dynamically check the values of array, character, and bit string indexes. |
||
When linking, search an object library named libname.a, where name is a string. |
||
Changes the algorithm of searching for libx.a or libx.b so the default directories are not searched. Use this option when you only want to search the directories specified by the ld(1) option -Ldir. |
||
Changes the algorithm of searching for libx.a or libx.b so that ld searches the specified directory before the default library directories. |
||
-m lower 1 |
Specifies that all identifiers are case insensitive and externals are converted to lower case. This is the default. |
|
Specifies that all identifiers are case sensitive. Allows mixed case identifiers |
||
Specifies that all identifiers are case insensitive and externals are converted to upper case. |
||
Specifies the case of the include file names in a preprocessor %INCLUDE statement. The specified case is applied when the module name is built by the preprocessor. -M lower is the default, specifying that all file names are converted to lowercase. -M mix specifies case sensitivity, allowing mixed case file names. -M upper converts filenames to upper-case. |
||
Links the image without shared libraries. By default, images are linked with shared libraries. You must link without shared libraries to use the dbg debugger. Thus the -N option is implied by the -g option. |
||
Generates an executable binary with the specified file name. If you do not use this option, the compiler names the executable binary a.out. |
||
Performs all optimizations, including global register allocation. Restrictions: The -c option cannot be specified with the -O option. The -O option must precede all source file arguments. |
||
Generate information for profiling. |
||
Do not generate information for profiling. This is the default. |
||
Turns on the preprocessor phase of compilation. This is the default for the -D dec dialect. |
||
Turns off the preprocessor phase of compilation. This is the default for the -D ibm and -D ansi dialects. |
||
Generates a compiler listing file with corresponding filename and a suffix of .l. The listing file includes source program lines with all the included files expanded, and a datamap of the program. |
||
Defines the compilation variant used by the VARIANT preprocessor built-in function. Ignored if you compile without using the preprocessor. |
||
Defines the file suffix for include files. Supplied for compatibility with Digital and valid for the -D dec dialect only. |
||
Displays the compiler passes, with their arguments, input, and output files, as they execute. Also displays resource usage in the C shell time format. |
||
Includes cross reference information in the listing file. Implies -s; you need not use -s if you use -x. |
Use the pl1 command to link edit separate objects into one executable binary when the main program is written in PL/I. The driver recognizes the .o suffix as the name of a file containing object code suitable for link editing and immediately invokes the link editor. For example:
pl1 -o file mainfile1.o file2.o
Write the main program in PL/I and use the pl1 command to link edit the program to insure correct initialization of the PL/I run-time library. This statement produces the executable binary file.
The pl1 command implicitly calls the ld link editor (unless you specify the -c compile-only option). The link editor combines object modules to produce an executable binary. These object modules include:
A pl1 command where all the parameters are object files does only a link edit. For example, such a command might appear in a file for make(1) that specifies a build procedure. This file separates the compile operations from the link edit so that make can omit operations on source files that have not been modified.
If possible, use the pl1 command instead of ld to link edit PL/I object files. This automatically selects the correct run-time libraries and the correct version of ld. However, if you need to specify options to ld, you must invoke ld directly. Refer to the manpage on ld(1) for more information on specifying ld options, including specifying the run-time libraries.
The object code for the PL/I built-in routines is in an archive library. The distinctive suffix .a identifies a file as an archive library. The link editor gets your program code from your object file or files, and then gets the built-in routine code from object libraries called run-time libraries. It merges them and resolves references.
Kednos PL/I for UNIX includes the following run-time libraries:
The default run-time library for the pl1 command. It contains support for all PL/I language features except indexed file support (files declared or opened using the ENVIRONMENT(INDEXED) option). Programs using indexed files that are linked to this library generate fatal run-time errors.
Contains the same features as libpli.a with the addition of indexed file support (see libpli.a). Because the library increases the size of executable binaries, slows the link editing process, and requires additional memory during execution, use it only when indexed file support is required.
Contains additional support functions required by libplit.a.
To specify other libraries when invoking the link editor, use the -l option. Library names start with lib and have extensions .so (shared object), .a (archive) or .b (ucode). For example, if you have written a PL/I program that calls routines from the run-time library libx11.a, then specify:
The link editor (ld) searches for any libraries you specify using the default search path listed in the manpage for ld. However, the system administrator or installer determines the actual location of the PL/I run-time libraries, so you might need to add directories to the default search path.
The -L option to the link editor, when followed by a directory name, adds the specified directory to the search path for run-time libraries. Do not type any separators between -L and the name of the directory. You can use this option several times; the link editor searches the directories in the order that you specify on the command line. Your definition of the search path must precede your specification of libraries (using the -l option described in See Run-Time Libraries ) on the command line.
The link editor searches the directories you specify with -L, in the order you specify them on the command line, before it searches the standard directories (which were specified during installation). This lets you specify files that supersede the usual run-time library.
If you use the -L option and do not follow it with a directory name, the link editor does not search its standard directories.
When you use the -L option, the link editor uses the following search path:
The PL/I preprocessor lets you change a source program at compile time. You can mix preprocessor statements with nonpreprocessor statements in the source program, but the preprocessor statements only execute at compile time. The resulting source program is then used for further compilation.
The preprocessor does two types of preprocessing:
Preprocessor statements let you include text from other sources (%INCLUDE statements), control the course of compilation (%DO, %GOTO, %VARIANT, %PROCEDURE, and %IF), issue user-generated diagnostic messages, and selectively control listings and formats. The preprocessor statements are described in full in the Kednos PL/I for UNIX Reference Manual.
At compile time, preprocessor variables, procedures, and variable expressions are evaluated in the order in which they appear in the source text, and the new values are substituted in the source program in the same order. Thus, the course of compilation becomes conditional, and the resulting executable binary may exhibit a variety of unique features. Note that preprocessor variables and procedures must be declared and activated before replacement occurs.
%THEN %FATAL 'Please compile this outside of prime time';
%T = '''Compiled on '||DATE()||'''';
DECLARE INIT_MESSAGE CHARACTER(60) VARYING INITIAL(T);
%IF VARIANT() = ''| VARIANT() = 'NORMAL'
%T = '''unknown variant '||variant()||'''';
INIT_MESSAGE=INIT_MESSAGE||' with '||T;
This example illustrates several aspects of the preprocessor. First, you must compile this program outside of prime time. Second, depending upon the value of VARIANT, the program is compiled with a different variant.
Notice the number of single quote marks around the string constant assigned to T. Single quotes are sufficient if you only use the value of T in a preprocessor user-generated diagnostic message. That is, the value of T is concatenated with nonpreprocessor text and assigned to INIT_MESSAGE because during preprocessing, single quotes are stripped off of string constants. To ensure that the run-time program also has quotes around the string, you must supply additional quotes, as shown.
The %PROCEDURE statement defines the beginning of a preprocessor procedure block and specifies the parameters, if any, of the procedure. A preprocessor procedure executes only at compile time. Invocation is similar to a function reference and occurs in two ways:
A preprocessor procedure is invoked by the appearance of its entry name and list of arguments. If the reference occurs in a nonpreprocessor statement, the entry name must be active before the preprocessor procedure is invoked. If the entry name is activated with the RESCAN option, the value of the preprocessor procedure is rescanned for further possible preprocessor variable replacement and procedure invocation. Preprocessor procedures can be invoked recursively.
Since the preprocessor procedure is always invoked as a function, the %PROCEDURE statement must also specify (using the RETURNS option) the data type attributes of the value that is returned to the point of invocation.
The return value replaces the preprocessor procedure reference in the invoking source code. Preprocessor procedures cannot return values using their parameter list. The return value must be capable of being converted to one of the data types CHARACTER, FIXED, or BIT. The maximum precision of the value returned by the %RETURNS statement is BIT(31), CHARACTER(32500), and FIXED(10).
You can use either of the following two types of argument lists in preprocessor procedures:
Since a keyword argument list ends with a semicolon rather than a right parenthesis, the STATEMENT option lets you use a preprocessor procedure that has a keyword argument list as if it were a statement. Consequently, preprocessor procedures using the STATEMENT option let you extend the PL/I language by simulating otherwise unavailable features.
All preprocessor statements are preceded by a percent sign (%) and are terminated by a semicolon (;). All text that appears within these delimiters is considered part of the preprocessor statement and is executed at compile time. For example:
%DECLARE HOUR FIXED; /* declaration of a preprocessor
%DECLARE (A,B) CHARACTER; /* a factored preprocessor
%HOUR = SUBSTR(TIME(),1,2); /* preprocessor assignment
Notice that a percent sign (%) is required only at the beginning of the statement, and must be the first item, other than white space (spaces or tabs) on the line. Preprocessor built-in functions are contained within preprocessor statements and consequently do not require a percent sign.
You can label preprocessor statements. Like other PL/I labels, you can use labels on preprocessor statements as the targets of program control statements. A preprocessor label must be an unsubscripted label constant preceded by a percent sign. The format for a preprocessor label is:
%label: preprocessor-statement;
As with other preprocessor statements, the percent sign alerts the compiler that all text until the semicolon line terminator is preprocessor text. Therefore, you do not need to enter another percent sign on that line.
The compiler treats all statements within a preprocessor procedure as preprocessor statements. You must label preprocessor procedures to invoke them, and you must use a percent sign before the procedure label. However, statements within the procedure do not require leading percent signs.
For a table summarizing the preprocessor statements and for individual descriptions of the statements, see the Kednos PL/I for UNIX Reference Manual.
A number of PL/I preprocessor built-in functions are available for use at compile time. With few exceptions, they have the same effect as run-time PL/I built-in functions with the same name. For a table summarizing the preprocessor built-in functions and for individual descriptions of the functions, see the Kednos PL/I for UNIX Reference Manual.
If you specify either the -s or -x compiler option, the PL/I compiler produces a listing file. The listing file contains the following information:
The following example shows portions of a listing file:
source file: /lang/tmp/real_progAAAaagzEa.pl
compiled on: 950923 at: 17:24:54 by: ANSI/IBM PL/I, rev 1.04in: /local/home/louise/test
Listing File is in: /local/home/louise/test/
0-1 0 0 Test: procedure options (main); À
0-3 1 0 declare x character (8) initial ('foo'),
0-4 1 0 input_x character (8) initial ('');
0-5 1 0 declare y fixed bin (15) initial (42),
0-6 1 0 input_y fixed bin (15) initial (0);
0-7 1 0 declare valid bit(1) initial ('0'B);
0-9 1 0 put skip list ('What is the answer?: ');
0-11 1 0 put skip list ('Type the most common file name: ');
0-14 1 0 if (x = input_x) & (y = input_y)
0-16 1 0 valid=real_programmer();
0-18 2 0 put skip list ('You''re not a real programmer!');
0-22 1 0 real_programmer: procedure() returns(bit(1));
0-24 2 0 /* this exists to show another subroutine level */
0-25 * 2 0 /* in the listing file */
0-27 2 0 declare real_prog bit(1);
0-29 2 0 put skip list ('You''re a Real Programmer!!!');
0-32 2 0 end; /* real_programmer */
***** EXTERNAL ENTRY POINTS ***** Ã
name class size loc attributes
name class size loc attributes
INPUT_X automatic 8c 84 CHAR(8) UNALIGNED INITIAL
INPUT_Y automatic 1 96 FIXED BIN(15,0) ALIGNED PRECISION INITIAL
constant ENTRY RETURNS INTERNAL
SYSPRINT constant FILE EXTERNAL
VALID automatic 1b 112 BIT(1) UNALIGNED INITIAL
X automatic 8c 92 CHAR(8) UNALIGNED INITIAL
Y automatic 1 128 FIXED BIN(15,0) ALIGNED PRECISION INITIAL
procedure REAL_PROGRAMMER on line 22
name class size loc attributes
REAL_PROG automatic 1b 96 BIT(1) UNALIGNED
***** ENTRY POINTS AND ARRAY OF LABELS *****
name class size loc attributes
constant ENTRY RETURNS INTERNAL
*****ERROR 179 SEVERITY 1 on line 1 in file Õ /lang/tmp/real_progAAAaagzEa.pl.*****
The undeclared name "SYSIN" has been contextually declared
in this block. It will acquire default attributes.
*****ERROR 179 SEVERITY 1 on line 1 in file /lang/tmp/real_progAAAaagzEa.pl.*****
The undeclared name "SYSPRINT" has been contextually
declared in this block. It will acquire default attributes.
The following list describes the callouts in the preceding listing file example:
Header information -- contains information about the source file you compiled, such as when you compiled it, the compiler variant used (dec, ansi, ibm), and the directory specification of the listing file.
À The source program listing -- contains line numbers generated by the compiler, an optional asterisk (*) if the line is continued from a previous line, a level number, specifying the level of procedural nesting, a second level number, specifying the block level within a procedure, and the source text.
à Cross reference listing tables -- includes tables listing external entry points, then a block-by-block listing of each procedure or internal block in the program, describing each variable declared in the block.
Õ Compilation error messages -- the text of any error messages generated during compilation.
The PL/I compiler identifies syntax errors and violations of language rules in the source program. If the compiler locates any errors, it writes messages to standard output. If you enter the pl1 command interactively, the messages are displayed on your screen.
If the compiler creates a listing file it also writes these messages to the listing, as shown in the previous section.
When it appears on the screen, a message from the compiler has the following format:
*****ERROR nn SEVERITY s on line line-no in file filename.*****
The nn specifies the error number.
The s specifies the severity of the error. The following letters represent possible severities:
The compiler produces messages with warning severity if it encounters the following:
The filename indicates the file specification.
The line number n specifies the source file line number of the statement that caused the error. This is the line number assigned to a statement by the compiler. The error message also appears in the listing file (if listing is requested) with the listing line number.
The message-text is the message. In many cases, the message text consists of more than one line of output. The messages generally provide enough information for you to determine the cause of an error and correct it.
To run a PL/I program, enter the name of the executable binary produced by the pl1 command. If you did not use the -o option in the pl1 command, the default name of the executable binary is a.out. Enter a.out to run your PL/I program. If you used the -o option and specified a filename, enter the filename to run your program.
If an error occurs at run-time, a message appears on the terminal. See See for a description of run-time error conditions and messages.
You can pass command line parameters to your PL/I program, and access the parameters in your program. The following sections show how to write your code to access command line parameters, and how to run a program and specify command line parameters.
Kednos PL/I for UNIX provides two methods to access command line parameters:
In your main program, you can declare up to ten parameters to be passed from the command line when users run your program. You must declare these parameters CHARACTER VARYING, giving the actual length of the string as the maximum length.
PARAM: PROCEDURE (name,address,city,state,zip)
DECLARE (name,address,city,state,zip) CHAR(100) VARYING;
Your program can access these parameters only if the parameters are actually passed upon program invocation. To check the number of specified parameters, reference the external variable ARGC (argument count), included in the global definitions file pl1std.in, as shown in the example below.
You can access the command line parameters using the global variable ARGV (argument pointer), a pointer to an array of pointers to the actual parameters passed to the program. Again you can reference only as many parameters as were actually passed on the command line.
Both ARGC and ARGV are included in the global declarations include file, plistd.in, supplied with Kednos PL/I for UNIX.
The following example shows both methods of accessing command line parameters:
PARAM_TEST: PROCEDURE (name, address, city, state, zip)
OPTIONS(MAIN);
DECLARE (name, address, city, state, zip) CHARACTER(100)
VARYING;
PUT SKIP EDIT ('Name: ',Name) (a,a);
PUT SKIP EDIT ('Name is missing') (a);
PUT SKIP EDIT ('Address: ',Address) (a,a);
PUT SKIP EDIT ('Address is missing') (a);
PUT SKIP EDIT ('City: ',City) (a,a);
PUT SKIP EDIT ('City is missing') (a);
PUT SKIP EDIT ('State: ',State) (a,a);
PUT SKIP EDIT ('State is missing') (a);
PUT SKIP EDIT ('Zip: ',Zip) (a,a);
PUT SKIP EDIT ('Zip is missing') (a);
PUT SKIP EDIT ('Parameter ',i, 'is ',ARGS(i)->ARG_CV) (a,f(2),a,a);
To specify command line parameters, type them after the command that runs your PL/I program. For example, if you compile the preceding example using the -o command line option, and call your program param_test, run it as follows:
% param_test "Jocelyn Wood" "92 Forest Path" "Groveland" "New Hampshire" "01110"
This chapter describes how to use the dbg debugger with Kednos PL/I for UNIX programs. This chapter provides the following information:
A debugger helps you locate the cause of run-time errors like incorrect output, an infinite loop, or premature termination of your program. The debugger lets you observe and manipulate program execution interactively so you can find the point where it stopped working correctly. Using a debugger helps you isolate errors in your code much more quickly than you otherwise could.
To use a debugger, you must compile and link your program successfully -- your program must not contain illegal constructs in the source code.
By issuing debugger commands at your terminal, you can do the following:
Once you have found the error in your program, you can edit your source code, fix the problem, and compile, link, and run the corrected version.
Dbg is a high level symbolic UNIX debugger. Using dbg, you can refer to program locations by the symbols (names) you used for those locations in your program -- the names of variables, routines, labels, and so on.
The dbg debugger is specific to Kednos PL/I for UNIX. If you wrote your program in more than one language, the debugger executes all of the code, letting you use dbg commands to debug the PL/I sections.
In addition to the program execution, code manipulation and display functionality, dbg includes the following features:
You can record the commands you issue during a debugging session and play the file back to execute the commands automatically.
You can use the audit command to write both your commands and their output to a file.
The help command displays brief information about dbg commands and related topics.
You can use the alias command to create personalized replacements for dbg commands.
The next sections contain information and definitions you should understand before using dbg.
The following terminology is used throughout this chapter:
Dbg works within the scope of the particular procedure block that is currently executing. This scope is the working environment. When you refer to a symbol or locator (defined later in this section), dbg looks for it in the working environment, issuing an error message if it is not found.
The environment command, described later in this chapter, lets you change the working environment. This and other commands require an environment specifier as a parameter. The environment structure parallels the directory/file structure of UNIX systems, starting with a root environment, similar to the root directory.
You can specify an environment in either of the following two ways:
The first colon (:) stands for the imaginary block, the block generated by the compiler to contain all outermost symbols in your source compilation unit. The imaginary block is at lexical level 0.
Name stands for the name of a routine in your source code. The first named routine must exist at lexical level 1 and not be contained in any other block.
You can specify a list of routine names contained within the first named routine. Use a colon to separate names.
To refer to a procedure either immediately contained in your current environment or contained at a lower level (contained within a procedure that ultimately is contained by your current environment), use a name or list of names to navigate inward, as follows:
To refer to a procedure immediately superior within the current module, use a caret (^). You can use multiple carets to navigate upward through your environment structure. Note that you cannot, at any time, navigate outward beyond the imaginary block for the compilation unit.
When you combine the caret symbol and block names in a relative environment specification, use a colon to separate names. Do not use the colon between a name and a caret.
See . Specifying Environments shows a typical program structure and the commands used to specify various environments in the program, starting at your current working environment.
Definitions for other terms appear in the text, with the term in bold type.
Many dbg commands contain data references. The following sections give general information on when you can access various types of data and how to qualify data references.
Dbg can access most PL/I data. However, you must consider storage class when you try to access data. In addition to assuring the data has a storage class that dbg can access, you may need to change your environment so you are in the scope of the data -- the part of your program where the named data has meaning -- to access some classes of data.
The following sections list the kinds of data that dbg can access, and describe how to access data of various storage classes. See See ENVIRONMENT for information on changing your environment. See See BREAK , See CONTINUE , and See STEP for information on executing your program and stopping in a specific location.
Dbg can access any valid PL/I data except implicitly based variables, data with dynamic sizes or extents (including arrays with dynamic bounds and strings with dynamic lengths), parameter data with * extents, controlled data, and defined data.
PL/I allocates storage for static data when the program activates, and maintains the storage for the duration of the program.You can set and show static data any time during program execution, providing your environment is within the name scope of the data.
External static data has the largest and outermost name scope. You can access it from all environments contained in your program since its scope extends from definition to the end of the program.
Internal static data is recognized from the declaration to the end of the immediately enclosing block, including contained blocks. To set or show internal static data, make sure your environment is in the name scope of the data.
Note that names declared in a block supersede both previous declarations of that name in any containing blocks and any external definitions, for that block and any contained blocks.
Automatic and parameter data exists locally in a routine. PL/I allocates storage for automatic variables only when the block that declares it is activated. The storage is released upon block deactivation. Parameter data likewise is unavailable until you call the routine to which the data is passed.
Dbg can access automatic and parameter data if the following conditions are true:
Access to explicitly qualified based variables follows the same rules as automatic data, with the following addition:
See the Kednos PL/I for UNIX Reference Manual for more information on based variables.
To access a structure member, you must fully qualify it within the structure. For example, the following structure contains a customer name:
If you are in an environment where this structure is active, you can access members of the structure by qualifying them fully to dbg as, for example, CUSTOMER_NAME.MIDDLE_INIT. You cannot omit intermediate qualification names when specifying structures to dbg.
When referring to arrays and structures in dbg, enclose the array bounds and structure numbers in square brackets rather than parentheses. Also, note that each member of the structure must be individually qualified. For example, the following structure contains an array of customer names:
Within dbg, use the following syntax to refer to the first FIRST_NAME in this array:
CUSTOMER_NAME[1].FIRST_NAME[1]
The following example shows invalid syntax. Do not use either of these:
Source-level debugging relates the run-time operation of your program to the source files. For this to happen, your executable program must contain information that relates the run-time actions to elements from the source file, such as variable identifiers.
When compiling and/or linking for the debugger, specify the -g flag, as shown in the following examples:
This produces an object file, lottery.o, and a file containing the symbol table information used by the compiler during linking, lottery.st.o.
This produces an executable file, lottery, and a file containing the symbol table information used by the debugger, lottery.st.
% pl1 -g lottery.pli -o lottery
This produces an executable file, lottery, and a file containing the symbol table information used by the debugger, lottery.st.
See See The pl1 Command and See Linking Objects using the pl1 Command for information on the commands used to compile and link PL/I code. See See Driver Options for more information on using options when generating an executable file.
You normally do not perform source-level debugging on optimized code. The optimizing phases discussed in See are intended only for debugged programs.
The optimizer often reorders portions of code to gain efficiency. When you run optimized code using the debugger and look at the values of various symbols, they might not be in the state you expect given your current breakpoint location.
Also, optimized code sometimes uses registers, instead of memory, to store values. Thus, the value you find in memory may not be current, and the debugger will not find the current value in the register.
If you must debug optimized code, use an assembly-level debugger such as dbx.
The dbg command invokes the dbg debugger and does the following:
Command options specify instructions for processing. See . dbg Command Line Options lists the dbg command options.
Specifies the name of the executable file. If you do not specify a filename, dbg uses the default, a.out.
Dbg executes the dbg commands in your .dbginit file or files when you invoke the debugger. Using these files is optional; you do not need to create a .dbginit files.
Use the .dbginit file in your $home directory to automatically execute dbg commands that you use every time you enter the debugger. Use the .dbginit file in your current working directory (where your PL/I executable file resides) to automatically execute dbg commands specific to your program. For example, you can use the shell command in dbg to print your working directory or the audit command in dbg to open an audit file.
Use your preferred UNIX editor to create .dbginit files. You can also use the record dbg command, described later in this chapter, to create a file containing dbg commands, which you can then rename to .dbginit.
Note that the commands in the .dbginit files must be valid at the point when dbg runs the .dbginit file. See the command descriptions for information on when commands can be executed.
Use the exit dbg command to end your debugging session. See for more information.
Dbg uses readline, a product of the Free Software Foundation, to read the dbg command lines. Readline lets you edit the command line as you enter it. By default, the line editing commands emulate an emacs-style interface.
The Kednos PL/I for UNIX kit includes the readline(3) manpage, containing full information on the readline commands. Once you have installed Kednos PL/I for UNIX, access the manpage as you would any other manpage, by typing man 3 readline.
You only need a few commands to get started using command line editing. The simplest are the left and right arrows, which let you move backward and forward by character. Readline maintains a history of the commands you entered, which you can access. Use your up and down arrow keys to move up and down through the history list.
Some of the most useful commands to start with are:
Once you become comfortable with these commands, you may want to learn how to use advanced commands, such as creating keyboard macros and transposing words. These commands are described in the readline(3) manpage.
You can customize readline by putting commands in an initialization file. Dbg uses the same initialization file as any other application that uses readline - the file specified by the INPUTRC variable, with a default of ~/ .inputrc. The following example shows a .inputrc file that contains a section for dbg that enables filename completion:
Once you create a .inputrc file containing a section for dbg (beginning with the line $if Dbg), you can use the additional commands you have defined. In the preceding example, you can now invoke filename completion on your dbg command lines by typing a partial filename and then a tab, to complete the filename.
The rest of this chapter describes each debugger command in detail, giving examples based on a PL/I program named lottery. The lottery program computes the number of possible combinations and permutations of n numbers that can be drawn from a field of m numbers.
The initial program listing is:
/* Lottery is the example program for the dbg chapter
/* Compile lottery.pli using the -g compiler option.
LOTTERY: PROCEDURE OPTIONS(MAIN);
DECLARE (M_VALUE, N_VALUE) FLOAT BIN(53);
PUT LIST('INVALID NUMBER ENTERED, TRY AGAIN!') SKIP;
PUT SKIP LIST('Number is too big, sorry!');
FACTORIAL: PROCEDURE (N) RETURNS (FLOAT BIN (53));
PERMUTATIONS: PROCEDURE (M,N) RETURNS (FLOAT BIN (53));
P = FACTORIAL(M) / FACTORIAL(M-N);
COMBINATIONS: PROCEDURE (M,N) RETURNS (FLOAT BIN (53));
P = PERMUTATIONS(M,N) / FACTORIAL(N);
PUT SKIP LIST ('Enter number of choices (>0): ');
PUT SKIP LIST ('Enter number of selections (>0): ');
P = PERMUTATIONS(M_VALUE,N_VALUE);
C = COMBINATIONS(M_VALUE,N_VALUE);
OUTPUT: PUT EDIT ('If order counts, chance is 1 in ', P)
You can issue debugger commands any time you see the debugger prompt (dbg). Type the command at the (dbg) prompt and press the RETURN key. To issue several commands on a line, separate the command strings with semicolons (;).
You can abbreviate debugger commands as long as the abbreviation specifies a unique command. You can type debugger commands and keywords in either upper- or lower-case. The commands clear, CLEAR, and Clear are equivalent, for example.
If you enter a carriage return at the dbg prompt, giving no other dbg command, dbg recalls your last dbg command line and reissues it.
A typical debugging session might consist of the following steps:
Additional commands let you record your entire session, record sequences of commands and play them back as a script, get help on the debugger commands, and access the Shell to execute Shell commands.
See . Debugger Command Summary shows all the debugger commands. The following sections give details on each of the dbg commands. Each section contains a short description of the command, references to related commands, restrictions if appropriate, a format diagram, descriptions of each element of the format, and examples. The commands are arranged alphabetically.
While in a dbg session, you can get brief help on the commands. See See HELP for more information.
Creates or lists aliases. An alias is a replacement name associated with an equivalence string. An equivalence string is a one-word dbg command or a quoted string containing a dbg command.
If you specify an existing replacement name, the new equivalence string replaces the existing equivalence string.
Aliases can recurse up to a maximum depth of 20 levels. See the examples section for an example of recursive alias definition.
Specifies the name to be replaced by the equivalence string. You can enclose the replacement name in quotation marks. It must be one word.
A dbg command. You can enclose the equivalence string in quotation marks. Quotation marks are required if the equivalence string contains embedded white space.
The following legal commands all create an alias called "stop" which does exactly what the break command does. Each alias definition overwrites the existing alias definition.
Aliases can recurse up to a maximum depth of 20 levels. In the following example, the "halt" command replaces the "quit" command, the "stop" command replaces the "halt" command, and finally the "exit" command replaces the "stop" command, and dbg executes the "exit" command.
Program terminated. Termination signal = 5
Every time an alias translation occurs, dbg checks to see if there is a match.
error: Circular alias detected.
You can still exit the debugger as follows:
Creates an audit file containing both user-input dbg commands and their output.
The audit command does not record program output. To record all input and output, making a transcript of the entire session, use the UNIX script(1) command. See the script(1) manpage for more information.
Omit all parameters to display a message showing audit status and listing the filename if auditing is on.
Turns auditing on and writes to the specified file. If you were already writing to an audit file, this command closes the previous audit file.
Use the break command to set or display breakpoints. Breakpoints are locations in your program where you want execution to stop so you can use dbg commands to step through the code line by line, show or set values of variables, and so on.
When the program stops at a breakpoint, dbg does the following:
You can then enter dbg commands at the prompt.
You can set multiple breakpoints. Use the break command to set each breakpoint. Dbg allows a maximum of 50 breakpoints.
If a single statement extends over more than one line, you can set a breakpoint only at the first line of the statement.
See See CLEAR BREAK for information on clearing breakpoints, and See CONTINUE for information on resuming execution from breakpoints.
You must initialize the program before you use the break command. See INITIALIZE
An absolute environment expression, as defined in See Terminology .
If you specify an absolute environment and do not specify a locator, dbg sets the breakpoint on the first executable line of code it encounters in the routine. If the routine contains no executable code, dbg displays a "line not found" message. If a breakpoint already exists on the first executable line, dbg displays a "breakpoint set" message. Otherwise dbg sets a breakpoint and displays a message containing the actual line number on which the break was set.
An expression that resolves to the line number or label of a statement. If the statement is not executable, dbg searches forward in your code for an executable line. If no executable lines exist after the line you specified, dbg displays a "line not found" message. If an executable line is found that has a breakpoint already set, dbg displays a "breakpoint set" message. Otherwise, dbg sets a breakpoint on the executable line and displays a message containing the actual line number on which the break was set
Use the count parameter to specify that execution should stop only after dbg encounters the breakpoint a certain number of times.The specified number must be an integer or an expression that resolves to an integer. The default is 1.
Note that every time dbg hits the breakpoint after it reaches the number specified by "count", execution will stop. In other words, if you specify count=25, execution stops the 25th time dbg encounters the breakpoint and every time thereafter. If you want to stop after another 25 iterations, reissue the break command to reset the count.
Specifies one or more dbg commands. Dbg executes the commands when program execution stops at the breakpoint.
You must use double quotation marks around the specified string if it is more than one word long.
The numbers in these examples are keyed to the descriptions following the examples.
(dbg) break 37 action="show n"
Breakpoint set at LOTTERY:PERMUTATIONS 37
:LOTTERY:PERMUTATIONS 37 action = "show n"
Current location is __start+0x0
(dbg) break 25 count=3 action=reg --
Breakpoint set at :LOTTERY:FACTORIAL 25 count = 3 action = "reg"
Breakpoint encountered at :LOTTERY:FACTORIAL 25
Set a breakpoint. DBG gives a success message showing the breakpoint, including the environment.
Attempt to set another breakpoint. Since the chosen line does not contain an executable statement, sets a breakpoint at the next line containing executable code.
Set a breakpoint at the absolute environment :lottery, which is the main routine of your program. Dbg sets the breakpoint at the first executable statement and informs you of the actual location.
Shows the format used to set a breakpoint at a label using an absolute environment. In this case, the breakpoint was already set.
Shows the format used to set a breakpoint at a line using an absolute environment. In this case, the breakpoint was already set.
The break command with no parameters displays all currently set breakpoints.
Set another breakpoint, this time specifying a count and action.
The program stops at the first breakpoint it encounters, the one set in step eight. Execution stops at the breakpoint the third time it is encountered. DBG executes the specified action, the dbg register command to show all the registers and their contents, and then waits for a command.
Use the clear break command to clear breakpoints that you set using the break command. See See BREAK for information on setting breakpoints.
You must initialize the program before you use the clear break command. See INITIALIZE
An absolute environment expression, as defined in See Terminology .
An expression that resolves to the line number or label of an executable statement for which you previously set a breakpoint using the break dbg command.
If you attempt to clear a break on a non-executable line, dbg searches forward in the routine and clears the first breakpoint it encounters. If the routine contains no breakpoints, a "breakpoint not set" message. Otherwise dbg sets a breakpoint and displays a message containing the actual line number on which the break was cleared.
Dbg displays a success message, including the actual environment and locator, after clearing the specified breakpoint(s):
These examples assume you have set the breaks specified in See BREAK .
Breakpoint cleared from :LOTTERY 20
Breakpoint cleared from :LOTTERY 72
error: Breakpoint not set at line 35
Breakpoint cleared from :LOTTERY:PERMUTATIONS 37
The continue command initiates program execution or continues execution of the program after it has stopped.
You must initialize the program before you use the continue command. See INITIALIZE
An expression that resolves to the line number or label of an executable statement. The keyword at is required for this clause.
In the following example, the break command sets a breakpoint. The first continue command starts program execution. Execution stops at the breakpoint, and the user executes some dbg commands. The second continue command resumes execution until the next breakpoint.
Breakpoint encountered at :LOTTERY 37
Enter number of choices (>0) 8
Enter number of selections (>0) 2
Use the describe command to show attribute information about a symbol. This information includes the attributes you specified in the declaration statement, plus all the PL/I defaults applied to the symbol.
The name of a user-defined program symbol. You can describe any type of symbol, including arrays and structures. You cannot describe a single array element or structure member.
The following examples use the describe command to show attribute information for various types of PL/I symbols.
M float binary(53,0) aligned parameter 8 bytes at 0x48 bytes
35: 3 LAST CHARACTER(80) VARYING,
36: 3 FIRST CHARACTER(80) VARYING,
37: 2 SALARY FIXED DECIMAL(7,2);
39: PAYROLL.NAME.LAST = INPUT_BUFFER.NAME.LAST;
1 PAYROLL automatic 180 bytes at 0x38 bytes
2 NAME member 164 bytes at 0x0 bytes
3 LAST character(80) varying unaligned member 82 bytes at 0x0 bytes
3 FIRST character(80) varying unaligned member 82 bytes at 0x52 bytes
2 SALARY fixed decimal(7,2) aligned member 16 bytes at 0xa4 bytes
12: DECLARE MONTHS (12) CHARACTER (9) VARYING
13: INITIAL('January','February','March','April',
14: 'May','June','July','August',
15: 'September','October','November',
MONTHS (1:12) character(9) varying unaligned automatic
initialized 144 bytes at 0x70 bytes
Breakpoint encountered at :AGGREGATES:SUBR:60
50: DECLARE 1 RES_DATA BASED (RPTR),
58: ALLOCATE RES_DATA SET(RPTR);
60: RES_DATA.HOTEL_CODE = 'XYZ';
1 RES_DATA based() 44 bytes at 0xffffffffffffff50 bytes
2 DATE character(8) unaligned member 8 bytes at 0x0 bytes
2 HOTEL character(3) unaligned member 3 bytes at 0x8 bytes
2 PARTY_NAME member 30 bytes at 0xb bytes
3 LAST character(20) unaligned member 20 bytes at 0xb bytes
3 FST character(10) unaligned member 10 bytes at 0x1f bytes
2 STAY fixed binary(7,0) aligned member 2 bytes at 0x2a bytes
Use the directory command to display or add to the list of directories searched when dbg opens a source file for listing. (See See LIST for more information about listing source file lines.)
Use the down command to navigate downward (toward the more recent frame) through your dynamic frames. (See for information on navigating upward through dynamic frames. Contrast with See ENVIRONMENT , which navigates through your lexical environment.)
You must initialize the program before you use the down command. See INITIALIZE
Use this optional parameter to specify how many frames dbg should move down through. The number must be an integer.
Use the environment command to set your working environment. The environment command affects the scope in which dbg evaluates break, clear, describe, list, set, and show commands. Note that the environment command has no effect on the breakpoint or program execution. If you issue a continue or step command, execution resumes relative to the established breakpoint environment.
Use either an absolute or relative environment specifier to identify the procedure block that you want to become your working environment. See the entry on environment in See Terminology for more information.
The following example is keyed to the list that follows it.
Breakpoint encountered at :LOTTERY:COMBINATIONS:49
error: Symbol N not within current scope or not properly qualified.
(dbg) environment permutations
Current location is :LOTTERY:FACTORIAL:26
Code execution has stopped at a breakpoint. The environment command, with no parameters, shows the current environment.
The environment command, followed by an absolute environment specifier, sets the scope to LOTTERY.
You try to show the symbol N within the PERMUTATIONS subroutine. Although your breakpoint is within that subroutine, your environment is currently LOTTERY and so you cannot show the symbol.
The environment command with the @all parameter shows all the top level environments that you can specify.
The environment command used with an absolute environment specifier sets the environment to the PERMUTATIONS subroutine.
You can now show the symbol N within the current environment.
The environment command with the @break parameter resets environment to the scope of the breakpoint at which execution stopped.
A relative environment specifier navigates out one level.
The step command steps one line from the breakpoint, even though the environment is different.
The exit dbg command terminates the child debugger process containing your program, ends the debug session and exits the debugger. See See INITIALIZE for more information on the creation of the child debugger process.
The initialize command creates a child debugger process containing your program, and establishes the child process as a debugee of the debugger. You must initialize the program before you use any of the following commands:
If you have an existing child process and execute the initialize command, dbg kills the existing child process and creates a new one. This establishes a start address at the beginning of the new child process.
Executing the initialize command does not affect established breakpoints. To remove breakpoints, use the clear break command. For more information, see See CLEAR BREAK .
note: Child process 18249 created
(dbg) initialize 30 5 >results
Use the list command to display a sequence of source program lines.
If you specify the list command without arguments, dbg displays ten lines of source code to either side of the current line, or all lines to the beginning and/or end of the current scope, if there are fewer than ten lines.
Dbg lists twenty-one lines of source code at a time and then displays a prompt.
The line number or label of an executable statement.
To display the 21 lines containing one specific line, use the list command followed by the source line number.
To display specific lines, use the list command followed by the source line number of the first line to be listed, followed by a the source line number of the last source line you want to display. You can list up to 32767 lines of source code.
To display a single line, use the list command followed by the source line number, a comma, and the source line number again.
By default, the display starts at the current source line, which dbg tracks internally. The default range of the listing is 10 lines above and below the current statement for a total of 21 lines. For example:
Breakpoint encountered at :LOTTERY:FACTORIAL:50
43:COMBINATIONS: PROCEDURE (M,N) RETURNS (FLOAT BIN (53));
49: P = PERMUTATIONS(M,N) / FACTORIAL(N);
58: DO WHILE (M_VALUE <= 0.0);
59: PUT SKIP LIST ('Enter number of choices (>0): ');
60: GET EDIT (M_VALUE) (F(12));
To list specific lines, specify the starting and ending lines on the dbg command line. The following example lists five lines of the program starting at line 8:
8: DECLARE (TRUNC,ONSOURCE) BUILTIN;
9: DECLARE (M_VALUE, N_VALUE) FLOAT BIN(53);
10: DECLARE (C,P) FLOAT BIN(53);
To list one line, specify the same line number as the starting and ending lines, as follows:
8: DECLARE (TRUNC,ONSOURCE) BUILTIN;
2: /* Lottery is the example program for the dbg chapter
19: PUT SKIP LIST ('Number is too big, sorry!');
Use the list @all command to list your entire source program.
2: /* Lottery is the example program for the dbg chapter
4: /* Compile lottery.pli using the -g compiler option.
6: LOTTERY: PROCEDURE OPTIONS(MAIN);
71: PUT EDIT ('If order counts, chance is 1 in ', P)
Executes the commands in a playback file. You can create a playback file either by editing a file using your preferred editor or by using the dbg record command.
See See RECORD for information on recording debugger commands.
Turns command recording on and off. Command recording writes commands given to the dbg debugger to the specified file.
See See PLAYBACK for information on playing back recorded commands, and See Creating .dbginit Files for information on using files containing recorded commands as initialization files.
If you execute the record command with no parameters, dbg displays a status message telling you whether recording is currently on or off.
Use the set command to change the value of a variable. The set command works like a PL/I assignment statement.
You must initialize the program before you use the set command. See INITIALIZE
The fully-qualified name of the variable. You can set any variable that you can access. See See Accessing Data for more information.
A variable or constant that resolves to, or can be converted to, a value of the same data type as the variable being set. You can specify an element of an array by fully qualifying your specification, enclosing it in square brackets, providing the data type matches. Enclose strings in double quotation marks (for example, "string").
In the following examples, the set command assigns new values to different variables. The debugger validates that you have specified a value consistent with the data type and dimensional constraints of the variable.
Lets you access the shell defined by your SHELL environment variable (the default is /bin/sh, the Bourne shell) and execute shell commands.
The show command displays the value of a variable. You can show scalar variables, subscripted array elements, and structure members. Dbg formats the data according to the compiler-generated data type of the specified variable.
When you show a character string containing non-printable characters, special characters or control characters, dbg displays them in octal with the following exceptions:
You must initialize the program before you use the show command. See INITIALIZE
A string containing a valid reference to a variable in the current scope. You must properly qualify structure variable references, and include an explicit pointer reference to explicitly based variables.
The signal command displays the current signal values or lets you change the values. If you change a signal value it remains changed for the duration of your debugging session or until you change it again. Intervening initialize statements do not restore the default signal values.
When a program executes under debugger control, all signals pass to the debugger. The following steps occur:
If you issue the signal command with no parameters, dbg displays a table of all the signals by number and name and the currently set values for the STOP, IGNORE and REPORT options.
One of the signals listed in the table. You can specify either the signal number or the signal name. If you specify a signal identifier, you must specify one or more of the options.
Toggles the STOP option. If STOP is true, the child process stops and the debugger reports the signal and displays the (dbg) prompt. If STOP is false, the child process continues.
Toggles the IGNORE option. If IGNORE is true, the debugger does not pass the signal to the child process. If IGNORE is false, the debugger gives the signal to the child process, which can then handle it.
Toggles the REPORT option. If REPORT is true, the debugger reports the signal to you. If REPORT is false, the debugger does not report that the signal occurred.
You can specify any combination of values for the options. However, if STOP is true, the debugger always reports the signal to you before displaying the (dbg) prompt, even if REPORT is false.
The following example displays the current signal values and resets the values for the SIGFPE condition so that it is not passed to the child process. When the SIGFPE signal occurs, the user program stops. The debugger displays the (dbg) prompt. The user can then look at data, modify a few values, and continue execution at a point before the signal occurred. The signal will not be passed to the child process.
4 T F T Illegal instruction SIGILL
5 T T T Trace/BPT trap SIGTRAP
8 T F T Floating point exception SIGFPE
11 T F T Segmentation fault SIGSEGV
31 T F T User defined signal 2 SIGUSR2
8 T T T Floating point exception SIGFPE
program stopped: Floating point exception
A step operation executes the program one source line at a time. After dbg executes the specified number of source lines, it displays the following message:
where env is the current environment and m is the line number at the beginning of the statement where execution stopped. Use the continue or step command to resume program execution.
Step always steps to the next executable line of PL/I code. If the source line calls a routine, the step operation stops at the first executable line of the routine, if it is in PL/I. If the routine is in another language, the step operation stops at the first executable line of PL/I code after the routine.
You must initialize the program before you use the step command. See INITIALIZE
The step debugger command lets you execute a specified number of source program lines. When you type several statements on a single line, you cannot step through the statements individually. To step through statements individually, place them on separate source lines.
The following example continues the previous example, where the program is about to call the combinations routine:
[combinations:40x4005dc] p = permutations(m,n) / factorial(n);
stopped at [combinations:42 ,0x4005dc] p = permutations(m,n) / factorial(n);
37 combinations: procedure (m,n) returns (float bin (53));
>* 42 p = permutations(m,n) / factorial(n);
If you specify an integer argument, dbg performs the specified number of step operations.
Use the up command to navigate upward (toward the less recent frames) through your dynamic frames. (See See DOWN for information on navigating downward through dynamic frames. Contrast with See ENVIRONMENT , which navigates through your lexical environment.)
You must initialize the program before you use the up command. See INITIALIZE
Use this optional parameter to specify how many frames dbg should move up through. The number must be an integer.
Use the walkback command to display the frames on the call stack.
You must initialize the program before you use the walkback command. See INITIALIZE
Use this optional parameter to specify how many frames of the call stack to display, going from the most current frame back. The number must be an integer.
This chapter discusses the use of files for input and output (I/O) in PL/I and describes the aspects of the Digital UNIX operating system that relate to PL/I I/O. The chapter includes the following topics:
See , See , See , and See 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.
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 See , " See 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 See .
Declaring, opening, and closing files are discussed in more detail in the Kednos PL/I for UNIX Reference Manual.
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 Digital UNIX system services.
Note that, although you can call Digital UNIX system services directly from a PL/I program, it is not normally necessary to do so. A PL/I program executed on the Digital UNIX operating system has full access to I/O capabilities through the following language elements:
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:
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 See 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.
When you specify the TITLE option on an OPEN statement, you can include all or part of a Digital UNIX 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 Digital UNIX system. When accessing the file OUTFILE, the program will be written to the file /usr/payroll/january.
TITLE ('/usr/payroll/january');
The following is an example of using a variable to specify the title:
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>.
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:
OPEN FILE (INFILE) RECORD OUTPUT;
The local file specification created on the Digital UNIX system is INFILE.
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:
The system provides every process with a default set of standard name assignments, as listed in See . 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.
The default files associated with the GET and PUT statements, SYSIN and SYSPRINT, are defined by PL/I as follows:
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".
The following examples enumerate the steps in completing a file specification. All examples assume that the following environment variable assignments are in effect:
They also assume the following current default device and directory:
DECLARE STATES FILE RECORD OUTPUT;
OPEN FILE(STATES) TITLE ('/usr/STATE.DATA/NEVADA');
Final Specification: /usr/STATE.DATA/NEVADA
DECLARE STATES FILE RECORD OUTPUT;
Final Specification: /usr/users/malcolm/NEBRASKA
Kednos PL/I for UNIX 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:
In the IBM dialect only, the following ON conditions are also used:
See the Kednos PL/I for UNIX 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)
The ON statement provides a default title for the file INFILE.
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:
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 Digital UNIX 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 Digital UNIX 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.
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.
/* Check for a record not found */
IF ONCODE() = RMS$_RNF /* if record not found */
PUT SKIP EDIT(STATENAME,'Not found.')
PUT SKIP EDIT('Record already exists for', STATENAME)
In this example, the ON-unit declares symbolic names for two specific status values returned by ONCODE:
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).
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 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.
File Organizations and Input/Output
Record I/O is performed by the READ, WRITE, DELETE, and REWRITE statements; each statement processes an entire record. In stream I/O, more than one line or record can be processed by a single statement. In addition, some forms of record I/O allow you to access records in the file by record number or by a key field contained in the record.
This chapter includes the following topics:
For position information and descriptions of the READ, WRITE, DELETE, and REWRITE statements, see the Kednos PL/I for UNIX Reference Manual.
The UNIX file system supports only stream files; however, the PL/I run-time system simulates the behavior of relative files by imposing restrictions on the access of files having these organizations.
One of the consequences of this is that (unlike VAX PL/I) the Kednos PL/I for UNIX run-time system relies on the file organization and access method specified in the DECLARE, OPEN, and READ statements of your PL/I program to determine the file organization. Thus it is up to the programmer to ensure that the correct file organization is specified in the input/output statements of the PL/I program; otherwise, results are unpredictable. To avoid problems when specifying the file, always open a file with the same file attributes.
Kednos PL/I for UNIX does not support some file organizations or combinations of file organizations and access methods due to limitations of the file system. These are:
In a stream file, characters are ordered one after the other, in the order in which they are written. New characters can be added only at the end of an existing file. Stream files are discussed in more detail in See Stream Files .
A relative file contains a specified number of fixed-length cells, numbered from 1 to n, where n is a user-specified maximum. Any record written to the file is written to a specific numbered cell; the cell number is also the relative record number of the record in the file.
Normally, the records in a relative file have an implied numeric data field, for example, an account number or employee number, which corresponds to the cell in which the record will be placed. When you read or write a record in a relatively organized file, you specify the record by its relative record number. Relative files are discussed in more detail in See Relative Files .
In standard PL/I, you can specify one of the following sets of attributes to define the way a program is going to access the records in a file:
In PL/I, there is an additional way to access a file. Specify the ENVIRONMENT option RECORD_ID_ACCESS to indicate that records can be read or written randomly with the file address of the record.
Although you cannot change the organization of the records in a file after you have created the file, you can select a different type of access mode for reading or processing the file. You can also access a file using more than one access mode; for example, you can read a record in an indexed file by specifying a key, and then read records sequentially beginning at that position in the file.
You can use sequential access with any type of file organization except stream access to a variable length record file. When you access a file sequentially, each read or write operation reads or writes the next record in the file. As you process a file sequentially, PL/I keeps track of the current record (that is, the record just read or written) and the next record (the record that follows the record just read or written).
When you access a relative file sequentially, the records are read or written in order by relative record number. In a file in which not all cells contain records, sequential input operations involve only cells that contain data records.
When you access a file randomly by key, each I/O request must contain the KEY or KEYFROM option.For a relative file, the key is the relative record number of the record to be accessed.
By default, a READ statement accesses a record based on an exact match of the key specified. In PL/I, you have the option of requesting that the READ statement match any record with an equal or greater key value, or any record with a greater key value.
When you access a file for random and sequential access, you can read records sequentially or randomly. For example, you can use a keyed READ statement to position the file at a specified record and then read or process records sequentially from that position.
You can use a record identification to access records in any type of disk file (except stream files with variable length records) that is opened for any type of access. To access records by record identification:
DECLARE LIBFILE FILE ENVIRONMENT(RECORD_ID_ACCESS),
READ FILE(LIBFILE) KEY(MODULE_NAME) INTO(INREC)
OPTIONS(RECORD_ID_TO(SAVED_ID));
The READ statement in this example returns the value of the record identification associated with the record whose key is indicated by the variable MODULE_NAME. The value of SAVED_ID may subsequently be used in a REWRITE or DELETE statement to modify the record.
In a file containing fixed-length records, all records have the same length. Thus, when you create a file with fixed-length records, you must specify the length of each record in the file; this size cannot be changed after the file is created.
To create a file with fixed-length records in a PL/I program, use the FIXED_LENGTH_RECORDS option of the ENVIRONMENT attribute. The MAXIMUM_RECORD_SIZE option specifies the size of each record. For example:
DECLARE FIXED_FILE FILE RECORD KEYED OUTPUT
ENVIRONMENT(FIXED_LENGTH_RECORDS,
When the file FIXED_FILE is opened, its record format is established as having fixed-length 80-character records.
When a file that has fixed-length records is processed by READ and WRITE statements, the file system checks the length of the variable specified in the INTO or FROM option to see if it is the same as the length of the records in the file. If not, the ERROR condition is signaled.
PL/I supports only record I/O on variable-length record files with relative file organizations. In a file containing variable-length records, each record can have a different size. PL/I places a count field at the beginning of each record to indicate its size; however, this count field is not considered a part of the data record, nor is the length of the count field included in the size of the record.
Variable length is the default record format for PL/I files. Use the MAXIMUM_RECORD_SIZE option to specify the maximum length that any record can have. For example:
DECLARE VAR_FILE FILE RECORD OUTPUT
ENVIRONMENT(MAXIMUM_RECORD_SIZE(80));
This declaration indicates that the file VAR_FILE has variable-length records, each with a maximum length of 80 characters.
When a file that has variable-length records is processed by READ statements, the file system checks the length of the variable specified in the INTO option to see if it is large enough to hold the record being read. If not, the ERROR condition is signaled.
Stream input and output are performed by the statements GET and PUT, respectively. Both statements can perform either list-directed or edit-directed operations.
A file has the STREAM attribute if it meets any of the following conditions:
Files declared with the STREAM attribute have the following characteristics:
Stream files contain only ASCII data. The ASCII format used to represent program data in a stream output file differs depending on the attributes given to the file. For example, the representation of character strings differs depending on the presence or absence of the PRINT attribute in the file declaration.
Unlike VAX VMS, an existing stream file cannot be reopened and accessed by the READ and WRITE statements. Stream files are true byte streams on UNIX. If READ and WRITE open a file implicitly, the attributes RECORD INPUT SEQUENTIAL and RECORD OUTPUT SEQUENTIAL are implied, respectively. These attributes are not compatible with an existing disk file created with the STREAM and OUTPUT attributes, and these operations will produce unpredictable results.
Whenever a PL/I program opens a file with the SEQUENTIAL OUTPUT attributes, PL/I creates a new stream file. By default, records are 510-byte, variable-length records. If record I/O is done on this file, you must specify the FIXED_LENGTH_RECORDS attribute (or the IBM dialect equivalent attribute). 2
In PL/I, you can open a file with the APPEND option of ENVIRONMENT to add new records to the end of an existing sequential file. This overrides the default action of PL/I, which is to overwrite an existing file when the existing file is opened for output. For example:
OPEN FILE (BIRD_FILE) OUTPUT SEQUENTIAL
ENVIRONMENT (APPEND, FIXED_LENGTH_RECORDS);
WRITE FILE (BIRD_FILE) FROM (NEWDATA);
This OPEN statement opens the file BIRD_FILE and positions it at its current end-of-file. The WRITE statement adds a new record at the end of the file.
The ENVIRONMENT option SUPERSEDE lets you create a new version of a file each time you open it, simultaneously deleting an existing version. This is the default behavior for output files in PL/I. For example, the following OPEN statement opens the file CONTROL.DAT, deleting any pre-existing versions of the file.
The relative file organization is suitable for files with data that can be arranged serially and be uniquely identified by an integer value, for example, a part number or an employee identification number. Within the file, records are written into cells that are numbered; there is a one-to-one correspondence between the cell number and the integer value associated with the data in the record. This number, called the relative record number, is the key by which records are accessed.
See . Relative File illustrates a relative file in which not all cells contain records. The first record written to the file was relative record number 1 (which may have been data for a part numbered 1 or an employee whose number is 1, for example). The second record written was relative record number 2. The third record written was relative record number 4; thus cell number 3 does not contain a record.
In PL/I, relative file organization is the default organization for files that are opened with the KEYED attribute. Thus, when a WRITE statement is directed to a file with the KEYED and OUTPUT attributes, PL/I creates a relative file.
When you initially create a relative file in a PL/I program, consider using the ENVIRONMENT option MAXIMUM_RECORD_SIZE (or the IBM dialect RECSIZE option) to maximize the efficiency of I/O operations on the file.
When you specify the length of the records in a file, the value you specify is used in the MAXIMUM_RECORD_SIZE option (or the IBM dialect RECSIZE option) to calculate a cell size. It uses the following formulas to calculate the size:
When you select a record size for a relative file, try to specify a size that is no greater than the largest record that will be written. Otherwise, any unused space in each cell will be wasted. If you do not specify a maximum record size for either fixed- or variable-length records, PL/I uses the default length of 480 bytes.
You can create a relative file from any existing file that is suitable for relative file organization. See . Creating a Relative File illustrates copying a sequential file with fixed-length records into a relative file.
COPY_TO_RELATIVE: PROCEDURE OPTIONS(MAIN);
%INCLUDE PARTLIST; /* Declaration of PARTLIST */
DECLARE OLDFILE FILE INPUT RECORD SEQUENTIAL ENVIRONMENT(
DECLARE RECORD_NUMBER FIXED BINARY(15);
PARTS FILE OUTPUT KEYED RECORD ENVIRONMENT(
CLOSE FILE(OLDFILE), FILE(PARTS);
OPEN FILE(OLDFILE), FILE(PARTS);
READ FILE(OLDFILE) INTO(PARTLIST); Õ
RECORD_NUMBER = PARTLIST.NUMBER;
WRITE FILE(PARTS) FROM(PARTLIST)
KEYFROM(RECORD_NUMBER);
The following notes are keyed to See . Creating a Relative File :
The structure PARTLIST describes the layout of the records in the file. The records will be ordered in the relative file according to the field PARTLIST.NUMBER.
The relative file PARTS is declared with fixed-length, 36-byte records.
The file OLDFILE is the sequential file containing the records to be copied to a relative file. When the end-of-file is reached, the file is closed and the STOP statement terminates the program.
As each record is read into the structure PARTLIST, the value of NUMBER is copied to the fixed binary integer RECORD_NUMBER. The part number is maintained in each record in its character-string form.
Each WRITE statement copies the record to the output file, specifying the value of the part number as a relative record number.
Records in this file can subsequently be accessed either sequentially or by part number. To access a record by part number, you specify the number as a key. For example:
GET LIST(INPUT_NUMBER) OPTIONS(PROMPT('Part? '));
READ FILE(PARTS) INTO(PARTLIST) KEY(INPUT_NUMBER);
Here, the value entered in response to the GET statement is used as a key value to access a record in the file.
In See . Creating a Relative File , the file PARTS is opened with the KEYED and OUTPUT attributes. When this program is executed, the amount of space allocated for the file PARTS depends on the relative record numbers of the records that are written to the file. For example, if the largest record number specified for a record is 200, only enough space for 200 records is allocated.
To add or modify records in a relative file, open the file with the DIRECT and UPDATE attributes. For example, a procedure that updates the file PARTS when new stock is ordered might contain the following:
ORDER_PARTS: PROCEDURE(ORDERED_AMOUNT,PART_NUMBER);
%INCLUDE PARTLIST; /* Declaration of PART.LIST */
DECLARE (ORDERED_AMOUNT,PART_NUMBER) FIXED BIN(15);
DECLARE PARTS FILE RECORD DIRECT UPDATE;
READ FILE(PARTS) INTO(PARTLIST)
PARTLIST.ON_ORDER = PARTLIST.ON_ORDER +
REWRITE FILE(PARTS) FROM(PARTLIST);
In this example, the procedure ORDER_PARTS receives as its parameters the order quantity and the part number. It reads the record associated with the part number from the file, adds the order quantity to the existing quantity, and rewrites the record.
You can access a relative file sequentially as well as by key. When you access the file sequentially, each READ statement returns the record in the next cell that contains a record, skipping empty cells. The following example illustrates reading a relative file sequentially:
PRINT_PART: PROCEDURE OPTIONS(MAIN);
%INCLUDE PARTLIST; /* Declaration of PARTLIST */
DECLARE EOF BIT(1) ALIGNED INIT('0'B);
OPEN FILE(PARTS) INPUT SEQUENTIAL RECORD KEYED;
READ FILE(PARTS) INTO(PARTLIST) KEYTO(CHECK_NUM);
PUT SKIP EDIT(PARTLIST.NAME, /* Output data */
PUT SKIP EDIT('Relative record number',CHECK_NUM,
'Part number:',PARTLIST.NUMBER)
(X(10),A,X,F(5),A,X,A); /* Output
READ FILE(PARTS) INTO(PARTLIST) KEYTO(CHECK_NUM);
This procedure outputs the contents of the file PARTS, listing each field in the data records described by PARTLIST. The READ statement specifies the KEYTO option; the procedure outputs the value returned to the variable CHECK_NUM.
PL/I signals the KEY condition when errors occur during the processing of record numbers for relative files. For example, it signals the KEY condition when the number of a record that already exists is specified in a KEYFROM option in a WRITE statement.
The following sample ON-unit shows how to detect whether a record already exists in a relative file.
/* Check for duplicate records */
IF ONCODE() = RMS$_REX /* If duplicate */
PARTLIST.NUMBER,'exists. Reenter')
GET LIST(PARTLIST.NUMBER); /* Get new value */
GOTO GET_DATA; /* Go get other data */
In this example, the ON-unit gets symbolic names for a specific status value returned by ONCODE, from RMSDEF, a system include file provided for compatibility with VAX PL/I. The value RMS$_REX indicates that a record already exists.
In an ON-unit for the KEY condition for a relative file, ONCODE can also return the values associated with the following status codes:
The symbolic names for these status codes are included from the system include file rmsdef.in, from /usr/lib/pl1/include.
Options of the ENVIRONMENT Attribute
The options of the ENVIRONMENT attribute provided by Kednos PL/I for UNIX let you do the following:
This chapter presents an overview of the environment options and information on how to specify them, and gives a description of each option. The descriptions of the environment options are arranged in alphabetic order. The chapter concludes with a discussion of the environment options designed for file protection, file sharing, and I/O optimization.
All environment options can be specified in the declaration of a file constant or, in sthe dec and ansi dialects, in an OPEN statement . Certain options can also be specified in a CLOSE statement.
If you declare a file constant or file variable explicitly or implicitly as EXTERNAL, you must use identical attributes, including ENVIRONMENT options, in all blocks that declare the file.
Environment options fall into the following categories, based on whether they require an argument and, if so, what type of argument is required:
All arguments must be specified in parentheses following the name of the environment option. For example:
Considerations for specifying each type of argument are given in the following sections.
You can use integer expressions and character expressions in expression arguments for environment options. The ways you can specify these arguments differ for DECLARE statements and for OPEN and CLOSE statements.
In a DECLARE statement, you must specify a constant expression. Integer expressions can consist of integer constants, constant identifiers defined by %REPLACE statements, and the operators +, -, *, and /. You must specify character expressions using character-string constants.
In an OPEN or a CLOSE statement, you can specify the argument using constant expressions or variable references, or expressions or variable references of the required type.
If a single variable is specified for an expression, its data type must be convertible to the data type of the option. All integer constants and expressions are converted to FIXED BINARY(31).
You can specify all character-string expressions using varying or nonvarying strings. The description of the option specifies the maximum length of a string argument.
For any of these options, PL/I applies a default value if no option is specified for the file when it is opened.
Options that are specified by variable references cannot be specified in a DECLARE statement. The data type of the variable must match the data type described in the option description.
For an option that can be enabled or disabled, you can specify a Boolean constant, that is, '1'B (to enable) or '0'B (to disable) the option in a DECLARE statement. In an OPEN or CLOSE statement, you can specify a Boolean constant, variable, or expression.
An option that is specified without a value is interpreted as enabled. For example, the following are equivalent:
ENVIRONMENT(FIXED_LENGTH_RECORDS)
ENVIRONMENT(FIXED_LENGTH_RECORDS('1'B))
For arguments of this type, PL/I converts any non-Boolean value to BIT(1) ALIGNED.
Many ENVIRONMENT options specify values that can be set only when a file is created. For example, the length of records in a file with fixed-length records is set when the file is created and cannot be changed thereafter. When these options are specified, they determine the option for the file if the OPEN option creates the file. Because the options are not stored with the file, they must be given for each opening of a file. The results are unpredictable if the options given do not match with those existing for the file.
Conflicting or invalid options or values for options can be detected during compilation or at run time. At compile time, the compiler issues a diagnostic message to indicate the error.
At run time, the UNDEFINEDFILE condition is signaled if conflicting options are in effect or if conflicting values are specified for the same option. For example, if the MAXIMUM_RECORD_SIZE option is specified in the DECLARE and OPEN statements for a given file and if the options specify different values, UNDEFINEDFILE is signaled.
For run-time errors, an ON-unit can reference the ONCODE built-in function to determine the specific error, if desired. If no ON-unit exists for the UNDEFINEDFILE condition, the PL/I run-time system displays an error message describing the error that occurred.
The options to the PL/I ENVIRONMENT attribute for the DEC and ANSI dialects are summarized in alphabetic order in See . Summary of DEC and ANSI Dialect ENVIRONMENT Options .The ENVIRONMENT options for the IBM dialect are summarized in See . Description of Columns in Table 6-2 describes the columns in See . Summary of DEC and ANSI Dialect ENVIRONMENT Options .
The sections following these tables describe the Kednos PL/I for UNIX environment options in detail.
Gives the name of the ENVIRONMENT option and its argument, if any. An option that does not show an argument can be specified with a Boolean argument. |
|
Indicates when the option is meaningful. The possible items in this column are: |
|
Indicates whether the option is valid for stream or record files. |
|
Indicates the default value, if any, when the option is not specified for a file. |
|
Specifies a file with fixed-length records of a maximum record size. |
|||||
Defines the type of file access allowed to members of the owner's group. |
Current process default 3 |
||||
Varies 4 |
|||||
Specifies the type of file access allowed the owner of the file. |
Current process default See See umask(1) |
||||
Indicates that records will be accessed by internal file system identification. |
|||||
Enabled 5 |
|||||
Specifies a temporary file which is deleted when the process terminates. |
|||||
Specifies the type of file access allowed to general system users. |
Current process default See See umask(1) |
Specifies the size of a block when writing to a buffered file. |
|||||
Specifies that records in the file are placed in physical sequence. |
|||||
Specifies a file with fixed-length records of a maximum record size. These are all equivalent to F; the B and S portions are ignored. |
|||||
Varies 6 |
|||||
Specifies that varying character strings are read/written using the entire storage of the variable. |
|||||
Specifies a file with variable-length records with a maximum record size. These are all equivalent to V; the B and S portions are ignored. |
Some environment options are accepted but ignored by the Kednos PL/I for UNIX compiler, for compatibility with other implementations of PL/I. See . ENVIRONMENT Options That Are Ignored lists these options:
The APPEND option opens an existing file for output so that new records are added following the current end-of-file. The format of this option is as follows:
Use the APPEND option to open a file and position it at the end-of-file. For example, to add records at the end of a file, you can open the file as follows:
DECLARE LISTFILE FILE SEQUENTIAL OUTPUT;
OPEN FILE(LISTFILE) ENVIRONMENT(APPEND);
This OPEN statement opens the file LISTFILE. The file is positioned at its current end-of-file.
The BLKSIZE option sets the size of a buffer in BUFFERED file. This option is valid only with BUFFERED files and is ignored otherwise. The format of this option is:
A positive integer or a fixed binary(31) static variable specifying the maximum block size for the file. Valid values range from the current record size to 32767 bytes. Note that the actual length of a variable-length record includes the four control bytes containing length information.
Although PL/I provides a default of the current record size, this default will not give you any of the advantages of buffered I/O. To improve performance when using buffers to write to a file, specify a block-size that is a multiple of the record size plus any control bytes.
The DEFAULT_FILE_NAME option specifies default file name for a file. Its format is:
The next example shows how to open the file /usr/users/tim/employee.dat:
OPEN FILE (INFILE) INPUT TITLE('employee')
ENVIRONMENT(DEFAULT_FILE_NAME('/usr/users/tim/*.dat'));
The following example shows how to open the file /tmp/workfile:
The DELETE option specifies that the file is to be deleted when it is closed. The format of this option is:
The F, FB, FS, and FSB options all equate to the dec/ansi dialect FIXED_LENGTH_RECORDS option. Blocking and spanning are unsupported. The format of this option is:
See See FIXED_LENGTH_RECORDS Option for more information.
When the FILE_ID option is specified in the opening of an existing file, PL/I uses the value specified in the FILE_ID option to locate the file. The format of the option is:
Specifies the name of the 6-element array variable containing the file identification. See See FILE_ID_TO Option for information on obtaining the file identification when you create a file.
The variable must be declared as (6) FIXED BINARY(31) and must be connected.
Use the FILE_ID_TO option to obtain the file identification when you create a file. Its format is:
Specifies the name of the 6-element array variable. PL/I returns the file identification of the created file to this variable.
You must declare the variable as (6) FIXED BINARY(31), and it must be connected.
This option allows you to save the internal file identification of a file created with the TEMPORARY option so that you can access the file later and eventually delete it.
For an example of the FILE_ID_TO and FILE_ID options used for temporary files, see the following description of the TEMPORARY option.
The FIXED_LENGTH_RECORDS option specifies that all records in the file are to be of the same length. If you do not specify this option when you create a file, the records in the file will be variable length by default. The format of this option is:
When the FIXED_LENGTH_RECORDS option is specified for the creation of a file, the size of each record can be specified with the MAXIMUM_RECORD_SIZE option. If MAXIMUM_RECORD_SIZE is not specified, PL/I provides a default length of 512 bytes for stream files and a default length of 480 bytes for relative files. There is no default for indexed files.
The GROUP_PROTECTION option defines the type of access to be permitted to the file by other users in the owner's group (also see id(1)). The format of this option is:
Is a 1- to 4-character string expression indicating the access privileges to be granted to users in the owner's group. The expression can contain any of the following letters to indicate the access allowed:
w -- Write/delete access is allowed.
x -- Execute access is allowed.
Letters can be repeated, but the maximum length of the string is 4 characters. The character-expression string is case insensitive; "W" and "w" are equivalent.
For compatibility with OpenVMS implementations of PL/I, you can use "d" as a synonym for "w", and "e" as a synonym for "x". All other characters are invalid. If any other character is present in the string, the UNDEFINEDFILE condition is signaled.
The MAXIMUM_RECORD_SIZE option specifies the largest size that records in a file can have. The actual meaning of this option varies according to the type of file:
Is a numeric expression with values in the range 1 to 32,767. A value of 0 indicates that there is no user-defined limit to the size of records.
If the value is out of range, the UNDEFINEDFILE condition is signaled.
The MAXIMUM_RECORD_SIZE option is meaningful when a file is created and when it is opened. If the specified opened size does not match the specified created size, the results are undefined. If not specified, PL/I provides a default length based on the file organization and record format as follows:
The OWNER_PROTECTION option defines the type of access to be permitted to the file by the file's owner and by other users with the same user identification (UID). Refer to id(2) for more information. The format of this option is:
Is a 1- to 4-character string expression indicating the access privileges to be granted to the file's owner. The character-string expression can contain any of the following letters to indicate the access allowed:
w -- Write/delete access is allowed.
x -- Execute access is allowed.
Letters can be repeated, but the maximum length of the string is 4 characters. The character-expression string is case insensitive; "W" and "w" are equivalent.
For compatibility with OpenVMS implementations of PL/I, you can use "d" as a synonym for "w", and "e" as a synonym for "x". All other characters are invalid. If any other character is present in the string, the UNDEFINEDFILE condition is signaled.
The RECORD_ID_ACCESS option indicates that the records in a file will be accessed randomly, using the internal identification of the records. The format of this option is:
You must open a file with this option to use the RECORD_ID_TO and RECORD_ID options of the record I/O statements. See See , See Input/Output Statement Options for more information.
When a file is opened with the RECORD_ID_ACCESS option, access by record identification can be mixed with sequential access or access by key during this opening. However, a statement cannot specify a record both by key and by record identification.
The RECSIZE option specifies the largest size that records in a file can have. The actual meaning of this option varies according to the type of file:
The SCALARVARYING option specifies that character strings with the VARYING attribute be read and written in strict accordance with the PL/I ANSI standard. Its format is as follows:
The SCALARVARYING option has the following effect on I/O operations involving VARYING character-string variables:
Thus, records to be read into or from variables with the VARYING attribute should be images of a varying character string -- including the 2-byte count field at the beginning of the string.
When SCALARVARYING is not specified, character-string variables with the VARYING attribute are handled so as to facilitate reading and writing files with variable-length records. The rules are as follows:
For strings with the VARYING attribute that are embedded in arrays or structures, the entire storage is always read or written.
When a file is to be read with SCALARVARYING in effect, the target variable must be declared CHARACTER VARYING, and the length of the target variable must match the record length of each record in the file, minus two bytes. If the length does not match, the ERROR condition is signaled.
The following example illustrates reading a file with the SCALARVARYING option (presumably the file was created with the SCALARVARYING option in effect):
DECLARE EOF BIT(1) ALIGNED INITIAL('0'B);
DECLARE STRING CHARACTER(80) VARYING,
OPEN FILE(INFILE) ENVIRONMENT(SCALARVARYING);
ON ENDFILE(INFILE) EOF = '1'B;
READ FILE(INFILE) INTO(STRING);
PUT SKIP LIST(LENGTH(STRING),STRING);
READ FILE(INFILE) INTO(STRING);
The file defined as INFILE must have 82-byte records: the first two bytes of each record must contain the length of the data within the record. This READ statement reads 82 bytes, and uses the first two as the length and contents of each string.
The SHARED_READ option specifies that other users who have concurrent access to the file can read records in it. The format of this option is:
The SUPERSEDE option specifies that if a file already exists with the same name and type, it will be deleted and a new file created in its place. This is the default. The format of this option is:
The TEMPORARY option creates a temporary file name using tempnam(3s). The format of this option is:
When you create a file with the TEMPORARY option, the file system calls tempnam(3s) to create a uniquely named temporary file. A file thus created can be used during the execution of the program and deleted on completion, without cluttering up the current working directory.
The file can be deleted when it is closed or, if needed later, can be deleted after it has been reused. You specify deletion by using the DELETE option when you open, reopen, or close the file.
However, because the name of the temporary file is not available to a PL/I application, the file can be reaccessed only by its internal file identification. You can obtain this identification by specifying the FILE_ID_TO option when the file is created. For example:
DECLARE WORKFILE FILE OUTPUT SEQUENTIAL,
WORKFILE_ID (6) FIXED BINARY(31);
OPEN FILE(WORKFILE) ENVIRONMENT (
OPEN FILE (WORKFILE) ENVIRONMENT (
These statements declare the file WORKFILE, open it with the FILE_ID_TO option, close it, and later reopen it, using the FILE_ID option and specifying the file identification obtained when the file was first opened. The second OPEN statement also specifies the DELETE option of ENVIRONMENT, so that the file is deleted when it is subsequently closed.
The WORLD_PROTECTION option defines the type of access to be permitted to the file by users who are not in the owner's group and who are not the superuser. Refer to id(1). The format of this option is:
Is a 1- to 4-character string expression indicating the access privileges to be granted to users in the world category. The character-string expression can contain any of the following letters to indicate the access allowed:
w -- Write/delete access is allowed.
x -- Execute access is allowed.
Letters can be repeated, but the maximum length of the string is 4 characters. The character-expression string is case insensitive; "W" and "w" are equivalent.
For compatibility with OpenVMS implementations of PL/I, you can use "d" as a synonym for "w", and "e" as a synonym for "x". All other characters are invalid. If any other character is present in the string, the UNDEFINEDFILE condition is signaled.
Each user who is authorized to use the system is assigned a user identification (UID) and a group id (GID) by the system manager. When a PL/I program creates a file, the current UID associated with the process executing the program defines the file's ownership.
Based on this UID, called the owner UID, the file system defines the file protection in terms of which users on the system can access the file and what operations they can perform on the file. These users are defined as follows:
The types of permissions defined for a file are:
The types of permissions defined for a directory are:
The difference between read access and execute access is that you are allowed to perform wildcard operations on a directory you have read access to, but you must know the exact pathname of a file in a directory to which you have only execute access.
You can explicitly control the protection applied to a file by specifying the type of access allowed each category of user.
In a PL/I program, you can specify file protection when you create the file.
When you specify ENVIRONMENT options for a file you are creating in a PL/I program, you can specify the following options to define the access permitted to various users:
These options specify the types of access permitted by the specification of the following codes:
r -- gives the right to read the file.
w (or d) -- gives the right to modify or delete the file.
x (or e) -- gives the right to execute executable files.
These codes can be specified in any order for an option; if you specify an option and omit a code, that category of user is denied that type of access. If you specify one or more protection options, the protection for unspecified categories defaults to no access. If you do not specify any protection options, then PL/I uses the current default protection (umask) for all the categories.
This specification defines protection to a file as follows:
Note that the UNIX command chmod lets the owner of a file change file permissions at any time. Additional commands and user privileges let users override or change file permissions. For details on these commands and privileges, see umask(1).
The file system applies the permissions you specify for a file when the file is accessed from a program or from the command level. It also applies the permissions when the file is shared.
Input/Output Statement Options
PL/I lets you specify the OPTIONS keyword on input/output statements and supports certain options for each statement. This chapter explains how to code options for I/O statements, summarizes the valid options for each I/O statement, and describes each option individually.
Use the OPTIONS keyword and an options list in a statement to specify I/O statement options. Enclose the options list in parentheses and separate individual options by commas, as follows:
See . Summary of Input/Output Statement Options lists the I/O options, their uses, the statements for which they are valid, and their data types.
CANCEL_CONTROL_O 7 |
|||
FAST_DELETE 8 |
|||
Clears the terminal type-ahead buffer before reading input data. |
|||
The NO_ECHO option specifies, when the input device is a terminal, that the data entered at the terminal will not be displayed as it is entered.
Use the NO_ECHO option when you want to keep data entered at a terminal from being seen by users other than the one who entered the data. For example, if you request a password, the NO_ECHO option protects the password, as follows:
GET LIST (PASSWORD) OPTIONS (NO_ECHO,
Data entered in response to this GET statement is not displayed on the terminal.
The PROMPT option specifies, when the input device is a terminal, a character-string prompt to be displayed before actual input. The format of this option is:
Unlike a PUT statement followed by a GET statement, a GET statement with the PROMPT option is actually executed as a single statement. For example:
GET LIST (NUM) OPTIONS (PROMPT('Enter number: '));
When this statement is executed, the terminal display will be as:
The prompting string and the input data occur in the same statement.
The PROMPT option causes any data that was not processed by the last GET operation to be ignored. If the SKIP option is not specified, the prompt is output at the current cursor position. If you specify the SKIP option in conjunction with the PROMPT option, the SKIP operation is performed before the prompting message is displayed.
The PURGE_TYPE_AHEAD option specifies, when the input device is a terminal, that all data in the terminal's type-ahead buffer be deleted before the input operation is performed.
When a command or program is being executed, the terminal keyboard accepts input data and stores it in a buffer called the type-ahead buffer. When the command or program is completed, the command interpreter reads its next command from the type-ahead buffer. When a GET statement is executed with this option in effect, any data in the type-ahead buffer is deleted, ensuring that the GET statement will not read any extraneous data.
The RECORD_ID option indicates that the record of interest is specified by its record identification. The format of this option is:
RECORD_ID (variable-reference)
Specifies the name of a 2-element array variable containing the record identification.
The following example illustrates a record whose record identification is saved for a later file access.
SAVE_RECORD_ID(2) FIXED BINARY(31),
OPEN FILE(BOOKFILE) ENV(RECORD_ID_ACCESS);
READ FILE(BOOKFILE) INTO(INBUF) KEY(KEYVALUE)
OPTIONS(RECORD_ID_TO(SAVE_RECORD_ID));
OPEN FILE(BOOKFILE) INPUT ENV(RECORD_ID_ACCESS);
READ FILE(BOOKFILE) INTO(INBUF)
OPTIONS(RECORD_ID(SAVE_RECORD_ID));
During the first opening of the file, the record identification of a specified record is obtained and saved. When the file is subsequently reopened, this value is used to access a record and to effectively position the file at that record.
The RECORD_ID_TO option specifies the name of a variable to be assigned the value of the record identification of the record on which the current operation is being performed. The format of this option is:
File-Handling Built-In Subroutines
In addition to the PL/I input and output statements and the functions and features available through the options of the ENVIRONMENT attribute, there are also two built-in file-handling subroutines. They are called built-in subroutines because you do not need to declare them before using them in a PL/I program. The subroutines are:
Both of these subroutines are valid only in the dec dialect.
The following sections describe the FLUSH an dREWIND routines.
The FLUSH built-in subroutine writes all file buffers that have been modified and preserves all of the file attributes of the file. This subroutine provides the ability to checkpoint a file during its processing and ensure its integrity. Its calling sequence is:
Specifies the name of the file variable or file constant associated with the file whose buffers are to be flushed. If the file is not currently opened, the FLUSH subroutine performs no operation.
Use the FLUSH subroutine to explicitly request PLI to write all internal file buffers back to the file. This subroutine is called implicitly by the REWIND built-in subroutine.
The REWIND built-in subroutine positions a file so that the next record to be read will be the first record in the file. Its calling sequence is as follows:
Specifies the name of the file constant or file variable associated with the file to be rewound. If the file is not currently open, the REWIND subroutine implicitly opens the file with the attributes specified in the declaration of the file.
Use this subroutine to begin processing a file at its logical beginning. This subroutine is valid for disk files of all organizations. The position of the file following the call to the REWIND subroutine is:
You can also use the REWIND built-in subroutine to reposition a stream file after an end-of-file condition. Normally, if end-of-file (Ctrl/D on a terminal) is entered during an input operation on a stream input file, the PL/I program must close the input file and reopen it before any more data can be read. However, an ENDFILE ON-unit can be written as:
ON ENDFILE(STREAMFIL) CALL REWIND(STREAMFIL);
This ON-unit calls the REWIND built-in subroutine each time an end-of-file is encountered for the file constant STREAMFIL. The REWIND built-in subroutine repositions the stream file at its beginning so that the program can continue reading input.
Using Sort Subroutines (IBM Only)
The ibm dialect of Kednos PL/I for UNIX provides an interface to SyncSort, which must be separately licensed from Syncsort Incorporated.
To use the sort routines, insert code in your program to call one of the Sort program's entry points. The call passes information on the fields to be sorted. You must specify information about the data to be sorted, the type of sort to perform, the format and destination of the output, and so on.
The Sort program called by Kednos PL/I for UNIX provides a flexible interface with wide functionality. You define the sorting field in each record, the type of sort, and what types of error messages to display. You can also specify whether the data originates and/or is output to a file or a user-written routine.
The following sections describe how to use the sort routines.
Before writing the call to the Sort program, you must determine the following:
This section contains information on the PL/I sorting interface. Understanding the interface will help you decide which routine to use and what to pass to the routine. The sections following See Calling the Sort Subroutines give details on each portion of the call. They contain information on what specifying sort fields, the available sort types, how to determine storage needs, and so on.
This section contains information on sorting using the PL/I sorting interface to call the Sort program, a separately licensed external product, SyncSort. Understanding the interface will help you decide which routine to use and what to pass to the routine. Kednos PL/I for UNIX contains a built-in interface to call SyncSort using the previously established IBM Sort program call syntax. This provides compatibility and portability between platforms.
The Kednos PL/I for UNIX Sort interface provides four entry points to the Sort program. Each entry point specifies a different combination of data source and destination, either from and to a file or from and to a subroutine, or a combination of the two. The entry points are described in See Determining Which Entry Point to Use .
The Sort program handles the complete sort operation. It communicates with the calling program, and any specified user-written input or output routines, by using return codes.
To use the Sort program, insert a CALL statement in your program. The CALL statements specifies one of the four Sort entry points. It must contain the correct arguments for the specified entry point. Once the Sort program is called, it does the following:
Note that user-written input or output routines become, for all purposes, part of the Sort program for the duration of the sort. The Sort program calls the routines at the appropriate point in processing. Return codes control the flow of control between the Sort program and the input or output routines, telling the Sort program whether it should call the routine again or continue to the next stage in processing.
When sorting in PL/I, the data can originate in a file and be output to another file, or it can originate and/or be output to a user-written PL/I subroutine. The simplest use of the Sort program is to sort a file and direct the results into another file. The input file must be in the default directory, and the output file will be placed in the default directory. By default, the input file is SORTIN and the output file is SORTOUT.
Using subroutines lets you manipulate the data before and/or after the sort. For example, you could read a file and sort only certain records, or you could print the resulting sorted data. Like files, input and output subroutines must exist in the default directory. The format of input and output routines is described more fully in See Input and Output Routines .
The Sort program interface provides four entry points. The following table lists the entry points to the Sort program and specifies the source and destination of data in each case:
The format of the call to any of the four sort entry points is:
CALL PLISRTx (sort-specification, record-specification, maximum-storage, return-code [,input-routine] [,output-routine] [,file-prefix,message-level] );
A character-string expression of the form:
'bSORTbFIELDS=(start1,length1,format1,order1
[,startn,lengthn,formatn,ordern] ) [,OPTION1[...,OPTIONn]]b'
A character-string expression of the form:
'bRECORDbTYPE=RECTYPE[,LENGTH=(rec-length[,,min-length,
modal-length)]b'
A fixed binary (31) expression giving the amount of storage to be used by the Sort program.
Fixed binary (31) user-supplied variable in which Sort returns a code indicating success or failure. This is a required argument.
Name of the user-written PL/I routine that supplies records to the Sort program. Required for PLISRTB and PLISRTD; invalid otherwise.
Name of the user-written PL/I routine that receives sorted records from the Sort program. Required for PLISRTC and PLISRTD; invalid otherwise.
The sort-specification is the first argument to PLISRTx. It has the following syntax:
'bSORTbFIELDS=(start1,length1,format1,order1,
...startn,lengthn,formatn,ordern)[OPTION1[...,OPTIONn]]b'
The sorting information specifies the location of each sort field and how to sort by each field. You can specify multiple sets of sorting information but the total of all the lengths must be 256 bytes or less.
If you specify more than one sort field, the Sort program sorts on each field in order. In other words, it sorts on the first field, then sorts groups of records that have the same first field according to the second field, and so on.
Sort fields can overlap each other.
The following list gives details on each element of the sorting information.
Additional options to the Sort program. Use a comma separate any options from the preceding arguments and from each other. Do not put blank spaces between options.
The following list gives details on each additional option.
The record-specification is the second argument to PLISRTx. It has the following syntax:
'bRECORDbTYPE=RECTYPE[,LENGTH=(rec-length[,,min-length,
modal-length)]b'
For stream files only, LENGTH defaults to 512 bytes. The LENGTH argument is required for all other types of files. The length of a record can never exceed the value specified as rec-length. The maximum length you can specify is 32767 bytes.
You can specify storage either by declaring a fixed binary (31) variable and passing the variable to the Sort routine, or by passing a constant value. For example, either one of the following calls will invoke the Sort program PLISRTA to sort a 40-byte character record using 512,000 bytes of storage:
DECLARE RETURN_CODE FIXED BIN(31);
CALL PLISRTA(' SORT FIELDS=(1,40,CH,D) ', ' RECORD TYPE=F,LENGTH=(40) ', 512000, RETURN_CODE);
DECLARE RETURN_CODE FIXED BIN(31);
DECLARE MAXSTORAGE FIXED BIN(31) INITIAL(512000);
CALL PLISRTA(' SORT FIELDS=(1,40,CH,D) ', ' RECORD TYPE=F,LENGTH=(40) ',MAXSTORAGE,RETURN_CODE);
You must specify a value for storage. Determining storage for a particular sorting operation can be complicated. One guideline is to provide enough storage so the storage can hold three sets of the records being sorted. However, this might be too much.
When using PLISRTB, PLISRTC, or PLISRTD, leave enough storage available on your system to open the files after the Sort programs use the specified amount.
In any case, do not specify an amount of storage greater than the available physical memory on your processor.
Kednos PL/I for UNIX passes the value specified for storage directly to the /MEMORY option of the SyncSort routines. For more information and guidelines on determining a value for storage, see the SyncSort Reference Guide.
The required return code argument is a variable to contain the fixed binary(31) value returned by the sort program. The sort program returns one of the following:
In your calling program, declare a fixed binary(31) variable to contain return code.
To determine success or failure of the sort, check the return code after the call to the Sort program.
For example, assume that the variable RETURN_CODE was declared for use with the Sort program. The following code calls PLISRTD to sort on a single 10-character field. Since the record is varying length, four bytes are added so the field starts at the fifth position in the record. The input and output routines are SORT_IN and SORT_OUT. After returning from the call, the code checks the success of the sort, and signals an error if necessary:
CALL PLISRTD (' SORT FIELDS=(5,10,CH,A),EQUALS ',
' RECORD TYPE=V,LENGTH=(84,,15,50) ',
256000,RETURN_CODE,SORT_IN,SORT_OUT);
The input-routine argument is used with PLISRTB and PLISRTD. The output-routine argument is used with PLISRTC and PLISRTD. These arguments are required for the specified routines. They give the name of the user-written PL/I routine that supplies records to or accepts records from the Sort program. The specified routines must exist in the default directory. See See Input and Output Routines for more information on writing routines for use with the Sort program. See the preceding section for an example of calling PLISRTD, specifying the user-written input routine SORT_IN and the user-written output routine SORT_OUT.
The optional file prefix argument lets you replace the default prefix `SORT' in the names of the input, output, and temporary files the sort program uses. Using a file prefix lets you invoke the sort program multiple times and use different file prefixes so invocations do not interfere with each other. For example, you can specify 'TEMP' for the file prefix, as shown in the following example:
CALL PLISRTA(' SORT FIELDS=(1,40,CH,D) ', ' RECORD TYPE=F,LENGTH=(40) ',STOR,RETURN_CODE,'TEMP');
In this case, the sort program uses the files TEMPIN, TEMPOUT, TEMPWRK01 to TEMPWRKnn, TEMPCNTL, and TEMPCKPT.
The file prefix must be four characters starting with an alphabetic character. It can not be the reserved prefix LIST. Note that the names PEER, BALN, CRCX, OSCL, POLY, and DIAG are reserved file prefixes in other implementations of PL/I. Avoid using these for a file prefix if you are concerned about compatibility.
If you omit this argument but require the message-level argument, specify a null string ('') in place of the file prefix argument.
The message-level argument indicates how the Sort program handles diagnostic messages. You can specify one of the following:
If you omit the file-prefix argument but require the message-level argument, specify a null string ('') in place of the file prefix argument. For example, the following call invokes PLISRTB to sort on the first 12 characters of a 30 character record in ascending order. Input is passed to the Sort program by a user-written routine called READ_DATA, the file prefix is defaulted to SORT, and no messages are passed back:
CALL PLISRTB(' SORT FIELDS=(1,12,CH,A) ', ' RECORD TYPE=F,LENGTH=(30) ',MAXSTORAGE,RETURN_CODE, READ_DATA,' ','NO');
When sorting in PL/I, the data can originate in a file and be output to another file. This is done using PLISRTA, the simplest interface.
Input and output routines give you additional flexibility. When using routines PLISRTB, PLISRTC, and PLISRTD, your sort data can originate and/or be output to a user-written routine. These input and output routines are written in PL/I. They can be either internal or external procedures. If they are internal to the calling program (the program routine with the call to the Sort program), the input and output routines follow the usual scoping rules. Whether or not the routines are internal to the calling program, the input and output routine names must be known within the scope of the block containing the call.
The Sort program calls the input and output routines once for each record being sorted. Therefore, write each routine to handle one record at a time. Note that this means automatic variables will not retain their value between calls. If a variable, such as a counter, must retain its value between calls, either declare it STATIC or declare it in the containing block.
The PLIRETC built-in subroutine lets you set a return code. Use PLIRETC in your input and output routines to return a value to the Sort program. This can also be used in conjunction with the PLIRETV built-in function for purposes other than sorting.
Use an input routine to manipulate the data in some way before sorting it. For example, you might want to print the data or generate or modify the sorting fields.
The input routine and the Sort program communicate using calls to PLIRETC. Sort allows three PLIRETC return codes when calling an input routine:
Calls made to PLISRTB or PLISRTD require an input routine. When using an input handling routine, the sort processing is as follows:
The input routine passes records back to the Sort program in the RETURN statement. Therefore you must specify the RETURNS attribute in the input routine PROCEDURE statement.
Returned records must be in character string format. They can be fixed or varying. Varying strings are padded differently depending on what you specify as the record format in the RECORD argument to the PLISRTx call. If you specify V, strings are not padded. If you specify F, strings are padded with blanks to the maximum length.
SORT_INPUT_ROUTINE: PROCEDURE RETURNS(CHAR(80));
/* you must specify the returns attribute. For varying
strings, the length must be the maximum length.
DECLARE CUST_RECORD CHARACTER(80);
DECLARE CUSTOMER_FILE FILE RECORD INPUT;
ON ENDFILE(CUSTOMER_FILE) BEGIN;
PUT SKIP(2) LIST('End of customer file input.');
CALL PLIRETC(8); /* signal end of input to Sort */
/* Do any processing you require to get a record. */
/* For example, you could get the record from a file */
/* and then display the record. */
READ FILE (CUSTOMER_FILE) INTO (CUST_RECORD);
/* signal Sort to include this record */
Use an output routine to do an y post-sorting processing. For example, you might want to print the data or use the sorted data in a calculation.
The input routine and the Sort program communicate using calls to PLIRETC. Sort allows only one PLIRETC return codes when calling an input routine:
Calls made to PLISRTC or PLISRTD require an output routine. When using an output handling routine, the sort processing is as follows:
Note that the Sort program does not pass an end-of-data code to your output routine. Do any end-of-data processing after the Sort program returns to the calling program.
SORT_OUTPUT_ROUTINE: PROCEDURE(CUST_RECORD);
DECLARE CUST_RECORD CHARACTER(80);
DECLARE NEWCUST_FILE FILE RECORD OUTPUT;
/* Do any processing you require. */
/* For example, you could display the record. */
This section contains an example of calling PLISRTA, which uses a file for both input and output, and PLISRTD, which uses input and output routines. PLISRTB and PLISRTC use a combination of files and routines. If you want to use either of those entry points, look at both of the following programs for examples.
SORT_EXAMPLE1: PROCEDURE OPTIONS(MAIN);
/* declare a variable to hold the code returned by the Sort
DECLARE RETURN_CODE FIXED BIN(31);
/* call the PLISRTA entry point of the sort routine. */
CALL PLISRTA (' SORT FIELDS=(5,20,CH,A,25,20,CH,A,45,1,CH,A) ',
' RECORD TYPE=F,LENGTH=(120) ',
WHEN(0) PUT SKIP LIST ('Sort completed successfully.');
WHEN(16) PUT SKIP LIST ('Sort failed.');
PUT SKIP LIST('Invalid Sort return code'||RETURN_CODE);
The example above sorts a customer file by name. The arguments of the call to PLISRTA are:
SORT_EXAMPLE2: PROCEDURE OPTIONS(MAIN);
/* declare a variable to hold the code returned by the Sort
DECLARE RETURN_CODE FIXED BIN(31);
/* call the PLISRTD entry point of the sort routine. */
CALL PLISRTD (' SORT FIELDS=(5,20,CH,A,25,20,CH,A,45,1,CH,A) ',
' RECORD TYPE=D,LENGTH=(124) ',
WHEN(0) PUT SKIP LIST ('Sort completed successfully.');
WHEN(16) PUT SKIP LIST ('Sort failed.');
PUT SKIP LIST('Invalid Sort return code'||RETURN_CODE);
SORT_INPUT: PROCEDURE RETURNS(CHAR(120) VARYING);
/* you must specify the returns attribute. For varying
strings, the length must be the maximum length. */
DECLARE CUST_RECORD CHARACTER(120) VARYING;
DECLARE CUSTOMER_FILE FILE RECORD INPUT;
ON ENDFILE(CUSTOMER_FILE) BEGIN;
PUT SKIP(2) LIST('End of customer file input.');
CALL PLIRETC(8); /* signal end of input to Sort */
/* Do any processing you require to get a record. */
/* For example, you could get the record from a file */
/* and then display the record. */
READ FILE (CUSTOMER_FILE) INTO (CUST_RECORD);
/* signal Sort to include this record */
RETURN(CUST_RECORD); /* return the record to Sort */
SORT_OUTPUT: PROCEDURE(CUST_RECORD);
DECLARE CUST_RECORD CHARACTER(*);
DECLARE NEWCUST_FILE FILE RECORD OUTPUT;
/* Do any processing you require. */
/* For example, you could display the record. */
CALL PLIRETC(4); /* request the next record */
The example sorts a varying length record ASCII format customer file by customer name. The elements of the call to PLISRTD are similar to the ones in the call to PLISRTA. The differences are:
You must declare the input routine using the RETURNS(VARYING) attribute, and declare the CUST_RECORD as CHARACTER VARYING. The output routine must contain a CUST_RECORD declared as CHARACTER(*). The RECORD TYPE is D, since the file is in ASCII format with varying length records. The maximum record length is specified, including a 4 byte length prefix (compatible with the length prefix on IBM implementations of PL/I).
In PL/I, errors are signaled through ON conditions and handled by groups of statements called ON-units. An ON condition is any one of several named conditions that interrupt program execution. When an ON condition occurs, or is signaled, the corresponding ON-unit is executed.
This chapter discusses the following topics:
Refer to the Kednos PL/I for UNIX Reference Manual for descriptions of the ON, REVERT, and SIGNAL statements and ON conditions.
The RESIGNAL built-in subroutine is used in an ON-unit to pass a signaled condition, so that the run-time system will attempt to locate another ON-unit to handle the condition.
RESIGNAL works by setting up the internal mechanism for passing the signal. It does not by itself cause an exit from the ON-unit that calls it. Instead, it returns to the next statement in the ON-unit. Resignaling does not occur until execution of the ON-unit is completed.
The format of a statement calling the RESIGNAL built-in subroutine is:
VAXCONDITION provides a general-purpose signaling mechanism for PL/I applications that execute under the control of the VMS operating system. This condition is carried to the PL/I compiler for compatibility reasons.
An ON-unit for a VAXCONDITION condition is established in the following format:
ON VAXCONDITION (expression) on-unit
Any expression yielding a FIXED BINARY(31) value that can represent either a specific VMS condition value or status value, or an arbitrary user-specified value. The low-order three bits of the value are interpreted as the condition's severity by the default PL/I and system condition handlers. The expression is evaluated when the ON statement is executed, not when the condition is signaled.
A VAXCONDITION ON-unit can be used in conjunction with calls to system service, run-time library, or other system procedures that return status values. An error-handling routine can test the return status value from a system procedure and, if not successful, signal the error.
ON-units can exist for any number of specific values. For example:
VCND: PROCEDURE OPTIONS(MAIN);
ON VAXCONDITION(COND1), VAXCONDITION(COND2)
PUT SKIP LIST ('Main handler for VAXCONDITIONs: ',
PUT SKIP EDIT (' Caught ', oncode()) (A,F(5,0));
PUT SKIP EDIT ('p1: caught VAXCONDITION: ',COND1)
During its execution, an ON-unit can take any of the following courses of action:
These courses of action are described individually in the following subsections.
A condition is assumed to be handled in PL/I when the ON-unit established for the condition completes execution without performing one of the following actions:
When the condition is handled, PL/I continues execution of the program at the point of interruption. Normal completion of any ON-unit (except ERROR signaled as the default action) results in return of control either to the statement that caused the condition or to the statement immediately following the statement that caused the condition. However, the effects of normal return from ERROR, FIXEDOVERFLOW, OVERFLOW, UNDERFLOW, and ZERODIVIDE are generally unpredictable. Exceptions are cases of ERROR that are specifically documented to allow normal return, and ON-units that execute as a result of a SIGNAL statement. Normal return from a CONVERSION condition that modifies ONCHAR or ONSOURCE pseudovariables causes the conversion to be retried.
In PL/I, an ON-unit can choose not to handle a condition and can request that, rather than returning control to the point of interruption, PL/I continue to search for another ON-unit to handle the condition. It does this by calling the RESIGNAL built-in subroutine as follows:
The RESIGNAL built-in subroutine has no arguments.
When an ON-unit calls RESIGNAL, PL/I resumes its search of the call stack starting at the call frame beneath the frame in which it located the current ON-unit. The next example and See . Resignaling a Condition illustrate the effect of the RESIGNAL built-in subroutine. The reverse numbers indicate the order of execution. Procedure B establishes an ANYCONDITION ON-unit that handles specific VAXCONDITION values. When the ON-unit is executed as a result of a signal in either procedure B or C, it tests the current value of ONCODE to see whether it is a value of interest. If not, procedure B calls RESIGNAL.
END; /*Begin block for IF statement */
See . Resignaling a Condition illustrates the preceding example.
When the FIXEDOVERFLOW condition is signaled in procedure C, B calls RESIGNAL and PL/I continues its search of the call stack. It locates the ON-unit for handling the FIXEDOVERFLOW condition in procedure A and executes it.
Note that the default condition handling performed by PL/I uses the resignaling capability to continue signals that are not handled within the program. PL/I default condition handling is described in See Search Path for ON-Units .
An ON-unit in a PL/I procedure can execute a nonlocal GOTO statement that transfers control to a previous block. In this case, PL/I releases call frames, beginning with the call frame created for the ON-unit, until it reaches the block containing the label specified in the GOTO statement.
This removal of call frames from the call stack is called an unwind. The next example and See . Unwinding the Call Stack illustrates a situation in which an unwind occurs. The reverse numbers indicate the order of execution. The ERROR ON-unit established in procedure A receives control when the ERROR condition is signaled in procedure C. This ON-unit executes the GOTO PRINT_MSG statement. The label PRINT_MSG is in procedure A. Thus, the call stack is unwound and the call frames for the ON-unit, procedure C, and procedure B, in that order, are removed from the stack, and execution continues at the label PRINT_MSG.
See . Unwinding the Call Stack illustrates the preceding example.
When an unwind occurs in the UNIX environment, PL/I examines each call frame in the calling sequence to determine if a condition ON-unit exists for that frame. If so, PL/I calls the ON-unit with the condition value SS$_UNWIND, and the ON-unit has the chance to perform block- or procedure-specific cleanup operations.
You can use an ON-unit to terminate program execution. To do this, include a STOP statement in the ON-unit. For example:
ON UNDEFINEDFILE(INFILE) BEGIN;
PUT EDIT('File ',ONFILE(),' undefined. Error ',ONCODE())
The STOP statement performs the following actions:
Thus, when a FINISH ON-unit that has been executed as a result of a STOP statement handles the condition, control returns to the STOP statement, which then terminates the image.
If no FINISH or ANYCONDITION ON-unit exists, the program terminates.
If a FINISH or ANYCONDITION ON-unit executes a STOP statement, the program enters an infinite loop. Therefore, do not put STOP statements in FINISH or ANYCONDITION ON-units.
In the UNIX environment, an exception is a hardware- or software-detected condition that synchronously or asynchronously interrupts the execution of an image. A condition handler is a procedure that exists specifically to respond to one or more such conditions; each procedure in the program can establish a condition handler. It is usually the responsibility of each handler to determine the specific condition that was signaled, and to decide whether or not to handle it.
Most high-level languages do not provide language constructs to handle exceptions; therefore, condition handlers are established by calling the UNIX Run-Time Library procedure signal(3). The PL/I language, however, uses the ON-unit condition handler to handle a specific condition. By using the keyword condition names defined by PL/I and the extensions provided by PL/I, you can write ON-units to handle any possible UNIX-specific condition. Each procedure can establish separate ON-units for each of several possible conditions that the procedure wishes to handle.
You should never use signal(3) to establish a condition handler in a PL/I call frame.
UNIX signals are mapped to PL/I signals and can be handled by on units in PL/I. The main program establishes default handlers for UNIX signals, thus this behavior is only in affect when the main program is in PL/I. PL/I runtime library establishes the default signal handler for all UNIX signals except SIGSTOP and SIGKILL which cannot be caught. For more information about UNIX signals see the signal(3) manpage.
The default handling of signals is as follows:
All other signals generated are handled either by a VAXCONDITION(signal) handler for the specific signal code or by the PL/I ANYCONDITION handler. As usual the specific code that caused the condition is available by calling ONCODE().
Note that unlike other conditions, in the case of a UNIX signal not handled by a specific on condition handler, a PL/I ERROR condition is NOT generated. This allows UNIX signals to behave in the normal way if no condition handlers are used.
Within a PL/I program the values for the UNIX signals are available in the following variables, each corresponding to one of the UNIX signals. For access to these variables, a program can GLOBALREF the variables. The standard include file, signaldef.in, contains the declarations for these variables. To include the signaldef.in file in your PL/I program, use the following statement:
See . Corresponding Values identifies the correspondence between UNIX signal numbers and the corresponding ONCODE value.
The numbers listed in See . Corresponding Values for the ONCODE values are under program control. The values listed are the initial value for each of the signals. These numbers may be modified, if desired, by assigning a new value to the variable. Take care not to duplicate these signal numbers or they cannot be distinguished. These values should not be modified within a condition handler.
You may want to use your own number for the ONCODE value, if the numbers are used to identify a related error message.
The following program shows an example of how UNIX signals can be handled, and how the ONCODE values can be modified:
UNIXSIG: PROC OPTIONS( MAIN );
dcl sig$_usr1 fixed bin(31) globalref;
dcl sig$_int fixed bin(31) globalref;
dcl sig$_quit fixed bin(31) globalref;
/* set specific value for sig$_int */
/* set up anycondition handler to test for
* sig$_usr1, sig$_int and sig$_quit */
if (oncode() = sig$_usr1) then
PUT LIST ( 'mainloop: caught sigusr1 ',oncode());
else if oncode() = sig$_int then
PUT LIST ( 'mainloop: caught sigint ',oncode());
else if oncode() = sig$_quit then
PUT LIST ( 'mainloop: caught sigquit ',oncode());
/* set up specific handler for sig$_usr2 */
on vaxcondition(sig$_usr2) begin;
PUT LIST ( 'usr2: caught sigusr2 ',oncode());
/* main loop processing starts here */
In this example, specific handlers are set up for the UNIX signals SIGUSR1, SIGINT, SIGQUIT, and SIGUSR2. The first three are caught in the ANYCONDITION handler and the ONCODE is compared to the current values in the global variables sig$_usr1, sig$_int and sig$_quit. The signal SIGUSR2 is caught in a specific VAXCONDITION on units testing for sig$_usr2.
In PL/I, each call frame in the calling sequence for ON-units is searched in a specific sequence. If it reaches the call frame at which the program was entered without locating an ON-unit, it performs default condition handling. The default handling depends on whether or not the call frame at which the procedure was entered specified the MAIN option.
The next example and See . Execution of an ON-Unit illustrates the call frames established for the execution of a series of procedures. Procedure A establishes an ON-unit for the FIXEDOVERFLOW condition, and procedure B establishes an ON-unit for an UNDEFINEDFILE condition for the file PRINTFILE. When a FIXEDOVERFLOW condition is signaled in procedure C, PL/I locates the ON-unit established in procedure A and activates the corresponding ON-unit. When PL/I activates an ON-unit, it creates an activation record for the ON-unit and places the ON-unit on the call stack for execution, as if it were a unique block activation.
ON UNDEFINEDFILE (PRINTFILE) OPEN
FILE (PRINTFILE) TITLE('SYS$OUTPUT');
RETURN; /* Fixed overflow signaled */
See . Execution of an ON-Unit illustrates the preceding example.
If PL/I entered a program at a procedure containing the MAIN option, PL/I searches for ON-units and performs default condition handling as follows:
If one of these ON-units exists, it is executed and the search is ended. If the ON-unit completes execution by handling the condition, the program continues at the point at which the condition was signaled.
If a FINISH ON-unit is found, its execution is attempted. If it executes a nonlocal GOTO or signals another condition, program execution continues.
If no FINISH ON-unit is found, or if a FINISH ON-unit completes execution by handling the condition, then PL/I resignals the condition to the default UNIX condition handler. This handler prints a message and terminates the program.
If an ERROR ON-unit is found, it is executed. If it completes execution by handling the condition, the program continues.
If an ERROR ON-unit is not found, the default PL/I handler resignals the condition. If this resignaling results in control returning to the system, the default UNIX condition handler prints a message. If the error is a fatal error, the default handler terminates the program; if the error is nonfatal, the program continues.
If the call frame at which the program was entered did not specify the MAIN option, the default condition handling is:
If one of these ON-units exists, it is executed and the search is ended. If the ON-unit completes execution by handling the condition, the program continues at the point at which the condition was signaled.
The next example and See . Search for an ON-Unit illustrate a search for an ON-unit that will handle a decimal overflow condition. The reverse numbers indicate the sequence in which the search takes place.
ON ERROR BEGIN; Õ /* ERROR signaled */
B: PROCEDURE; /* Look for ERROR */
C: PROCEDURE; /* Look for ERROR */
Referring to the example above and See . Search for an ON-Unit , you can see that PL/I takes the following actions:
Searches the call frame (C) in which the condition was signaled for three specific ON-units: VAXCONDITION (SS$_DECOVF), FIXEDOVERFLOW, ANYCONDITION
Searches the previous call frame (B)
Reaches the main procedure (A) ON-units
Searches the call frame (C) ERROR ON-unit
Searches the previous call frame (B)
Locates the ERROR ON-unit in the main procedure (A)
If a second condition is signaled during the execution of an ON-unit, PL/I searches for an ON-unit that will handle the second condition, beginning in the call frame in which the second condition was signaled.
The next example and See . Effect of Multiple Conditions illustrate the search sequence followed when a second condition occurs during the execution of an ON-unit. The reverse numbers indicate the order of execution. The ERROR condition in procedure C is handled by the ON-unit established in procedure B. During the execution of this ON-unit, a FIXEDOVERFLOW condition is signaled. PL/I locates the ON-unit (shown in the See . Effect of Multiple Conditions as a box with dotted lines) established for FIXEDOVERFLOW conditions in procedure C and gives it control.
C: PROCEDURE; Ã /* Original ERROR signaled */ Õ
See . Effect of Multiple Conditions illustrates the preceding example.
Note that if the second condition is the same condition as the first, and the ON-unit does not establish another ON-unit, the same ON-unit will be executed repeatedly as the condition is signaled. A similar situation results when a STOP statement is executed within a FINISH or ANYCONDITION ON-unit; the program will enter an infinite loop when the STOP statement executes. The STOP statement signals FINISH, the current ON-unit is re-executed, the STOP statement is executed again, and so on.
In a PL/I program, an ANYCONDITION ON-unit or a VAXCONDITION ON-unit established specifically to handle the SS$_UNWIND condition is invoked during the unwind. The following example illustrates a VAXCONDITION ON-unit:
DECLARE SS$_UNWIND GLOBALREF VALUE FIXED BINARY(31);
ON VAXCONDITION(SS$_UNWIND) BEGIN;
CLOSE FILE(DATA_REC_TEMP) ENVIRONMENT(DELETE('0'B));
Although it is not specifically resignaled, when an ON-unit that is handling the unwind condition completes execution, the unwind continues.
Note that when an ANYCONDITION ON-unit executes a nonlocal GOTO statement, the nonlocal GOTO causes an unwind, and the first ON-unit that is given control is the ANYCONDITION ON-unit itself. Thus, an infinite loop occurs. To avoid this situation, an ANYCONDITION ON-unit can contain the following lines:
DECLARE SS$_UNWIND GLOBALREF VALUE FIXED;
IF ONCODE() = SS$_UNWIND THEN GOTO OKAY;
This check for the condition SS$_UNWIND ensures that if a nonlocal GOTO is executed in this ON-unit, it will not cause the ON-unit to be re-executed.
After an ON-unit is established, it remains in effect for the activation of the current block and all its dynamically descendent blocks, unless one of the following situations occurs:
The following examples illustrate some typical ON-units. The first example establishes an ON-unit for the FINISH condition. The ON-unit ensures that two files are closed properly, and calls a routine that stops a timer in an orderly fashion.
Normally, the FINISH ON-unit should be declared in the main procedure; however, it will be executed on image exit if it is established in any block that is active when that occurs.
The next example contains an ERROR ON-unit that will terminate a program in an orderly fashion, should some error occur that is not handled by a specific ON-unit.
DECLARE STATUS FIXED BINARY(31);
The ERROR ON-unit provides a cleanup procedure to ensure that the files identified as INFILE and OUTFILE are properly closed before the image exits. The ON-unit saves the value returned by ONCODE in the variable STATUS, and transfers control to a RETURN statement that returns the numeric value to the caller. If the procedure was invoked by a RUN command, this value is returned to the command interpreter, which in turn displays on the terminal the mnemonic code for the error and the error message.
The next example contains an ON-unit that changes the value of a bit variable when end-of-file is encountered.
ON ENDFILE(STATE_FILE) EOF = '1'B;
OPEN FILE(STATE_FILE) INPUT SEQUENTIAL;
READ FILE(STATE_FILE) SET(STATE_PTR);
READ FILE(STATE_FILE) SET(STATE_PTR);
The procedure reads the records in the file STATE_FILE until it encounters end-of-file. At that point, the ON-unit executes and changes the value of EOF from 0 to 1. This action causes the test in the DO WHILE statement to fail, terminating the loop that reads the records.
The following example shows an ON-unit that consists of a sequence of statements in a begin block:
This ON-unit consists of CLOSE and CALL statements that request special processing when the end-of-file condition occurs during reading of the default system input file, SYSIN.
The following example shows a null statement specified for an ON-unit:
This ON-unit causes PL/I to continue output on a terminal regardless of the number of lines already output. The null statement indicates that no processing is to occur when the condition occurs. Program execution continues as if the condition had been handled.
See , See File Organizations and Input/Output demonstrates an ON-unit that handles errors encountered during record I/O operations.
All UNIX-defined conditions have symbolic names associated with them. When thePL/I ONCODE built-in function is invoked in an ON-unit, it returns the value of the associated global symbol. This 32-bit status value describes the condition that was signaled. The low-order three bits of the status value contain the severity of the condition (success, warning, error, or fatal). Severity is important when no ON-unit exists for a condition, and default condition handling is performed by PL/I (see See Search Path for ON-Units ). This number is program dependent.
All symbolic names associated with UNIX condition values are defined as system global symbols. Thus, you can declare the names for these values in a PL/I program using the GLOBALREF attribute, and refer to them symbolically. The linker will automatically locate the definitions of the symbols in the default system libraries when the procedure is linked. You can use the system global symbol names to refer to the values returned by the ONCODE built-in function in an condition-handling ON-unit.
See . ONCODE Values for PL/I ON Conditions lists the PL/I keyword condition names and the UNIX global symbol names associated with each condition name.
UNIX Global Symbol Name 9 |
|
---|---|
AREA 10 |
See the Kednos PL/I for UNIX Reference Manual for a discussion of allocation in areas. |
PLI$_CONVERSION if a SIGNAL CONVERSION statement was executed, otherwise PLI$_ONCNVPOS (PLI$_ONCNVPOS could change in a future release of PL/I) |
|
A specific status value associated with the error that caused the condition to be signaled 11 |
|
STRINGRANGE See Only signalled via SIGNAL statement. No hardware support on UNIX. |
|
SUBSCRIPTRANGE See Only signalled via SIGNAL statement. No hardware support on UNIX. |
|
Any user-defined condition or UNIX signal global symbol value that was signaled |
|
The ONFILE built-in function returns the name of the file constant for which the current file-related condition was signaled. Its format is given in the Kednos PL/I for UNIX Reference Manual.
The ONFILE built-in function can be used in the following ON-units:
The returned value is a varying-length character string. If referenced outside an ON-unit or within an ON-unit that is executed as a result of a SIGNAL statement, the ONFILE function returns a null string.
The ONKEY built-in function returns the key value that caused the KEY condition to be signaled during an I/O operation to a file that is being accessed by key. Its format is given in the Kednos PL/I for UNIX Reference Manual.
This built-in function can be used in an ON-unit established for these conditions:
The returned key value is a varying-length character string. If referenced outside an ON-unit, or within an ON-unit executed as a result of the SIGNAL statement, the ONKEY built-in function returns a null string.
Using PL/I in the Common Language Environment
The PL/I compiler is part of the UNIX Standards common language environment. This environment defines certain calling procedures and guidelines that allow you to call routines written in different languages or prewritten system routines from PL/I. You can call any of the following routine types from PL/I:
The terms routine, procedure, and function are used throughout this chapter.
The definitions of routine, procedure, and function used in this chapter differ somewhat from standard PL/I terminology. The following definitions, used for consistency with the UNIX system routines documentation, apply only to this chapter:
The UNIX Procedure Calling and Condition Handling Standard describes the concepts used by all UNIX languages for invoking routines and passing data between them. This standard specifies the PL/I parameter handling mechanism as well as defining the calling sequence, argument data types and descriptor formats, condition handling, and stack unwinding.
The following sections discuss the parameter handling mechanism in more detail.
To pass data between routines that are not written in the same UNIX language, you must specify how you want that data to be represented and interpreted. You do this by specifying a parameter-passing mechanism. The general parameter-passing mechanisms and their keywords and abbreviations in PL/I are as follows:
The parameter-passing mechanisms are intended for use only in calling non-PL/I routines. External routines written in PL/I should be called with the established mechanisms.
The following sections describe the arguments in terms of PL/I data types, dummy arguments created (if any), parameter-passing mechanism conventions, and attributes to define the manner in which parameters are to be passed. Remember that when PL/I creates a dummy argument, modifications, if any, that the called procedure makes to the dummy argument are not accessible to the caller.
When you pass a parameter by reference, the PL/I compiler passes the address at which the actual parameter value is stored. In other words, your routine has access to the parameter's storage address. Therefore, when you manipulate and change the value of this parameter, the changed value overwrites the previous value of the parameter. Thus, when you pass a parameter by reference, any changes that you make to the value of the parameter in your routine are reflected in the calling routine as well, provided a dummy argument was not created.
You can pass an argument of any data type by reference. PL/I uses this mechanism by default for all arguments except character strings or arrays with nonconstant extents, and unaligned bit strings. Note that bit-string variables must have the ALIGNED attribute to be passed by reference. In general, the parameter descriptor for an argument to be passed by reference only needs to specify the data type of the parameter.
For example, the MEMSET runtime library routine requires the first argument passed by reference, and the second and third argument passed by value. You can declare this procedure as follows:
DECLARE MEMSET ENTRY (ANY, CHAR(1) VALUE,
When this procedure is invoked, the first parameter can be any variable, the second parameter must be a character, and the third variable a numeric expression.
The data types in the parameter descriptors of all output arguments must match the data types of the written arguments.
When you write a parameter descriptor for a non-PL/I procedure, you can specify the ANY attribute without the VALUE attribute to describe an argument being passed by reference. The argument can be of any addressable data type known to PL/I. For example:
DECLARE MEMSET ENTRY (ANY, CHAR(1) VALUE,
The first parameter descriptor in the ENTRY attribute specifies that the argument can have any data type and is being passed by reference. When you specify ANY for an argument to be passed by reference, you cannot specify data type attributes. Note that if you specify the VALUE attribute in conjunction with the ANY attribute, PL/I passes the argument by value.
The ANY attribute is especially useful when you must specify a data structure as an argument. You need not declare the structure within the parameter descriptor, only the ANY attribute.
When PL/I passes an argument by reference, it puts either the address of the actual argument or the address of a dummy argument in the argument list of the called procedure. PL/I creates a dummy argument in the following cases:
In the last case of the previous list, PL/I issues an informational or warning message and, for scalar arguments, creates a dummy argument of the data type of the parameter. It places the address of this dummy argument in the argument list. If the argument is an aggregate, PL/I issues an error message and does not create a dummy argument for the array or structure.
In creating a dummy argument, PL/I does the conversions listed in See . Converted Data Types of Arguments Passed by Reference :
In all other cases, the data type of the dummy argument is the same as the data type of the written argument.
When you pass an argument by reference, PL/I puts the address of the actual argument in the argument list. This address can be interpreted as a pointer value. In fact, you can explicitly specify a pointer value as an argument for data to be passed by reference. For example:
DECLARE MEMSET (POINTER VALUE, CHAR(1) VALUE,
When MEMSET is invoked with the following statement at the procedure invocation, PL/I places the pointer value returned by the ADDR built-in function directly in the argument list.
In FORTRAN, you must always pass arrays by reference; the array extents are, by custom, passed as separate arguments. The REFERENCE attribute provides a convenient way to express an array parameter for FORTRAN. For example:
DECLARE SUM ENTRY ((*) FLOAT REFERENCE, FIXED BINARY(31))
SUM is a FORTRAN routine that sums the elements of a one-dimensional array of floating-point numbers. Its second parameter is the number of elements in the array.
When you pass a parameter by value, the PL/I compiler passes a copy of the parameter's value to the routine instead of passing its address. Because only a copy of the parameter's value is passed, the routine does not have access to the storage location of the parameter. Therefore, when you pass a parameter by value, any changes that you make to the parameter value in the called routine do not affect the value of that parameter in the calling routine.
For an argument to be passed by value, you must use the VALUE attribute in a parameter description. The following declaration of the external entry VHF illustrates a declaration for an external routine that receives its parameter by value.
DECLARE VHF ENTRY (FIXED BINARY(31) VALUE);
You can also define PL/I procedures that receive arguments by value. To do this, you must specify the VALUE attribute in the declaration of the parameter. For example, the corresponding definition of the routine VHF would be as follows:
DECLARE LENGTH FIXED BINARY(31) VALUE;
Arguments that can be passed by value are limited to the following data types, which can be expressed in 32 bits:
No other data types can be passed by value. Note that when ENTRY VALUE is specified in a parameter descriptor, only the entry points of external routines may be passed by value. A complete entry value for an internal routine requires two longwords, one for the parent frame and one for the 32-bit entry-point address.
When you specify the VALUE attribute in a parameter descriptor, you can specify the ANY attribute instead of declaring any data type attributes. For example, the declaration of VHF can appear as follows:
DECLARE VHF ENTRY (ANY VALUE);
When the procedure is invoked, PL/I converts the written argument as needed to create a longword dummy argument.
For arguments to be passed by value, PL/I always creates a dummy argument directly in the argument list for the called procedure. If the parameter descriptor is specified with the ANY and VALUE attributes, PL/I creates dummy arguments the data types shown in See . Assignment of Data Type to Dummy Arguments :
If a parameter descriptor is specified as VALUE with a particular data type (as opposed to being specified as ANY), a dummy argument of that data type is always created, and the written argument is assigned to the dummy. The written argument must be valid for conversion to the data type specified in the corresponding parameter descriptor.
PL/I provides the OPTIONS(VARIABLE) option to the ENTRY declaration, and the OPTIONAL and TRUNCATE parameter attributes.
The option and parameter attributes are described in the following sections.
This option is provided for use in calling non-PL/I procedures and can only be used for that purpose. If you declare an external entry with OPTIONS(VARIABLE), you can omit an optional argument and let the compiler pass a zero for the argument. The called procedure usually provides a default value. You must, however, enter the correct number of commas ton ensure that the argument list contains the correct number of longwords.
Some PL/I and non-PL/I routines with fixed-length argument lists accept optional arguments and provide a default action if no value is specified for the optional argument. When an optional argument is not specified, its corresponding argument list longword is filled with a value of zero passed by immediate value.
In PL/I, you can omit the specification of an optional argument in a written argument list as long as you enter the correct number of commas to ensure that the argument list will have the correct number of longwords. You can indicate that you are not specifying an optional argument in either of the following ways:
For example, an argument list that has three optional arguments can be written as follows:
The called procedure must detect and interpret the optional parameters in the argument list. The following example illustrates optional arguments omitted from an argument list:
BIT(1) ALIGNED VALUE OPTIONAL),
This call to the service ASCTIM specifies only the second argument; the argument list contains four arguments. When you specify a null argument, as in the previous example, PL/I always places a zero in the argument list passed to the called procedure.
Some routines may allow an argument list to be truncated in a specified location. For example:
DECLARE GET_INPUT ENTRY (ANY CHARACTER(*),
ANY CHARACTER(*) OPTIONAL TRUNCATE,
FIXED BINARY(15) OPTIONAL TRUNCATE);
This declaration routine (GET_INPUT) specifies that the argument list may vary in length. In fact, GET_INPUT has three parameters, but the last two parameters are optional.
When you invoke such a routine omitting trailing arguments, you do not have to account for all the arguments in the procedure invocation argument list. For example, the GET_INPUT routine can be invoked with trailing arguments omitted:
The variable GET_STRING is specified for the first argument. The other two arguments are not specified.
The basic steps for calling routines are the same whether you are calling a routine written in PL/I, a routine written in some other UNIX language, a system service, a utility routine, or a UNIX Run-Time Library routine. The following sections outline the procedures for calling non-PL/I routines.
Before you call an external routine, you must first determine whether the call should be a procedure call or a function call. You should call a routine as a procedure if it does not return a value. You should call a routine as a function if it returns any type of value.
To call a routine written in another UNIX language, or to call a system routine, you need to declare the routine as an external procedure or function and to declare the data types and passing mechanisms of its arguments. Note that arguments can be either required or optional.
You should include the following information in an external routine declaration:
Once you have declared a routine, you can call it. To call a procedure, you use the CALL statement. To call a function, you can use a function invocation either in an assignment statement or as an argument in another routine call. In either case, you must specify the name of the routine being called and all parameters required for that routine. Make sure the data types and passing mechanisms for the actual parameters you are passing coincide with those you declared earlier, and with those declared in the routine.
If you do not want to specify a value for a required parameter, you can pass a null argument by inserting a comma (,) placeholder in the argument list. If you use any passing mechanism other than the default, you must specify the passing mechanism in the CALL statement or the function call.
At this point, the routine being called receives control, executes, and then returns control to the calling routine at the next statement after the CALL statement or function call.
The following information pertains to the GNU readline and assembler software, used in the Kednos PL/I for UNIX software. The Free Software Foundation supplies the GNU Copyleft, which is provided verbatim in this appendix.
Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a. You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b. You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c. If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
a. Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b. Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c. Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
ONE LINE TO GIVE THE PROGRAM'S NAME AND AN IDEA OF WHAT IT DOES. Copyright (C) 19YY NAME OF AUTHOR This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19YY NAME OF AUTHOR Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. SIGNATURE OF TY COON, 1 April 1989 Ty Coon, President of Vice
This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
using record identification 5-4
Activation records of ON-units 10-13
Aggregates, see Arrays and Structures
located in search for ON-units 10-14, 10-16
APPEND ENVIRONMENT option 6-11
specifying pointer values 11-5
Attributes for file access 5-3
searching for ON-units 10-13, 10-15 to 10-16
as arguments to ENVIRONMENT options 6-2
clear break debugger command 3-26
specifying ENVIRONMENT options 6-1
diagnostic message format 2-18
drivers for other languages 2-4
resignaling a condition 10-1, 10-5 to 10-6
using built-in functions 10-22
Condition Handling Standard support 11-2
assigning values to variables 3-46
DEFAULT_FILE_NAME ENVIRONMENT option 6-12
DELETE ENVIRONMENT option 6-13
describe debugger command 3-29
ENDFILE condition 4-7, 10-23 to 10-24
action by default handler 10-15
ENTRY attribute, declaring non-PL/I routines 11-6
Entry name, as procedure argument 11-6
environment debugger command 3-33
FIXED_LENGTH_RECORDS 6-11, 6-14, 6-16, 6-24
MAXIMUM_RECORD_SIZE 6-17, 6-19
specifying arguments 6-2 to 6-3
Environment, access to data 3-6
action by default handler 10-15
message format in compiler 2-18
F, FB, FS, and FSB ENVIRONMENT options 6-11, 6-14
Fatal severity condition handling 10-15
access modes and PL/I attributes 5-3
reading and writing 5-11 to 5-12, 7-5
signaling ONKEY built-in function 10-24
see also Records, Relative files, Stream files
STOP statement in ON-unit 10-19
FIXED_LENGTH_RECORDS ENVIRONMENT option 5-5, 6-11, 6-14, 6-16, 6-24
overview of RISC ULTRIX features 4-1
I/O statement options 7-2 to 7-3
File environment options 5-5 to 5-6
Main procedure condition handling 10-14
MAXIMUM_RECORD_SIZE ENVIRONMENT option 5-5 to 5-6, 5-9, 6-17, 6-19
ONCODE built-in function 4-8, 10-23
return value global symbol names 10-23
values in KEY ON-unit 4-9, 5-14
ONFILE built-in function 4-8, 10-24
ONKEY built-in function 4-8, 10-24
compared to condition handlers 10-8
referencing global symbols 10-22
passing to non-PL/I routines 11-2
PLIRETC built-in subroutine 9-11
Pointers, passing as arguments 11-5
Reading files 5-4, 5-11 to 5-12
Record Management Services (RMS), condition values 4-9
RECORD_ID_ACCESS ENVIRONMENT option 5-4, 6-19
identification, accessing records by 5-4
register debugger command 3-45
Relative files 5-8 to 5-9, 5-11 to 5-12
RESIGNAL built-in subroutine 10-1, 10-5 to 10-6
SCALARVARYING ENVIRONMENT option 6-20
Search directories, debugger 3-31
Search order for ON-units 10-13, 10-15 to 10-16
SHARED_READ ENVIRONMENT option 6-22
PLIRETC built-in subroutine 9-11
compiler-generated line numbers 2-20
Static data, debugger access to 3-6
STOP statement in ON-unit 10-8
Subroutines for file-handling 8-1
SUPERSEDE ENVIRONMENT option 5-8, 6-22
TEMPORARY ENVIRONMENT option 6-23
displaying prompting message 7-3
UNDEFINEDFILE condition 4-4, 4-7, 10-23 to 10-24
ENVIRONMENT option conflicts 6-3
V, VB, VS, and VSB ENVIRONMENT options 6-24
specifying file title with 4-4
file, specifying title with 4-3
showing values in debugger 3-49
VAXCONDITION condition 10-2, 10-23
What I like best about this manual is
1.
If you do not specify --case upper, do not declare an external symbol that will map to "main" (lowercase). This will conflict with the library function "main" supplied in the Kednos PL/I for UNIX run-time library.
In addition, the file symbols "SYSPRINT", "SYSIN", and "SYSOUT" are always case insensitive regardless of the specified compiler option. In other words, whether you specify "sysprint", "Sysprint", or "SYSPRINT", you will always refer to the pre-declared PL/I files.
2. The default is preserved for compatibility with VAX PL/I. Kednos PL/I for UNIX does not support SEQUENTIAL (record) access to variable length stream files.
4. 512 bytes for sequential files with fixed-length records. For sequential files with variable-length records, the default is 510 bytes. For relative files, the default is 480 bytes.
6. 512 bytes for sequential files with fixed-length records. For sequential files with variable-length records, the default is 510 bytes. For relative files, the default is 480 bytes.