Document revision date: 30 March 2001

## Guide to Creating OpenVMS Modular Procedures

Previous | Contents | Index

### 2.4.2 Using Event Flags

Event flags allow modular procedures to communicate with each other and to synchronize their operations. Because they can be allocated at run time, event flags allow one procedure to run independently of other procedures existing in the same process.

Event flags are allocated and deallocated by the run-time library procedures LIB$GET_EF and LIB$FREE_EF. (For more information, see the descriptions of the LIB$GET_EF and LIB$FREE_EF procedures in the OpenVMS Programming Concepts Manual and the OpenVMS RTL Library (LIB$) Manual.)

### 2.4.3 Using Logical Unit Numbers

A logical unit number is used to define either the device or file a program uses to perform input and output. Modular procedures do not need to know the unit numbers of other procedures running at the same time.

Logical unit numbers are used only in BASIC and FORTRAN.

Logical unit numbers should be allocated and deallocated using the LIB$GET_LUN and LIB$FREE_LUN RTL procedures. (For more information about using logical unit numbers, see the descriptions of the LIB$GET_LUN and LIB$FREE_LUN procedures in the OpenVMS Programming Concepts Manual and the OpenVMS RTL Library (LIB$) Manual.)

## 2.5 Using Input/Output

In general, your procedure's input/output (I/O) is directed to either the terminal or a file. (In some cases, you may need to use mailbox I/O and network operations. For information about these areas, see the DECnet for OpenVMS Networking Manual.) Regardless of whether you are directing input/output to the terminal screen or to a file, you must follow two rules to maintain modularity:

1. A procedure must not print error or informational messages either directly or by calling the $PUTMSG system service. It must either return a condition value in R0 as a function value, or call LIB$SIGNAL or LIB$STOP to output all messages. (LIB$SIGNAL and LIB$STOP can be called either directly or indirectly.)
2. A procedure should use device-independent services and procedures for input/output.

### 2.5.1 Terminal Input/Output

The methods available for performing input/output to the terminal include the following:

- Queue I/O Request system service ($QIO)
  Using a $QIO to perform terminal I/O is very efficient. However, $QIOs use device-dependent services and are the most difficult to use from high-level languages of all methods discussed here, because there are more steps involved and because the calling interface requires more knowledge from the caller than RMS services. Using a $QIO in your procedure may require additional steps, such as constructing item lists, writing AST routines, assigning an I/O channel, queueing an I/O request, testing to ensure that the request was successfully queued and completed, and deassigning the I/O channel. (For more information about $QIOs, see the OpenVMS System Services Reference Manual.)
- OpenVMS Record Management Services (RMS)
  The RMS facility provides device-independent and general-purpose services that are easier to call than $QIOs. However, it is often not convenient to construct the access control blocks (FAB, RAB, and so forth) required by RMS from a high-level language. (For more information about RMS, see the OpenVMS Record Management Services Reference Manual.)
- Language I/O statements
  Language I/O statements are provided for all high-level languages. These statements are easy to use and provide simple I/O and data formatting for the high-level language user. Native language I/O statements make it unnecessary for the high-level language user to call $QIO or RMS directly; these calls are made by the compiled code on your behalf. However, low-level and medium-level languages (VAX MACRO and BLISS-32) have no built-in language I/O statements and must use $QIO and RMS for terminal and file I/O. (For more information, see the appropriate language reference manual.)
- Screen Management Procedures in the run-time library (SMG$)
  SMG$ procedures provide an easy-to-call interface for high-level languages. They are device independent and aid in the composition of complex screen images. The SMG$ facility in the run-time library provides screen composition operations; that is, SMG$ makes it easy for an application to divide its screen into multiple regions and provides functions for manipulating those regions. Other features provided by SMG$ procedures are as follows:
  - Output to virtual displays
  - Input from a virtual keyboard or locator device
  - The ability to perform asynchronous input
  - Built-in minimal screen updating
  - Optional buffering and batching to optimize performance
  - The ability to trap broadcast messages
  - The option of performing output to a file or a hardcopy device
  - Support for foreign (not Compaq) terminals
  - Subprocess manipulation
  For more information about SMG$ procedures, see the OpenVMS RTL Screen Management (SMG$) Manual and the OpenVMS Programming Concepts Manual.

During I/O to the terminal, it is important that the procedure and the main program cooperate in controlling the terminal screen. For example, an I/O procedure may write something to the terminal screen that the calling program wants to erase. To erase it, the calling program must know both what and where that information is. The calling program and the called procedure must communicate by passing arguments that define which part of the screen will be accessed by each. The run-time library contains Screen Management (SMG$) procedures for this purpose.

Do not combine different methods of I/O within your application. Problems can arise if the calling program and the called procedure use different methods of I/O. Each method of performing input/output maintains some knowledge of what is on the terminal screen. At the very least, the current cursor position is remembered. If another type of I/O is performed, that information is not updated and, therefore, becomes incorrect. The results of any subsequent I/O would be unpredictable. If you must combine other methods with uses of SMG$ procedures, use the SMG$ procedures that aid such an integration.

