# Compaq COBOL
User Manual

Previous | Contents | Index

### 13.4.4.2 Calling a System Routine in a Function Call (OpenVMS)

In the following example, LIB$STAT_TIMER returns a condition value called RET-STATUS. To call this system routine, use the FORMAT of the function call described in the OpenVMS documentation on system services or Run-Time Library routines. In this case, the format is as follows:

    01 ARG-CODE   PIC S9(9) COMP.
    01 ARG-VALUE  PIC S9(9) COMP.
    01 RET-STATUS PIC S9(9) COMP.
             .
             .
             .
        CALL "LIB$STAT_TIMER"
              USING BY REFERENCE ARG-CODE, ARG-VALUE
              GIVING RET-STATUS.

As stated earlier, this example does not pass a value for the optional handle-address argument.

The FORMAT will describe optional arguments in one of two ways:

       [,optional-argument]

or

       ,[optional-argument]

If the comma appears outside of the brackets, you must pass a zero by value or use the OMITTED phrase to indicate the place of the omitted argument.

If the comma appears inside the brackets, you can omit the argument as long as it is the last argument in the list.

For example, look at the optional arguments of a hypothetical routine, LIB$EXAMPLE_ROUTINE:

    LIB$EXAMPLE_ROUTINE arg1 [,arg2] [,arg3] [,arg4]

You can omit the optional arguments without using a placeholder:

    CALL "LIB$EXAMPLE_ROUTINE"
          USING ARG1
          GIVING RET-STATUS.

However, if you omit an optional argument in the middle of the argument list, you must insert a placeholder:

    CALL "LIB$EXAMPLE_ROUTINE"
          USING ARG1, OMITTED, ARG3
          GIVING RET-STATUS.

In general, Run-Time Library routines use the [,optional-argument] format, while system services use the ,[optional-argument] format.

In passing arguments to the procedure, you must define the passing mechanism required if it is not the default. The default passing mechanism for all COBOL data types is BY REFERENCE.

The passing mechanism required for a system routine argument is indicated in the argument description. The passing mechanisms allowed in system routines are those listed in the OpenVMS Calling Standard.

If the passing mechanism expected by the routine or service differs from the default mechanism in COBOL, you must override the default. To force an argument to be passed by a specific mechanism, refer to the following list:

- If the argument is described as "the address of," use BY REFERENCE, which is the default.
- If the argument is described as "the value of," use BY VALUE.
- If the argument is described as "address of descriptor," use BY DESCRIPTOR.

Note If a routine requires a passing mechanism that is not supported by COBOL, calling that routine from COBOL is not possible.

Even when you use the default passing mechanism, you can include the passing mechanism that is used. For example, to call LIB$STAT_TIMER, you can use either of the following definitions:

    CALL "LIB$STAT_TIMER"
          USING ARG-CODE, ARG-VALUE
          GIVING RET-STATUS.

    CALL "LIB$STAT_TIMER"
          USING BY REFERENCE ARG-CODE, ARG-VALUE
          GIVING RET-STATUS.

### 13.4.4.3 Calling a System Routine in a Procedure Call (OpenVMS)

If the routine or service you are calling does not return a function value or condition value, you can call the system routine as a procedure. The same rules apply to optional arguments; you must follow the calling sequence presented in the FORMAT section of the OpenVMS documentation on system services or Run-Time Library routines.

One system routine that does not return a condition value or function value is the Run-Time Library routine LIB$SIGNAL. LIB$SIGNAL should always be called as a procedure, as shown in the following example:

    01 ARG-VALUE PIC S9(5) COMP VALUE 90.
        .
        .
        .
        CALL "LIB$SIGNAL" USING BY VALUE ARG-VALUE.

## 13.4.5 Checking the Condition Value (OpenVMS)

Many system routines return a condition value that indicates success or failure; this value can be either returned or signaled. In general, system routines return a condition value with the following exceptions:

