Previous | Contents | Index |
Example 11-11 Calling SYS$GETJPI (AXP) |
---|
TIME: PROCEDURE OPTIONS (MAIN); %INCLUDE SYS$GETJPI; /* * INCLUDE definitions required by SYS$GETJPI */ %INCLUDE $JPIDEF; /* item codes */ (1) %INCLUDE $SSDEF; /* System (SS$_*) status values */ %INCLUDE $STSDEF; /* status value variable */ DECLARE 1 JPI_LIST STATIC EXTERNAL, (2) 2 JPI_BUFIO, /* Buffered I/O count */ 3 LENGTH FIXED BIN(15) INITIAL(4), 3 ITMCOD FIXED BIN(15) INITIAL(JPI$_BUFIO), (3) 3 BUFADR POINTER INITIAL(NULL()), 3 RETLEN POINTER INITIAL(NULL()), 2 JPI_CPUTIM, /* CPU time */ 3 LENGTH FIXED BIN(15) INITIAL(4), 3 ITMCOD FIXED BIN(15) INITIAL(JPI$_CPUTIM), (3) 3 BUFADR POINTER INITIAL(NULL()), 3 RETLEN POINTER INITIAL(NULL()), 2 JPI_DIRIO /* Direct I/O count */ 3 LENGTH FIXED BIN(15) INITIAL(4), 3 ITMCOD FIXED BIN(15) INITIAL(JPI$_DIRIO), (3) 3 BUFADR POINTER INITIAL(NULL()), 3 RETLEN POINTER INITIAL(NULL()), 2 JPI_PAGEFLTS /* Page faults */ 3 LENGTH FIXED BIN(15) INITIAL(4), 3 ITMCOD FIXED BIN(15) INITIAL(JPI$_PAGEFLTS), (3) 3 BUFADR POINTER INITIAL(NULL()), 3 RETLEN POINTER INITIAL(NULL()), 2 ENDLIST FIXED BIN(31) INITIAL(0); DECLARE (TO,CLOCK_TIME) FLOAT BIN(24) STATIC EXTERNAL, (4) (BUFIO,END_BUFIO,CPUTIM,END_CPUTIM,DIRIO, END_DIRIO,PAGEFLTS,END_PAGEFLTS) FIXED BIN(31) STATIC EXTERNAL, CPUSECONDS FLOAT BIN(24); DECLARE DFOR$SECNDS ENTRY (FLOAT BIN(24)) RETURNS(FLOAT BIN(24)); TIMRE: ENTRY; JPI_BUFIO.BUFADR = ADDR(END_BUFIO); (5) JPI_CPUTIM.BUFADR = ADDR(END_CPUTIM); JPI_DIRIO.BUFADR = ADDR(END_DIRIO); JPI_PAGEFLTS.BUFADR = ADDR(END_PAGEFLTS); IF SYS$GETJPIW(,,,JPI_LIST,,,)^=SS$_NORMAL (6) THEN PUT SKIP LIST ('Error from SYS$GETJPI'); CLOCK_TIME = DFOR$SECNDS(TO); CPUSECONDS = (END_CPUTIM-CPUTIM)/100E0; BUFIO = END_BUFIO-BUFIO; (7) DIRIO = END_DIRIO-DIRIO; PAGEFLTS = END_PAGEFLTS-PAGEFLTS; PUT SKIP EDIT ('Times in seconds','Page','Direct','Buffered') (A(20),A(10),A(10),A(10)); PUT SKIP EDIT ('CPU','Elapsed','Faults','I/O','I/O') (A(10),A(10),A(10),A(10),A(10)); PUT SKIP EDIT (CPUSECONDS,CLOCK_TIME,PAGEFLTS,DIRIO,BUFIO) (F(7,1),COLUMN(11),F(9,1),COLUMN(21),F(7,0),COLUMN(31), F(7,0),COLUMN(41),F(7,0)); /* * After calling TIMRE, fall through here to reinitialize. */ TIMRB: ENTRY; (8) TO = DFOR$SECNDS(0E0); JPI_BUFIO.BUFADR = ADDR(BUFIO); (5) JPI_CPUTIM.BUFADR = ADDR(CPUTIM); JPI_DIRIO.BUFADR = ADDR(DIRIO); JPI_PAGEFLTS.BUFADR = ADDR(PAGEFLTS); IF SYS$GETJPIW(,,,JPI_LIST,,,)^=SS$_NORMAL THEN PUT SKIP LIST ('Error from SYS$GETJPI'); RETURN; END TIME; |
Example 11-12 shows a sample procedure that calls the SORT routines to perform an alphabetic sort on a file. The following notes are keyed to Example 11-12:
Example 11-12 Sorting Files |
---|
/* * Sort a file */ SORTEM: PROCEDURE RETURNS(FIXED BINARY(31)); /* * Include the declarations of the SORT procedures required * for a sort using the file interface. */ %INCLUDE SOR$PASS_FILES; /* SORT File Spec Procedure */ (1) %INCLUDE SOR$BEGIN_SORT; /* SORT Init Procedure */ %INCLUDE SOR$SORT_MERGE; /* Procedure to Initiate Sort */ %INCLUDE SOR$END_SORT; /* Sort Termination Procedure */ /* * Include constants and return status variable. */ %INCLUDE $DSCDEF; /* Include data type definitions */ %INCLUDE $FABDEF; /* FAB declarations */ %INCLUDE $STSDEF; /* Declarations for return status value */ /* * Additional constants not currently available in PLI$STARLET. * (SORT constants described in the SOR$BEGIN_SORT documentation.) */ %REPLACE ASCENDING_ORDER BY 0; %REPLACE DESCENDING_ORDER BY 1; /* * Declare the input and output files; these are logical names * which must be defined before the program is run. */ DECLARE INPUT_FILE CHARACTER(6) STATIC INIT('INFILE'), (2) OUTPUT_FILE CHARACTER(7) STATIC INIT('OUTFILE'); /* * Declare the key buffer array required to sort the first 80 * characters of any record. (Note that while the SORT documentation * describes this as an array, it is more obviously expressed in * PL/I as a structure. An array of FIXED BIN(15) elements could * be used instead.) */ DECLARE 1 KEY_BUFFER STATIC, 2 NUMBER_OF_KEYS FIXED BINARY(15) INIT(1), (3) 2 KEY_TYPE FIXED BINARY(15) INIT(DSC$K_DTYPE_T), /* character */ 2 KEY_ORDER FIXED BINARY(15) INIT(ASCENDING_ORDER), 2 START_POS FIXED BINARY(15) INIT(0), 2 KEY_LENGTH FIXED BINARY(15) INIT(80), LONGEST_RECORD FIXED BINARY(15) STATIC INIT(80); /* * Call the SORT routines in the required order. (4) * After each call to SORT, check STS$SUCCESS. */ STS$VALUE = SOR$PASS_FILES( INPUT_FILE, /* Input file name */ OUTPUT_FILE, /* Output file name */ FAB$C_REL, /* File organization */ FAB$C_VAR); /* Record type */ IF ^STS$SUCCESS THEN GOTO ERROR; STS$VALUE = SOR$BEGIN_SORT(KEY_BUFFER,LONGEST_RECORD); IF ^STS$SUCCESS THEN GOTO ERROR; STS$VALUE = SOR$SORT_MERGE(); IF ^STS$SUCCESS THEN GOTO ERROR; STS$VALUE = SOR$END_SORT(); IF ^STS$SUCCESS THEN GOTO ERROR; RETURN(1); ERROR: (5) PUT SKIP(2) EDIT ('SORT Failed. Error Code',STS$VALUE) (A,X,F(8)); RETURN(STS$VALUE); END SORTEM; |
Example 11-13 shows a procedure that performs a record sort, processing each record before passing it to the SORT program. The following notes are keyed to Example 11-13:
Example 11-13 A Record Sort |
---|
/* * This progam sorts the file STATE_FILE based on the field CAPITAL.NAME * in each record. Logical name equivalences are required for the input * file STATE_FILE and an output file SORTED_FILE. */ STATESORT: PROCEDURE OPTIONS(MAIN) RETURNS(FIXED BINARY(31)); /* * Declare SORT routine */ %INCLUDE $DSCDEF; /* Include data type definitions */ %INCLUDE SOR$BEGIN_SORT; /* SORT init procedure */ (1) %INCLUDE SOR$RELEASE_REC; /* SORT procedure to send records */ %INCLUDE SOR$SORT_MERGE; /* Procedure to initiate SORT */ %INCLUDE SOR$RETURN_REC; /* SORT procedure to retrieve records */ %INCLUDE SOR$END_SORT; /* SORT termination procedure */ %INCLUDE $STSDEF; /* Declare return status values */ %INCLUDE $SSDEF; /* Status codes */ (2) DECLARE EOF BIT(1) INIT('0'B); /* * Key buffer and data for SORT routines */ DECLARE 1 KEY_BUFFER STATIC, 2 NUMBER_OF_KEYS FIXED BINARY(15) INIT(1), 2 KEY_TYPE FIXED BINARY(15) INIT(DSC$K_DTYPE_T), /* char keys */ 2 KEY_ORDER FIXED BINARY(15) INIT(0), /* ascending order */ 2 START_POS FIXED BINARY(15) INIT(24), (3) 2 KEY_LENGTH FIXED BINARY(15) INIT(20), LONGEST_RECORD FIXED BINARY(15) (4) INIT(SIZE(STATE_RECORD)); /* * Declare a buffer to construct each record to be passed to SORT */ DECLARE 1 STATE_RECORD STATIC, /* complete record */ (5) 3 NAME CHARACTER(20), 3 POPULATION FIXED BINARY(31), 3 CAPITAL, 4 NAME CHARACTER(20), 4 POPULATION FIXED BINARY(31), 3 LARGEST_CITIES(2), 4 NAME CHARACTER(30), 4 POPULATION FIXED BINARY(31), 3 SYMBOLS, 4 FLOWER CHARACTER(30), 4 BIRD CHARACTER(30), STATE_RECORD_CHAR CHARACTER(SIZE(STATE_RECORD)) (6) BASED(ADDR(STATE_RECORD)); /* * Input and output files */ DECLARE STATE_FILE FILE INPUT RECORD SEQUENTIAL, SORTED_FILE FILE RECORD OUTPUT SEQUENTIAL; (7) /* * Call SOR$BEGIN_SORT */ STS$VALUE = SOR$BEGIN_SORT(KEY_BUFFER,LONGEST_RECORD); IF ^STS$SUCCESS THEN RETURN(STS$VALUE); /* * Enter DO-loop to read the input file STATE_FILE. * Then call SOR$RELEASE_REC. */ OPEN FILE(STATE_FILE); ON ENDFILE(STATE_FILE) EOF = '1'B; READ FILE(STATE_FILE) INTO(STATE_RECORD); DO WHILE (^EOF); STS$VALUE = SOR$RELEASE_REC( (8) STATE_RECORD_CHAR); IF ^STS$SUCCESS THEN RETURN(STS$VALUE); READ FILE(STATE_FILE) INTO(STATE_RECORD); END; CLOSE FILE(STATE_FILE); PUT SKIP LIST('**** ALL RECORDS RELEASED'); /* * Call SOR$SORT_MERGE to sort the records that were released */ STS$VALUE = SOR$SORT_MERGE(); (9) IF ^STS$SUCCESS THEN RETURN(STS$VALUE); /* * Loop through the DO-group to get back each record and * write it to the sorted output file. */ STS$VALUE = 1; OPEN FILE(SORTED_FILE) OUTPUT; DO WHILE (STS$VALUE ^=SS$_ENDOFFILE); STS$VALUE = SOR$RETURN_REC(STATE_RECORD_CHAR); (10) IF STS$SUCCESS THEN WRITE FILE(SORTED_FILE) FROM(STATE_RECORD); ELSE IF ^STS$SUCCESS & (STS$VALUE ^= SS$_ENDOFFILE) THEN RETURN(STS$VALUE); END; CLOSE FILE(SORTED_FILE); /* * Call SOR$END_SORT to finish up */ STS$VALUE = SOR$END_SORT(); (11) IF ^STS$SUCCESS THEN RETURN(STS$VALUE); RETURN(1); /* successful completion */ END; |
In standard PL/I, a variable that is to be shared by external procedures must be declared with the EXTERNAL attribute in each procedure that references it. Kednos PL/I provides an alternative method for defining external variables. Using the GLOBALDEF attribute, one module can completely declare an external variable; all other modules that reference the variable declare it with the GLOBALREF attribute. The VALUE and READONLY attributes provide additional control over the storage of these variables.
Even if a PL/I program does not itself define external variables in this way, the GLOBALREF attribute permits a PL/I program to access variables defined in modules written in other languages.
This chapter discusses the following topics:
Within your PL/I programs, you can define variables as global external symbols when you are coding calls to system procedures. You can also use global symbols instead of external variables in PL/I procedures and functions.
Table 12-1 summarizes the differences between global symbols and external variables. Note that a primary difference between these variables is the manner in which the linker allocates storage for them. Linker storage allocation is described in Chapter 15.
Global Symbols | External Variables |
---|---|
Declared with the GLOBALDEF and GLOBALREF attributes. | Declared with the EXTERNAL attribute. |
Can be initialized only in the module that defines it with the GLOBALDEF attribute. All other modules must specify GLOBALREF. | Must be declared with the EXTERNAL attribute in all modules that declare it. If initialized, must be initialized with the same value in all modules that declare it. |
Correspond to global symbols declared in assembly language. | Correspond to FORTRAN common blocks. |
Fixed-point binary or bit string (less than 33 bits) global symbols can have the VALUE attribute. | Cannot have the VALUE attribute. |
No practical limit on the number of global symbols that can be defined and referenced in an object module. | Limited to 254 external variables in an object module (minus the number of external file constants). |
Allocation of storage can be controlled by explicit specification of a program section name. | No control over storage allocation. Each variable is placed in a separate program section. |
The GLOBALDEF attribute declares an external variable or an external file constant. You can optionally control the program section in which the data is allocated.
The format of the GLOBALDEF attribute is as follows:
GLOBALDEF [ (psect-name) ] |
psect-name
Specifies the name of a program section. A program section name can contain up to 31 alphanumeric characters, including dollar signs ($) and underscores (_). The first character cannot be a numeric character (0 through 9).If you do not specify a program section name, PL/I places the definition for the name in the default program section associated with the variable. For information on program sections created by PL/I, see Chapter 15.
The GLOBALDEF attribute implies the EXTERNAL and STATIC attributes.
The following restrictions apply to the use of the GLOBALDEF attribute:
The GLOBALREF attribute indicates that the declared name is a global symbol defined in an external procedure.
The GLOBALREF attribute implies the EXTERNAL and STATIC attributes. The corresponding name must be declared in another procedure with the GLOBALDEF attribute or, if the external procedure is written in another programming language, its equivalent in that language.
The following restrictions apply to the use of the GLOBALREF attribute:
To create a global symbol definition in a PL/I program, you must declare it with the GLOBALDEF attribute in one, and only one, PL/I external procedure. The GLOBALDEF attribute implies the EXTERNAL attribute.
An external variable defined with the GLOBALDEF attribute can be accessed by external procedures that declare the name with the GLOBALREF attribute. For example, the procedure ABC contains the following lines:
ABC: PROCEDURE; DECLARE UNIQUE_VALUE GLOBALDEF FIXED BINARY INITIAL (60); DECLARE XYZ EXTERNAL ENTRY (CHARACTER (*)); . . . CALL XYZ ('STRING'); |
The procedure XYZ contains the following lines:
XYZ: PROCEDURE (STRING_VAL); DECLARE UNIQUE_VALUE GLOBALREF FIXED BINARY; . . . |
In these examples, the external variable
UNIQUE_VALUE is declared with the GLOBALDEF attribute and initialized
in the procedure ABC. The called external procedure XYZ declares this
variable with the attribute GLOBALREF and the appropriate data type
attributes.
12.1.4 Using MACRO Global Symbols with Multiple Definitions
Using the VAX MACRO programming language, it is possible to give a
global external variable more than one name. However, in a PL/I
procedure, you can use only one global symbol name for a particular
variable. PL/I assumes that distinct global symbol names denote
distinct storage locations; the storage associated with different names
must not overlap. This rule applies only to global symbols that are
declared without the VALUE attribute.
12.2 The READONLY and VALUE Attributes
Kednos PL/I defines two storage class attributes that are not in the
standard PL/I language: READONLY and VALUE. The READONLY attribute can
be specified for any static variable. The VALUE attribute can be
specified only for variables that are declared with the GLOBALREF or
GLOBALDEF attributes. You cannot declare a variable with both the
READONLY and VALUE attributes.
12.2.1 The READONLY Attribute
The READONLY attribute can be applied to any static variable whose value will not change during the program execution. For example, you can initialize fixed values with the PL/I attributes STATIC and INITIAL, and use the READONLY attribute as in this example:
DECLARE MSG_TEXT CHARACTER(80) STATIC READONLY INITIAL ('Good morning'); |
This use of the READONLY attribute provides storage optimization and
protects variables from inadvertent modification.
12.2.2 The VALUE Attribute
A variable declared with the VALUE attribute does not require an address reference in storage; instead, the compiler can refer to it by value during execution.
When you give a variable the VALUE attribute, you must specify either GLOBALDEF or GLOBALREF. If you specify GLOBALDEF, you must use the INITIAL attribute to define a value for the variable.
For example, the VALUE attribute can be specified in the declaration of an external global symbol, as follows:
DECLARE REQUEST_CODE GLOBALDEF VALUE FIXED BINARY STATIC INITIAL (10); |
The variable REQUEST_CODE in this example can be accessed in any external procedure that declares it with the attribute GLOBALREF.
When the VALUE attribute is used with the GLOBALDEF or GLOBALREF attributes, the following rules apply:
A variable declared with the VALUE attribute can be specified as a value to initialize another variable; it must have the same data type as the variable that is being initialized. For example:
DECLARE TEMP GLOBALDEF FIXED VALUE INITIAL(10), ABC FIXED STATIC INIT(TEMP); |
The declaration of ABC in this example gives ABC the value 10.
Previous | Next | Contents | Index |