### 2.5.2 File Input/Output

File I/O can be performed by the following methods:

- Block I/O
  Uses system services to map a section of the file to the process virtual address space. No notion of records.
- OpenVMS Record Management Services (RMS)
  RMS provides a variety of file organizations and access modes from which you can select the processing techniques best suited to your application. RMS supports the sequential, relative, and indexed-sequential file organizations. These modes allow you to access records within these files sequentially, randomly by key value or relative record number, or randomly by the records file address (RFA). It is not usually necessary to call RMS directly from high-level languages. For specific information about performing record management operations in the language you are using, consult your language reference manual. (For more information about RMS, see the OpenVMS Record Management Services Reference Manual.)
- Language I/O
  The compiled code in most high-level languages calls a run-time library language support procedure for file operations. The run-time library procedures normally call RMS. Therefore, most RMS features are available to the high-level language user without calling RMS directly. Language I/O statements are suitable for either data files or output files. Low- and medium-level languages (VAX MACRO and BLISS-32) do not have any language I/O statements and must call RMS directly. (For more information, see the appropriate language reference manual.)

## 2.6 Documenting Modules

You should document every module you create so that you and others know what the procedure does. Each module should include:

- A preface that identifies the procedure
- A description of the procedure

In most cases, a module should contain only one procedure.

### 2.6.1 Writing a Module Preface

At the beginning of every module, include a preface that contains the following information:

Title: | Module name followed by a one-line functional description.
Version: | Version and a three-digit edit number. Generally 1-001 is the original version.
Facility: | Description of the library facility, such as general utility library (LIB).
Abstract: | Short (three to six lines) functional description of the module.
Environment: | Describe any special environmental assumptions that the module can make. These include assumptions made at both compilation and execution time that could affect either the hardware or software environments. Describes situations that the module assumes during execution time and optional modular programming elements that your module does not follow. Indicates the reentrancy characteristics of the procedures in this module. Each procedure is either fully reentrant, AST reentrant, or nonreentrant.
Author: | Your name and date the module was created.
Modified by: | Modification number, name of modifying programmer, modification date, and a list of the modifications.

End the preface with a page delimiter. After the preface, include the code for the procedure.

Example 2-4 shows a sample module description.

Example 2-4 Sample Module Description

            PROGRAM GRA_CUBE                ! Create representation of a cube

    !+
    ! VERSION:      1-002
    !
    ! FACILITY:     User Graphics Computation Library
    !
    ! ABSTRACT:     This module contains a procedure to create a mathematical
    !               representation of a cube, GRA_CUBE.
    !
    ! ENVIRONMENT:  User Mode, AST-reentrant
    !
    ! AUTHOR:       John Smith                CREATION DATE:  14-Sep-1993
    !
    ! MODIFIED BY:
    ! 1-001 - Original.  DWS 14-Sep-1993
    ! 1-002 - Fix a minor bug in cube volume computation.  MDL 15-Mar-1993
    !-

### 2.6.2 Writing a Procedure Description

At the beginning of every procedure in a module, describe the procedure by including the information in this section. Include all the description elements, even if they are not in the procedure. For example, if a procedure has no implicit inputs, write the following:

    !
    !  Implicit Inputs:
    !
    !       NONE
    !

Every procedure description should include the following information:

Functional description: | Describes a procedure's purpose and completely documents its interfaces. Includes the basis for any critical algorithms used, including literature references where applicable, and explains why a particular algorithm was chosen. Indicates the reentrancy characteristics of this procedure if they differ from those given in the module description.
Calling sequence: | Includes these elements in the following order: A return status, value argument, or CALL statement The procedure name The argument list (typically a list of registers or arguments) In VAX MACRO, each argument is symbolically defined as the offset relative to the argument pointer (AP). Lists the arguments in the order they will appear in a high-level language. Each argument characteristic should also be included, using the procedure argument notation described in OpenVMS Programming Interfaces: Calling a System Routine. Note that this manual has been archived but is available on the OpenVMS Documentation CD-ROM.
Formal arguments: | Lists any explicit input, input/output, or output arguments. Includes a qualifying description with each argument. The arguments should be listed in the order they are listed in the calling sequence.
Implicit inputs: | Lists any inputs from storage, internal or external to the module, that are not specified in the argument list. Usually all that will appear here is NONE. See Section 2.2.2.
Implicit outputs: | Lists any outputs to internal or external storage that are not specified in the argument list.
Completion status or routine value: | Lists the success or failure condition value symbols that could be returned. If your procedure returns a function value other than a condition value, change the heading to "Routine value."
Side effects: | Describes any functional side effects not evident from a procedure's calling sequence. This includes changes in storage allocation, process status, file operations, and possible signaled conditions. In general, you should document anything out of the ordinary that the procedure does to the environment. If a side effect modifies local or global storage locations, document it in the implicit output description instead.

