Kednos PL/I for OpenVMS Systems
User Manual


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; 

11.8.6 Using SORT Routines

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:

  1. The definitions for the SORT routines and several groups of constants are included from PLI$STARLET.
  2. The input and output file specifications are character-string arguments, initialized to the logical names INFILE and OUTFILE. INFILE must be equated to a file whose records are no longer than 80 characters.
  3. The key buffer specifies the information required for SOR$BEGIN_SORT.
  4. The SORT routines that are required to sort a file must be invoked in this order:
    1. SOR$PASS_FILES specifies the input and output file specifications. These can be logical names.
    2. SOR$BEGIN_SORT specifies the sizes of the records, key data types, sort sequences, and so forth.
    3. SOR$SORT_MERGE initiates the sorting.
    4. SOR$END_SORT calls SORT to clean up its work areas and close its temporary files.
  5. The procedures are invoked in the order listed in note 1. Each procedure returns its return value to STS$VALUE. If there are errors, the procedure returns with the value of STS$VALUE.

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:

  1. A record sort requires that SORT routines be called in the following order:
    1. SOR$BEGIN_SORT specifies the key data types, record sizes, collating sequence, and so on, in a key buffer area.
    2. SOR$RELEASE_REC passes each record to SORT.
    3. SOR$SORT_MERGE requests SORT to perform the sort on the records it receives.
    4. SOR$RETURN_REC requests SORT to pass a single record back. SORT returns the records in sorted order.
    5. SOR$END_SORT finishes the SORT.
  2. $SSDEF contains the symbol SS$_ENDOFFILE. SORT returns this value when SOR$RETURN_REC requests a record after all records have been returned.
  3. Within the key buffer, the START_POS field indicates that the key field within each record begins in position 25, that is, the capital field (note that this is equivalent to an offset of 24 bytes).
  4. The LONGEST_RECORD variable specifies the value SIZE(STATE_RECORD). This is the length of each record in the file, plus the length of the key on which the records are to be sorted.
  5. The structure STATE_RECORD contains the key field on which the records are to be sorted, as well as the structure declaration of the records in the file STATE_FILE.
  6. STATE_RECORD_CHAR is a character string that overlays the STATE_RECORD structure. It is used to pass records to SOR$RELEASE_REC and to obtain records from SOR$RETURN_REC.
  7. The procedure declares input and output files, and calls SOR$BEGIN_SORT to begin the sorting process.
  8. The records are passed to SOR$RELEASE_REC.
  9. SOR$SORT_MERGE is invoked to perform the merge.
  10. SOR$RETURN_REC returns each record individually, without the key field, to the structure STATE. When there are no more records, SOR$RETURN_REC returns with the function value SS$_ENDOFFILE.
  11. The sort is completed.

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; 


Chapter 12
Global Symbols

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:

12.1 Using Global Symbols in PL/I Procedures

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.

Table 12-1 Comparison of Global Symbols and External Variables
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.

12.1.1 The GLOBALDEF Attribute

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:

12.1.2 The GLOBALREF 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:

12.1.3 Defining Global Symbols in PL/I

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