- The system routine returns a function value.
- The CONDITION VALUES RETURNED is None.
- There is no CONDITION VALUES RETURNED description, but rather a CONDITION VALUES SIGNALED description. (Success conditions are not signaled.)
- The call to the routine was made as a procedure call.

If any of these conditions apply, there is no condition value to check.

If there is a condition value, you must check this value to make sure that it indicates successful completion. All success condition values are listed in the CONDITION VALUES RETURNED description.

Condition values indicating success always appear first in the list of condition values for a particular routine, and success codes always have odd values. A success code common to many system routines is the condition value SS$_NORMAL, which indicates that the routine completed normally and successfully. You can reference the condition values symbolically in your COBOL program by specifying them in the EXTERNAL phrase of the VALUE IS clause. Symbolic names specified in VALUE IS EXTERNAL become link-time constants; that is, the evaluation of the symbolic name is deferred until link time because it is known only at link time.

For example:

    01 SS$_NORMAL PIC S9(5) COMP VALUE EXTERNAL SS$_NORMAL
         .
         .
         .
         CALL "LIB$STAT_TIMER" USING ARG-CODE, ARG-VALUE GIVING RET-STATUS.
         IF RET-STATUS NOT EQUAL SS$_NORMAL...

Because all success codes have odd values, you can check a return status for any success code. For example, you can cause execution to continue only if a success code is returned by including the following statement in your program:

    IF RET-STATUS IS SUCCESS ...

Sometimes several success condition values are possible. You may only want to continue execution on specific success codes.

For example, the $SETEF system service returns one of two success values: SS$_WASSET or SS$_WASCLR. If you want to continue only when the success code SS$_WASSET is returned, you can check for this condition value as follows and branch accordingly:

    IF RET-STATUS EQUAL SS$_WASSET ...

or

    EVALUATE RET-STATUS
         WHEN SS$_WASSET ...

If the condition value returned is not a success condition, then the routine did not complete normally, and the information it should have returned may be missing, incomplete, or incorrect.

You can also check for specific error conditions as follows:

    WORKING-STORAGE SECTION.
    01 USER-LINE     PIC X(30).
    01 PROMPT-STR    PIC X(16) VALUE IS "Type Your Name".
    01 OUT-LEN       PIC S9(4) USAGE IS COMP.
    01 COND-VALUE    PIC S9(9) USAGE IS COMP.
    88 LIB$_INPSTRTRU VALUE IS EXTERNAL LIB$_INPSTRTRU.
                         .
                         .
                         .
    PROCEDURE DIVISION.
    P0.
        CALL "LIB$GET_INPUT" USING BY DESCRIPTOR USER-LINE PROMPT-STR
                                   BY REFERENCE OUT-LEN
                                   GIVING COND-VALUE.
        EVALUATE TRUE
            WHEN LIB$_INPSTRTRU
                 DISPLAY "User name too long"
            WHEN COND-VALUE IS FAILURE
                 DISPLAY "More serious error".
                        .
                        .
                        .

### 13.4.5.1 Library Return Status and Condition Value Symbols (OpenVMS)

Library return status and condition value symbols have the following general form:

`fac$_abcmnoxyz`

where:

fac | is a 2- or 3-letter facility symbol (LIB, MTH, STR, OTS, BAS, COB, FOR, SS).
abc | are the first 3 letters of the first word of the associated message.
mno | are the first 3 letters of the next word.
xyz | are the first 3 letters of the third word, if any.

Articles and prepositions are not considered significant words in this format. If a significant word is only two letters long, an underscore character is used to fill out the third space. The OpenVMS normal or success code is used to indicate successful completion. Some examples of this code are as follows:

RETURN Status | Meaning
--- | ---
LIB$_INSVIRMEM | Insufficient virtual memory
FOR$_NO_SUCDEV | No such device
MTH$_FLOOVEMAT | Floating overflow in Math Library procedure
BAS$_SUBOUTRAN | Subscript out of range

