HP OpenVMS Systems Documentation

Content starts here

HP Pascal for OpenVMS
User Manual

Previous Contents Index

6.2.6 Arbitrary Length Parameter Lists

Some run-time library routines require a variable number of parameters. For example, there is no fixed limit on the number of values that can be passed to functions that return the minimum or maximum value from a list of input parameters. The LIST attribute supplied by HP Pascal allows you to indicate the mechanism by which excess actual parameters are to be passed. For example:


Because the function MTH$DMIN1 returns the D_floating minimum of an arbitrary number of D_floating parameters, the formal parameter EXTRA_PARAMS is declared with the LIST attribute. All actual parameters must be double-precision real numbers passed by reference with value semantics.

For More Information:

On the LIST attribute (HP Pascal for OpenVMS Language Reference Manual)

6.3 Calling System Routines

All system routines are functions that return an integer condition value; this value indicates whether the function executed successfully. An odd-numbered condition value indicates successful completion; an even-numbered condition value indicates a warning message or failure. Your program can use the
HP Pascal predeclared function ODD to test the function return value for success or failure. For example:

IF NOT ODD ($BINTIM(Ascii_Time,Binary_Time))
      WRITELN('Illegal format for time string');

In addition, run-time library routines return one or two values: the result of a computation or the routine's completion status, or both. When the routine returns a completion status, you should verify the return status before checking the result of a computation. You can use the function ODD to test for success or failure or you can check for a particular return status by comparing the return status to one of the status codes defined by the system. For example:

   Seed_Value  : INTEGER;
   Rand_Result : REAL;

{In the executable section:}
Rand_Result := MTH$RANDOM (Seed_Value);

When the routine's completion status is irrelevant, your program can treat the function as though it were an external procedure and ignore the return value. For example, your program can declare the Hibernate (SYS$HIBER) system service as a function but call it as though it were a procedure:

{In the executable section:}
$HIBER; { Put process to sleep }

Because SYS$HIBER is expected to execute successfully, the program will ignore the integer condition value that is returned.

6.4 Using Attributes

When writing programs that use OpenVMS System Services and run-time library routines, it is common to use several HP Pascal attributes.

The VOLATILE attribute indicates that a variable is written or read indirectly without explicit program action. The most common occurrence for this is with item lists. In that case, the address of the variable is placed in the item list (most likely using the IADDRESS routine). This address is then used later when the entire item list is passed to a system service. Without the VOLATILE attribute, the compiler does not realize that the call to the system service or run-time library routine uses the variable.

The UNBOUND attribute designates a routine that does not have a static link available to it. Without a static link, a routine can only access local variables, parameters, or statically allocated variables. System services that require AST or action routines want the address of an UNBOUND routine. Routines at the outer level of a PROGRAM or MODULE are UNBOUND by default.

The ASYNCHRONOUS attribute designates a routine that might be called asynchronously of any program action. This allows the compiler to verify that the asynchronous routine only accesses local variables, parameters, and VOLATILE variables declared at outer levels. Without the assurance that only VOLATILE variables are used, the asynchronous routine might access incorrect data, or data written by the routine will not be available to the main program.

6.5 Using Item Lists

Many OpenVMS system services use item lists. Item lists are sequences of control structures that provide input to the system service and that describe where the service should place its output. These item lists can have an arbitrary number of cells and are terminated with a longword of value 0.