Example 2-5 shows a sample procedure description.

Example 2-5 Sample Procedure Description

    !++
    ! FUNCTIONAL DESCRIPTION:
    !
    !       Return the system date and time, using the caller's
    !       semantics for his/her string.
    !
    !       Non-reentrant; uses static storage.
    !
    ! FORMAL ARGUMENT(S):
    !
    !       RESULT_ADDR
    !       VMS USAGE : char_string
    !       TYPE      : character string
    !       ACCESS    : write only
    !       MECHANISM : by descriptor
    !
    !      Address of the descriptor into which the
    !      system date and time is written.
    !
    ! IMPLICIT INPUTS:
    !
    !       NONE
    !
    ! IMPLICIT OUTPUTS:
    !
    !       NONE
    !
    ! COMPLETION CODES:
    !
    !       SS$_NORMAL      Procedure successfully completed
    !       LIB$_STRTRU     Success, but source string truncated
    !
    ! SIDE EFFECTS:
    !
    !       Requests the current date and time from OpenVMS.
    !
    !--

## 2.7 Planning for Signaling and Condition Handling

Two methods are available to a procedure for indicating to its caller whether it completed successfully. One method is to return a condition value. The other method is to signal an error condition.

To provide a better user interface, all procedures in a facility should either return condition values or signal error conditions. Regardless of which method you choose, you should be consistent within the facility to make the procedures easier for the user to call.

### 2.7.1 Guidelines for Signaling Error Conditions

The signaling of an error condition is, in some instances, mandatory.

Procedures that return a function value cannot also return a condition value and therefore must signal any error conditions encountered.

However, to maintain efficiency, you might want other procedures to signal error conditions also. Checking the return status of a called procedure for repetitive calls can be time consuming and adversely affect the performance of the calling program. For example, if you are going to call a procedure 100 times within a loop and the chances of that procedure's failure are small, you may not want to take the time to check the return status after each call to make sure that the condition value returned was SS$_NORMAL. Signaling error conditions is far more efficient in this type of application.

From the point of view of the calling program, handling a signaled condition is slightly more difficult than checking a returned condition value because it involves writing a condition handler to be invoked in the event that an error condition is signaled. However, handling a signaled condition allows the calling program to execute more efficiently.

To signal an error condition, your procedure uses either a condition-handling mechanism provided by the source language, or it calls the Run-Time Library procedure LIB$SIGNAL. To use LIB$SIGNAL, your procedure calls LIB$SIGNAL and specifies the condition code and zero or more arguments specifying the environment of the condition. For more information about using LIB$SIGNAL, see the OpenVMS RTL Library (LIB$) Manual.

### 2.7.2 Guidelines for Returning Condition Values

From the point of view of the calling program, it is much easier to check returned condition values than to handle signaled error conditions. When the condition value is being returned, the calling program does not need to include a condition handler. The calling program needs only to check the status of the returned value.

However, if you return condition values rather than signal error conditions, you return less information about the error condition to the calling program. Compaq recommends that you return condition values when the explanation of the error condition is simple and self-contained. For example, LIB$GET_VM returns a condition value, because the possible status conditions are self-contained and simple (for example, insufficient virtual memory).

According to the OpenVMS Calling Standard, the status returned must be a condition value. (For more information, see OpenVMS Programming Interfaces: Calling a System Routine1.

### 2.7.3 When to Signal or Return Condition Values

To some degree, whether you decide to signal an error condition or return a condition value depends on the language you are using for your procedure. In some high-level languages, it is difficult to write a condition handler to be invoked in the event that an error condition is signaled. (For more information about condition handling in your language, consult the appropriate language reference manual.)

Regardless of which language you are using, there are general guidelines for when to return a condition value and when to signal an error condition.

You should signal an error condition in the following situations:

- Your procedure returns a value in R0 and cannot return a condition value.
- Your procedure must execute quickly, and checking the return status of a condition value would be inefficient.
- Your procedure will be executed repetitively; therefore, checking the condition value returned would adversely affect your procedure's performance.
- The amount of information you want to return about the error condition cannot be contained in a condition value.
- A useful error message requires information that cannot be determined until run time. For example, the FDL$PARSE procedure must tell you which line of the FDL file was the cause of an error. Because the line number of the line containing the error cannot be determined until run time, the signal mechanism is preferred.
- You want to execute a specific condition handler in the event that an error condition is signaled.

You should return a condition value in the following situations:

- You want to keep the error-handling mechanism simple.
- The speed of the error-checking mechanism is not of great concern.
- The total possible errors that may be returned is a small number, and sufficient information about those errors can be contained in the condition value returned.
- The functions provided by the procedure are so general that the procedure will be used in various levels and environments.

Note ##### 1 This manual has been archived but is available on the OpenVMS Documentation CD-ROM.

Previous | Next | Contents | Index

| privacy and legal statement |
4518PRO_002.HTML