## 13.4.6 Locating the Result (OpenVMS)

Once you have defined the arguments, called the procedure, and checked the condition value, you are ready to locate the result. To find out where the result is returned, look at the description of the system routine you are calling.

For example, in the following call to MTH$ACOS the result is written into the variable COS:

    01 ARG-CODE PIC S9(9) COMP VALUE 1.
    01 COS                COMP1 VALUE 0.
            .
            .
            .
        CALL "MTH$ACOS" USING BY REFERENCE ARG-CODE GIVING COS.

This result is described in the OpenVMS documentation on system services and Run-Time Library routines, under the description of the system routine.

# 13.5 Establishing and Removing User Condition Handlers (OpenVMS)

To establish a user condition handler, call the LIB$ESTABLISH routine.

The form of the call is as follows:

    CALL LIB$ESTABLISH USING BY VALUE new-handler GIVING old-handler

> ### new-handler

> Specifies the name of the routine to be set up as a condition handler.

> ### old-handler

> Receives the address of the previously established condition handler.

The GIVING phrase is optional.

LIB$ESTABLISH moves the address of the condition-handling routine into the appropriate process context and returns the address of a previously established condition handler.

The handler itself could be a user-written routine, or a library routine. The following example shows how a call to establish a user-written handler might be coded:

    01 HANDLER      PIC S9(9) COMP VALUE EXTERNAL HANDLER_ROUT.
    01 OLD-HANDLER  PIC S9(9) COMP.
       .
       .
       .
       CALL "LIB$ESTABLISH" USING BY VALUE HANDLER GIVING OLD-HANDLER.

In the preceding example, HANDLER_ROUT is the name of a program that is established as the condition handler for the program unit containing these source statements. A program unit can remove an established condition handler in two ways:

- Issue another LIB$ESTABLISH call which specifies a different handler.
- Issue the LIB$REVERT call.

The LIB$REVERT call has no arguments:

    CALL "LIB$REVERT".

This call removes the condition handler established in the current program unit.

Note that the LIB$ESTABLISH and LIB$REVERT routines only affect user condition handlers, not the default Compaq COBOL condition handler. When an exception occurs, the user condition handler, if one exists, is executed first, followed by the Compaq COBOL condition handler, if the user condition handler could not handle the exception.