Since different programs need a different number of item list cells, you can use a schema type to define a generic item list data type. This schema type can then be discriminated with the appropriate number of cells. Consider the following example:

   Item_List_Cell = RECORD
         1: (    { Normal Cell }
              Buffer_Length : [WORD] 0..65535;
              Item_Code     : [WORD] 0..65535;
              Buffer_Addr   : UNSIGNED;
              Return_Addr   : UNSIGNED
         2: (    { Terminator }
              Terminator    : UNSIGNED
   Item_List_Template( Count : INTEGER ) =
      ARRAY [1..Count] OF Item_List_Cell;

The Item_List_Cell data type specifies what a single cell looks like. The Buffer_Addr and Return_Addr fields are declared as UNSIGNED since most applications use the IADDRESS predeclared routine to fill them in. The Item_List_Template schema type defines an array of item list cells with a upper bound to be filled in by an actual discriminant.

To use this schema type, first determine the number of item list cells required including one cell for the terminator. After the number of cells has been determined, declare a variable discriminating the schema. Consider the following example:

   Item_List : Item_List_Template( 2 );

Additionally, since actual discriminants to schema can be run-time expressions, you can write a routine that can have item lists with a number of cells that is determined at run time.

After the item list variable has been declared, each cell must be filled in according to the system service and operation requested.

Consider the following example using the SYS$TRNLNM system service:

   Item_List       : Item_List_Template( 2 );
   Translated_Name : [VOLATILE] VARYING [132] OF CHAR;

   {Specify the buffer to return the translation:}
   Item_List[1].Buffer_Length   := SIZE( Translated_Name.BODY );
   Item_List[1].Item_Code       := LNM$_String;
   Item_List[1].Buffer_Addr     := IADDRESS( Translated_Name.BODY );
   Item_List[1].Return_Addr     := IADDRESS( Translated_Name.LENGTH);

   { Terminate the item list:}
   Item_List[2].Terminator      := 0;

The VAR section declares an item list with two cells. It also declares an output buffer for the system service. The VOLATILE attribute is used since the call to SYS$TRNLNM indirectly writes into the variable. The first cell is filled in with the operation desired, the size of the output buffer, the location to write the result, and the location to write the size of the result.

Using the SIZE predeclared function prevents the code from having to be modified if the output buffer ever changes size. Using the BODY and LENGTH predeclared fields of the VARYING string allows the system service to construct a valid VARYING OF CHAR string. Finally, the second cell of the item list is initialized. Since the second cell is the last cell, the terminator field must be filled in with a value of 0.

6.6 Using Foreign Mechanism Specifiers on Actual Parameters

The definition files provided by HP Pascal (SYS$LIBRARY:STARLET.PAS and so forth) are created from a generic description language used by the OpenVMS operating system. Since this description language does not contain all the features found in HP Pascal, some of the translations do not take advantage of HP Pascal features. Also, since several of the system services are generic in nature, it is impossible to provide a definitive definition for every situation.

If a formal parameter definition does not reflect the current usage, you can use a foreign mechanism specifier to direct the compiler to use a different passing mechanism or different descriptor type than the default for that parameter.

Consider the following:

  • ASTADR parameter
    Many system services define this parameter to be a procedure parameter with no formal parameters. This is because the format of the arguments passed to the AST routine vary with the system service. If you specify a routine with parameters as the actual parameter to an ASTADR parameter, you will receive a compile-time error saying that the formal parameter and actual parameter have different parameter lists. To solve this problem, you can specify the %IMMED foreign mechanism specifier on the actual parameter. This causes the compiler to pass the address of the routine without verifying that the parameter lists are identical.
  • ASTPRM parameter
    Many system services define this parameter to be an UNSIGNED parameter passed by immediate value. Since the parameter to an AST routine is dependent on the application, it is often desired to pass the address of a variable instead of its contents. To solve this problem, you can specify the %REF foreign mechanism specifier on the actual parameter. This causes the compiler to pass the address of the variable instead of the contents of the variable.
  • P1..Pn parameters
    The P1 through P6 parameters of the $QIO and $QIOW system services and the P1 through P20 parameters of the $FAO system services are also defined to be UNSIGNED parameters passed by immediate value. If the actual parameter is not UNSIGNED or requires a different passing mechanism, you can specify the %REF foreign mechanism specifier on the actual parameter. This causes the compiler to pass the address of the variable instead of the contents of the variable.
  • RESULTANT_FILESPEC parameter of the LIB$FIND_FILE run-time library routine
    This parameter is declared to be a VAR conformant PACKED ARRAY OF CHAR parameter and is passed by a CLASS_A descriptor. However, the LIB$FIND_FILE routine can also accept CLASS_VS descriptors of VARYING OF CHAR variables. To cause the compiler to build a CLASS_VS descriptor instead of the default CLASS_A descriptor, you can specify the %DESCR foreign mechanism specifier on the actual VARYING OF CHAR parameter.

6.7 Using 64-Bit Pointer Types

HP Pascal on OpenVMS I64 and OpenVMS Alpha systems includes limited support for 64-bit pointers.

64-bit pointers can be declared by using the [QUAD] attribute on a pointer variable declaration. When [QUAD] is used, the generated code will use all 64 bits of the pointer.

6.7.1 Pascal Language Features Not Supported with 64-Bit Pointers

Several Pascal features are not supported with 64-bit pointers. These features are:

  • Base types of 64-bit pointers cannot contain file types or schema types.
  • The READ built-in routine cannot read into variables accessed with 64-bit pointers. For example, the following code fragment will be rejected by the compiler:

    var quad_ptr : [quad] ^integer;
    quad_ptr := my_alloc_routine(size(integer));
  • Strings allocated in P2 address space cannot be used with the READV or WRITEV predeclared routines.
  • HP Pascal understands 32-bit descriptors as defined by the OpenVMS calling standard. Therefore, any HP Pascal construct that relies on descriptors is not supported for variables accessed with 64-bit pointers. The features rejected for 64-bit pointers are:
    • The use of %DESCR or %STDESCR on actual parameter values accessed with 64-bit pointers. For example, you cannot do the following:

        s32 = packed array [1..32] of char;
        qp : [quad] ^s;
        qp := my_alloc_routine(size(s32));
        some_routine( %stdescr qp^ );
    • Passing variables accessed with 64-bit pointers to formal parameters declared with %DESCR or %STDESCR foreign mechanism specifiers.
    • Passing variables accessed with 64-bit pointers to conformant array or conformant varying parameters.
    • Passing variables accessed with 64-bit pointers to STRING parameters.
    • At run time, the compiler will generate incorrect code when passing a VAR parameter that is accessed with a 64-bit pointer to a parameter that requires a descriptor. The generated code will build the descriptor with the lower 32-bits of the 64-bit address. For example:

          s32 = packed array [1..32] of char;
          qp : [quad] ^s;
      procedure a( p : packed array [l..u:integer] of char );
      procedure b( var p : s32 );
        a(p);   { This will generate a bad descriptor }
      qp := my_alloc_routine(size(s32));

6.7.2 Using 64-Bit Pointers with System Definition Files

For routines that have parameters that are 64-bit pointers, the Pascal definition uses a 64-bit record type. The definition files do not support either the INTEGER64 datatype or 64-bit pointers.

You can override the formal definition inside of definition files by using a foreign mechanism specifier (that is, %IMMED, %REF, %STDESCR, and %DESCR) on an actual parameter.

For example, the following is an example of calling lib$get_vm_64 using %ref to override the definition from PASCAL$LIB_ROUTINES.PEN:

program p64(input,output);

     arr_size = (8192 * 10) div 4; ! Make each array be 10 pages

     arr = array [1..arr_size] of integer;
     arrptr = [quad] ^arr;

     ptr : arrptr;
     ptrarr : array [1..10] of arrptr;
     i,j,stat : integer;
     sum : integer64;

!  PASCAL$LIB_ROUTINES.PAS on a V7.1 system contains
!  the following definitions for LIB$GET_VM_64
!                L0:UNSIGNED; L1:INTEGER; END;
!                L0,L1:UNSIGNED; END;
!     lib$routines$$typ4 = ^$QUAD;
![ASYNCHRONOUS] FUNCTION lib$get_vm_64 (
!        number_of_bytes : $QUAD;
!        VAR base_address : [VOLATILE] lib$routines$$typ4;
!        zone_id : $UQUAD := %IMMED 0) : INTEGER; EXTERNAL;
! Note that the BASE_ADDRESS parameter is a 64-bit pointer
! that will be returned by LIB$GET_VM_64.  The definition
! incorrectly declared it as a pointer to a record that is
! quadword sized.


! Allocate memory with lib$get_vm_64.  The definition of
! lib$get_vm_64 declares the return address parameter as
! a quadword-sized record since it doesn't have sufficient
! information to generate a INTEGER64 or other type.
! Use an explicit '%ref' foreign mechanism specifier to
! override the formal parameter's type definition and pass
! our pointer to lib$get_vm_64.

writeln('arr_size = ',arr_size:1);
for i := 1 to 10 do
  stat := lib$get_vm_64( size(arr), %ref ptrarr[i] );
  if not odd(stat)
     writeln('Error from lib$get_vm_64: ',hex(stat));
  writeln('ptrarr[',i:1,'] = ',hex(ptrarr[i]));

! Read/write all the memory locations to get some page faults
writeln('Initialize all memory');
for i := 1 to 10 do
  for j := 1 to arr_size do
    ptrarr[i]^[j] := i + j;

sum := 0;
writeln('Add up all memory in reverse direction');
for i := 10 downto 1 do
  for j := arr_size downto 1 do
    sum := sum + ptrarr[i]^[j];
writeln('Sum of array contents = ',sum:1);


On OpenVMS I64 and OpenVMS Alpha systems, the compiler allows the LONG and QUAD attributes to be specified on pointer types, as shown in the following example:

 var long_ptr : ^integer;
      quad_ptr : [quad] ^integer;

Both pointers point to integers, but long_ptr is 32 bits while quad_ptr is 64 bits.

Chapter 7
Input and Output Processing

This chapter provides details on the input/output (I/O) support provided for OpenVMS systems and discusses the following topics:

7.1 Environment I/O Support

HP Pascal uses the Record Management Services (RMS) to perform I/O tasks at the system level. In this environment, all of the HP Pascal I/O model is supported; the model is based on RMS concepts. If these sections contain no information on a concept or element in the HP Pascal I/O model, then this environment supports the concept or element exactly as it is described in the HP Pascal for OpenVMS Language Reference Manual.

You can use RMS features through HP Pascal when you call the OPEN procedure. For instance, when you call this procedure, you can specify the file organization, the component format, and the access method.

If you choose to use additional features of RMS that are not available in the HP Pascal I/O model, you can write a user-action function that manipulates the RMS control blocks: the file access block (FAB), the record access block (RAB), and the extended attribute block (XAB). Once you write the user-action function, you pass the function name as a parameter to the OPEN procedure.

For More Information:

  • On user-action functions ( Section 7.2)
  • On OPEN defaults ( Section
  • On OPEN and the HP Pascal I/O model (HP Pascal for OpenVMS Language Reference Manual)
  • On RMS concepts (Guide to OpenVMS File Applications)
  • On the user interface to RMS (OpenVMS Record Management Services Reference Manual)

7.1.1 Indexed Files

The HP Pascal I/O model allows you to use most of the features of RMS indexed files. However, if you wish to use segmented or null keys, you must write a user-action function.

When an existing indexed file is opened, the run-time library compares the keys in the file against the KEY attributes specified in the program. If no KEY attribute was specified for the corresponding key in the indexed file, then the comparison is bypassed and the open continues. The run-time library compares the position and the data type of the file's keys against the KEY attributes specified. If the KEY attribute explicitly specifies a collating sequence (ASCENDING or DESCENDING), then the specified sequence must match that of the key in the file. If no sequence is specified, either sequence is allowed. The CHANGES and DUPLICATES options are not checked.

For More Information:

  • On user-action functions ( Section 7.2)
  • On the OPEN procedure ( Section 7.1.6)
  • On indexed file organization and the KEY attribute (HP Pascal for OpenVMS Language Reference Manual)

7.1.2 OpenVMS Components and RMS Records

In the HP Pascal I/O model, data items in a file are called components. In RMS, these items are called records.

7.1.3 Count Fields for Variable-Length Components

Each variable-length component contains a count field as a prefix. This count field contains the number of bytes in the rest of the component. For files on tape, this count field is 4 bytes in length; for files on disk, this count field is 2 bytes in length.

7.1.4 Variable-Length with Fixed-Length Control Field (VFC) Component Format

The HP Pascal I/O model does not provide a direct means to create files of variable-length components with fixed-length control fields (VFC). If you open a file of this component format, HP Pascal treats the file like a file of variable-length components. If you want to create files of this component format, you must write a user-action function.

For More Information:

  • On user-action functions ( Section 7.2)
  • On VFC components (Guide to OpenVMS File Applications)

7.1.5 Random Access by Record File Address (RFA)

The HP Pascal I/O model does not allow random access by record file address. If you want to use this type of access, you must write a user-action function.

RMS supports random access by Record File Address (RFA) for relative and indexed files, and for sequential files only on disk. The RFA is a unique number supplied for files on disk. The RFA remains constant as long as the record is in the file. RMS makes the RFA available to your program every time the record is stored or retrieved. Your program can either ignore the RFA or it can keep it as a random-access pointer to the record for subsequent accesses.

If your disk file is sequential with variable-length records, the RFA provides the only method for randomly accessing records of that file.

For More Information:

  • On user-action functions ( Section 7.2)
  • On RFA (Guide to OpenVMS File Applications)

7.1.6 OPEN Procedure

When you use the OPEN procedure, RMS applies default values for OpenVMS file specifications, and assigns values to FAB, RAB, XAB, and Name Block data structures.

Previous Next Contents Index