When a program unit returns to its caller, the condition handler associated with that program unit is automatically removed (the program unit's stack frame, which contains the condition handler address, is removed from the stack).

Example 13-1 illustrates a user written condition handling routine that determines the reason for a system service failure. The example handler handles only one type of exception, system service failures. All other exceptions are resignalled, allowing them to be handled by the system default handlers. This handler is useful because the system traceback handler indicates only that a system service failure occurred, not which specific error caused the failure.

LIB$ESTABLISH is used by the main program, SSCOND, to establish the user written condition handler, SSHAND. System service failure mode is enabled so that errors in system service calls will initiate a search for a condition handler.

The condition handler is written as a subprogram that returns a result. The result indicates whether or not the condition handler handled the exception. Note that space must be allocated in the LINKAGE SECTION for the signal and mechanism arrays. The mechanism array always contains five elements, but the signal array varies according to the number of additional arguments.

When an exception occurs, the user condition handler is invoked first. The handler checks the error condition to determine if it is one that it can handle (the LIB$MATCH_COND routine would be useful here if the routine wanted to check for one of a collection of conditions). If the exception is not handled by this condition handler, then the default COBOL condition handler is invoked. If the default COBOL condition handler does not handle the exception, then the exception is handled by the operating system.

Example 13-1 User-Written Condition Handler

    IDENTIFICATION DIVISION.
    PROGRAM-ID.     SSCOND.
    DATA DIVISION.
    WORKING-STORAGE SECTION.

    01      SSHANDA          PIC S9(9) COMP  VALUE EXTERNAL SSHAND.
    PROCEDURE DIVISION.
    BEGIN.
    *
    *       Establish condition handler
            CALL "LIB$ESTABLISH" USING BY VALUE SSHANDA.
    *
    *       Enable system service failure mode
            CALL "SYS$SETSFM" USING BY VALUE 1.
    *
    *       Generate a bad system service call
            CALL "SYS$QIOW" USING BY VALUE 0 0 0 0
                                           0 0 0 0
                                           0 0 0 0.
            STOP RUN.
    END PROGRAM SSCOND.

    IDENTIFICATION DIVISION.
    *
    PROGRAM-ID.     SSHAND.
    *
    *       This routine is to be used as a condition handler
    *       for system service failures.
    *
    *       If this routine does not remedy the exception condition, it will
    *       return with a value of SS$_RESIGNAL. If the routine does remedy
    *       the exception condition, then it should return with a value of
    *       SS$_CONTINUE.
    *
    DATA DIVISION.
    WORKING-STORAGE SECTION.
    01      SS_HAND         PIC S9(9) COMP.
    01      SS$_SSFAIL      PIC S9(9) COMP  VALUE EXTERNAL SS$_SSFAIL.
    01      SS$_RESIGNAL    PIC S9(9) COMP  VALUE EXTERNAL SS$_RESIGNAL.
    01      MSGLEN          PIC S9(4) COMP.
    01      MSGID           PIC S9(9) COMP.
    01      ERRMSG          PIC X(80).
    01      STAT            PIC S9(9) COMP.

    LINKAGE SECTION.
    01      SIGNAL_ARRAY.
            03      SIGNAL_ARGS     PIC 9(9) COMP.
            03      SIGNAL          OCCURS 4 TO 10 TIMES
                                    DEPENDING ON SIGNAL_ARGS.
                    05 SIGNAL_VALUE PIC S9(9) COMP.
    01      MECHANISM_ARRAY.
            03      MECH_ARGS       OCCURS 5 TIMES.
                    05 MECH         PIC 9(9) COMP.

    PROCEDURE DIVISION USING SIGNAL_ARRAY MECHANISM_ARRAY
                       GIVING SS_HAND.
    BEGIN.
    *
    *       Initialize the return result
    *
            MOVE SS$_RESIGNAL TO SS_HAND.

            IF SIGNAL_VALUE(1) NOT EQUAL SS$_SSFAIL
            THEN
                    MOVE SS$_RESIGNAL TO SS_HAND
            ELSE
    *
    *               Disable system service failure mode
    *
                    CALL "SYS$SETSFM" USING BY VALUE 0

                    MOVE SIGNAL(2) TO MSGID
                    CALL "SYS$GETMSG" USING BY VALUE MSGID
                                            BY REFERENCE MSGLEN
                                            BY DESCRIPTOR ERRMSG
                                            BY VALUE 0 0
                                       GIVING STAT
                    IF STAT IS FAILURE
                    THEN
                            CALL "LIB$STOP" USING BY VALUE STAT
                    END-IF

                    DISPLAY "System service call failed with error:"
                    DISPLAY ERRMSG(1:MSGLEN)

    *
    *               This is where the handler would perform
    *               corrective measures
    *                        .
    *                        .
    *                        .
    *               MOVE SS$_CONTINUE TO SS_HAND
    *
            END-IF.
            EXIT PROGRAM.
    END PROGRAM SSHAND.

To run this example program:

    $ COBOL SSCOND
    $ LINK  SSCOND
    $ RUN   SSCOND

    System service call failed with error:
    %SYSTEM-F-IVCHAN, invalid I/O channel
    %SYSTEM-F-SSFAIL, system service failure exception, status=0000013C,
         PC=8005FA40, PS=0000001B
    %TRACE-F-TRACEBACK, symbolic stack dump follows
     Image Name   Module Name     Routine Name    Line Number  rel PC      abs PC
                                                            0 8005FA40    8005FA40
     SSCOND       SSCOND          SSCOND                   21 000000CC    000300CC
     SSCOND                                                 0 00020470    00030470
                                                            0 870C8170    870C8170
                                                            0 849708F0    849708F0

For more information about condition handling, including LIB$ESTABLISH and LIB$REVERT, refer to the OpenVMS RTL Library (LIB$) Manual. <>

# 13.6 Examples (OpenVMS)

This section provides examples that demonstrate how to call system routines from COBOL programs.

Example 13-2 shows a procedure call and gives a sample run of the program RUNTIME. It calls MTH$RANDOM, a random number generator from the Run-Time Library, and generates 10 random numbers. To obtain different random sequences on separate runs, change the value of data item SEED for each run.

Example 13-2 Random Number Generator (OpenVMS)

    IDENTIFICATION DIVISION.
    PROGRAM-ID. RUNTIME.

    *****************************************************
    *  This program calls MTH$RANDOM, a random number   *
    *  generator from the Run-Time Library.             *
    *****************************************************
    DATA DIVISION.
    WORKING-STORAGE SECTION.
    01 SEED   PIC 9(5) COMP VALUE 967.
    01 A-NUM  COMP-1.
    01 C-NUM  PIC Z(5).
    PROCEDURE DIVISION.
    GET-RANDOM-NO.
        PERFORM 10 TIMES
           CALL "MTH$RANDOM" USING SEED GIVING A-NUM
           MULTIPLY A-NUM BY 100 GIVING C-NUM
           DISPLAY "Random Number is  " C-NUM
        END-PERFORM.

Example 13-3 shows a program fragment that calls the SYS$SETDDIR system service.

Example 13-3 Using the SYS$SETDDIR System Service (OpenVMS)

    01 DIRECTORY  PIC X(24) VALUE  "[MYACCOUNT.SUBDIRECTORY]".
    01 STAT PIC S9(9) COMP.
            .
            .
            .
        CALL "SYS$SETDDIR" USING BY DESCRIPTOR DIRECTORY
                                 OMITTED
                                 OMITTED
                                 GIVING STAT.

Example 13-4 calls the System Service routine $ASCTIM.

Example 13-4 Using$ASCTIM (OpenVMS)

    IDENTIFICATION DIVISION.
    PROGRAM-ID.   CALLTIME.
    ****************************************************
    *  This program calls the system service routine   *
    *  $ASCTIM which converts binary time to an ASCII  *
    *  string representation.                          *
    ****************************************************
    DATA DIVISION.
    WORKING-STORAGE SECTION.
    01  TIMLEN              PIC 9999  COMP VALUE 0.
    01  D-TIMLEN            PIC 9999  VALUE 0.
    01  TIMBUF              PIC X(24) VALUE SPACES.
    01  RETURN-VALUE        PIC S9(9) COMP VALUE 999999999.
    PROCEDURE DIVISION.
    000-GET-TIME.
          DISPLAY "CALL SYS$ASCTIM".
          CALL "SYS$ASCTIM" USING BY REFERENCE TIMLEN
                                  BY DESCRIPTOR TIMBUF
                                  OMITTED
                                  GIVING RETURN-VALUE.
          IF RETURN-VALUE IS SUCCESS
          THEN
                 DISPLAY "DATE/TIME " TIMBUF
                 MOVE TIMLEN TO D-TIMLEN
                 DISPLAY "LENGTH OF RETURNED = " D-TIMLEN
          ELSE
                 DISPLAY "ERROR".
          STOP RUN.

Example 13-5 shows output from a sample run of the CALLTIME program.

Example 13-5 Sample Run of CALLTIME (OpenVMS)

    CALL SYS$ASCTIM
    DATE/TIME 11-AUG-2000 09:34:33.45
    LENGTH OF RETURNED = 0023

The following example shows how to call the procedure that enables and disables detection of floating-point underflow (LIB$FLT_UNDER) from a COBOL program. The format of the LIB$FLT_UNDER procedure is explained in the OpenVMS RTL Library (LIB$) Manual.

    WORKING-STORAGE SECTION.
    01   NEW-SET         PIC S9(9) USAGE IS COMP.
    01   OLD-SET         PIC S9(9) USAGE IS COMP.
               .
               .
               .
    PROCEDURE DIVISION.
               .
               .
               .
    P0.
         MOVE 1 TO NEW-SET.
         CALL "LIB$FLT_UNDER" USING NEW-SET GIVING OLD-SET.

The following example shows how to call the procedure that finds the first clear bit in a given bit field (LIB$FFC). This procedure returns a COMP longword condition value, represented in the example as RETURN-STATUS.

    WORKING-STORAGE SECTION.
    01   START-POS       PIC S9(9) USAGE IS COMP VALUE 0.
    01   SIZ             PIC S9(9) USAGE IS COMP VALUE 32.
    01   BITS            PIC S9(9) USAGE IS COMP VALUE 0.
    01   POS             PIC S9(9) USAGE IS COMP VALUE 0.
    01   RETURN-STATUS   PIC S9(9) USAGE IS COMP.
               .
               .
               .
    PROCEDURE DIVISION.
               .
               .
               .
            CALL "LIB$FFC" USING START-POS,
                                 SIZ,
                                 BITS,
                                 POS
                           GIVING RETURN-STATUS.

            IF RETURN-STATUS IS FAILURE
               THEN GO TO error-proc.

Example 13-6 uses LIB$SET_SYMBOL to set a value for a DCL symbol and shows the use of LIB$K_* symbols for arguments and LIB$_* symbols for return status values.

Example 13-6 Using LIB$K_* and LIB$_* Symbols (OpenVMS)

    identification division.
    program-id. SETSYM.
    environment division.

    data division.
    working-storage section.
    01 LOCAL-SYM  pic S9(9) comp value external LIB$K_CLI_LOCAL_SYM.
    01 GLOBAL-SYM pic S9(9) comp value external LIB$K_CLI_GLOBAL_SYM.
    01 COND-VAL   pic S9(9) comp.
    88 COND-NORMAL               value external SS$_NORMAL.
    88 COND-AMBSYMDEF            value external LIB$_AMBSYMDEF.
    procedure division.
    1.      call "LIB$SET_SYMBOL" using
                    by descriptor "XSET*SYM"
                    by descriptor "Test1A"
                    by reference  LOCAL-SYM
                    giving        COND-VAL.
            if      COND-AMBSYMDEF display "Ambiguous"
            else if COND-NORMAL    display "OK"
            else                   display "Not OK".
    2.      call "LIB$SET_SYMBOL" using
                    by descriptor "XSETS"
                    by descriptor "Test1B"
                    by reference  LOCAL-SYM
                    giving        COND-VAL.
            if      COND-AMBSYMDEF display "Ambiguous"
            else if COND-NORMAL    display "OK"
            else                   display "Not OK".
    3.      call "LIB$SET_SYMBOL" using
                    by descriptor "XSETS"
                    by descriptor "Test1C"
                    by reference  GLOBAL-SYM
                    giving        COND-VAL.
            if      COND-AMBSYMDEF display "Ambiguous"
            else if COND-NORMAL    display "OK"
            else                   display "Not OK".

    9.      stop run.

This uses the following macro, `libdef.mar` :

    .TITLE libdef
    $HLPDEF GLOBAL  ; case sensitive!
    .END

The program is compiled, linked, and run, as follows:

    $ cobol setsym
    $ macro libdef
    $ link  setsym,libdef
    $ run   setsym
    OK
    Ambiguous
    OK
    $ show symbol xset*
      XSETS == "Test1C"
      XSET*SYM = "Test1A"

Previous | Next | Contents | Index