# Compaq ACMS for OpenVMS
Writing Applications

Previous | Contents | Index

## 2.2.2 Defining the Block Step

When you define more than one step to do work for a task, you group those steps into a block step. A block step has four parts:

- Attributes
- Work
- Action
- Exception handler

Chapter 8 describes how to use exception handlers.

In the attributes part of the block step, you must indicate that the task uses DECforms to interface with the terminal by adding the keywords FORM I/O to the definition.

The work part of a block step consists of the exchange and processing steps you define for a task. The definition for the Add Car Reservation task, including the minimum block step syntax, follows:

    BLOCK WORK
      WITH FORM I/O
      GET_RENTAL_INFORMATION:
        EXCHANGE
          TRANSCEIVE FORM RECORD ADD_RESERVE_FORM_REC, ADD_RESERVE_FORM_REC
           SENDING ADD_RESERVE_WKSP
           RECEIVING ADD_RESERVE_WKSP;
      WRITE_RESERVATION_INFORMATION:
        PROCESSING
          CALL WRITE_RESERVE_PROC IN RESERVE_SERVER
           USING ADD_RESERVE_WKSP;
      END BLOCK WORK;

You use the BLOCK clause to start the work for the task. The END BLOCK WORK keywords indicate the end of that work. Include a semicolon (;) after the END BLOCK WORK keywords.

## 2.2.3 Defining Characteristics of the Task

A task definition must also describe the task characteristics. You use the task part of a definition to set up characteristics for the block step and for steps within the block step.

The most important characteristic of a simple data entry task is the workspace or workspaces used by the steps in the task. You use the WORKSPACES clause to name the workspace or workspaces used by the steps in the task. You must use the CDD path name of the record description for each workspace you name. The CDD given names of the path names you declare must match the given names of the workspaces referred to by the TRANSCEIVE and CALL clauses in the task definition.

The sample step definition uses only one workspace, ADD_RESERVE_WKSP. Suppose that the definition for this workspace is in the ACMS$EXAMPLES_RMS directory in the ACMS$DIR directory and that the anchor is in DISK1:[CDDPLUS]. The corresponding WORKSPACE clause looks like this:

    WORKSPACE IS DISK1:[CDDPLUS]ACMS$DIR.ACMS$EXAMPLES_RMS.ADD_RESERVE_WKSP;

You must end the clause with a semicolon (;). If you set your CDD default to DISK1:[CDDPLUS]ACMS$DIR.ACMS$EXAMPLES_RMS when you build the definition, you can use just the given name of the record description for the workspace:

    WORKSPACE IS ADD_RESERVE_WKSP;

If many programmers are working on a project, you might want to use the full path name, rather than the given name, because different programmers might use different CDD defaults.

Now the definition looks like this:

    WORKSPACE IS ADD_RESERVE_WKSP;
    BLOCK
      WORK WITH FORM I/O
      GET_RENTAL_INFORMATION:
        EXCHANGE
          TRANSCEIVE FORM RECORD ADD_RESERVE_FORM_REC, ADD_RESERVE_FORM_REC
           SENDING ADD_RESERVE_WKSP
           RECEIVING ADD_RESERVE_WKSP;
      WRITE_RESERVATION_INFORMATION;
        PROCESSING
          CALL WRITE_RESERVE_PROC IN RESERVE_SERVER USING ADD_RESERVE_WKSP;
      END BLOCK WORK;
    END DEFINITION;

You must end every definition with the END DEFINITION keywords and a semicolon (;).

ACMS requires that the name of each workspace be unique within the workspace declarations for each task group. If two or more given names of record path names are identical, you must assign a unique name with the keyword WITH NAME. For example, to assign the unique name ADD to the ADD_RESERVE_WKSP workspace, you use:

    WORKSPACE IS ADD_RESERVE_WKSP WITH NAME ADD;

Use the WITH NAME keyword carefully. In general, if you need to use the same record definition, under different names, in multiple parts of your application, it is easier to maintain the application if you assign unique workspace names than if you use WITH NAME.

## 2.2.4 Storing a Task Definition in the Dictionary

Once you have written the task definition, you can use either the ADU CREATE or ADU REPLACE command to store that definition in the dictionary.

When you use the CREATE or REPLACE command, you include:

- The kind of definition you are creating
- Where in the dictionary you want to store the definition
- The name of the file containing the source definition

For example:

    ADU>CREATE TASK ADD_CAR_RESERVATION_TASK ADDCAR.TDF

This CREATE command processes the definition in the file ADDCAR.TDF. If there are no errors in the definition, ADU stores it in the dictionary in the default directory defined by CDD$DEFAULT.

You can insert the REPLACE command at the beginning of the source definition file and submit it to ADU as a command file. When you submit definitions as command files, use the REPLACE command rather than the CREATE command to save yourself the effort of changing the command when you resubmit the file to ADU.

Example 2-2 shows the contents of the source definition file ADDCAR.TDF. This command file includes the REPLACE command and all the clauses used in this chapter to build the source definition.

Example 2-2 Contents of a Source Definition File

    SET VERIFY
    REPLACE TASK ADD_CAR_RESERVATION_TASK
      WORKSPACE IS ADD_RESERVE_WKSP;
      BLOCK
        WORK WITH FORM I/O
      GET_RENTAL_INFORMATION:
        EXCHANGE
          TRANSCEIVE FORM RECORD ADD_RESERVE_FORM_REC, ADD_RESERVE_FORM_REC
           SENDING ADD_RESERVE_WKSP
           RECEIVING ADD_RESERVE_WKSP;
      WRITE_RESERVATION_INFORMATION:
        PROCESSING
          CALL WRITE_RESERVE_PROC IN RESERVE_SERVER
           USING ADD_RESERVE_WKSP;
      END BLOCK WORK;
    END DEFINITION;

You can include the SET VERIFY command with a source definition you are submitting as a command file. This command displays each line of the definition as it is processed by ADU, letting you see where errors in the definition occur.

To submit the definition to ADU as a command file, use the at sign character (@) followed by the file name:

    ADU>@ADDCAR.COM

When you submit the command file, ADU checks the source definition file and returns any errors to the terminal. If errors occur, you can edit the source definition file to correct the definition and resubmit the file in the same manner.

Note If you use the CREATE or REPLACE command at the ADU prompt to process a definition file, the definition must not contain the CREATE or REPLACE clause, or else ADU returns an error. If you insert the CREATE or REPLACE clause in the definition file, you must submit it to ADU as a command file.

## 2.2.5 Additional Considerations: Error Handling and Ease of Use

So far, the sample task definition does not handle two considerations that you want to address when solving most business problems: handling processing errors and making the task easy to use.

A complete and realistic version of a data entry task makes provision for errors by taking the following actions:

1. Get information.
2. Allow the user to type a key or combination of keys to end the task instead of completing the first form.
3. Write information to the database.
4. If the processing is successful, let the user repeat the same task without going back to the selection menu. If a user-related or recoverable error occurs, save the input data, tell the user about the error, and let the user correct the error. If a nonrecoverable error occurs, cancel the task.

Once you have broken the problem down into these parts, you can begin putting together the definition. To handle errors that might occur in the processing step, you might need to add another exchange step to the task definition. To handle errors and special conditions in both the exchange and processing steps, you also might need to increase the number of workspaces and change some task characteristics.

### 2.2.5.1 Using ACMS Workspaces

When you want to handle errors in a task, you test the contents of a field in a workspace and take action based on the contents. For example, a procedure can return a value to a field in a workspace. You can use the CONTROL FIELD clause to test the contents of that field. Then you use action clauses to take action based on those contents. In addition to the CONTROL FIELD clause, ACMS provides three other conditional clauses for testing workspace fields:

- IF THEN ELSE
- SELECT FIRST
- WHILE DO

The CONTROL FIELD clause can test the contents of a control field in either of two workspaces:

- An ACMS system workspace, especially ACMS$PROCESSING_STATUS
- A workspace you define

You can use any of the ACMS system workspaces with a conditional clause. However, the ACMS$PROCESSING_STATUS system workspace is especially useful for handling results of procedures in processing steps. Workspaces you define are especially useful for handling information passed to a form.

There are three ACMS system workspaces; each workspace handles a different kind of information. The Compaq ACMS for OpenVMS ADU Reference Manual lists all the system workspaces and gives a brief description of each.

The first exchange step in the Add Car Reservation task uses the CONTROL FIELD clause to test a workspace that you define, while the processing step uses the IF THEN ELSE clause to test a system workspace field.

The ACMS$PROCESSING_STATUS system workspace has four fields:

- ACMS$L_STATUS
- ACMS$T_SEVERITY_LEVEL
- ACMS$T_STATUS_TYPE
- ACMS$T_STATUS_MESSAGE_LONG or ACMS$T_STATUS_MESSAGE

All processing work returns a final status value. For example, when a procedure exits, ACMS places its return status in the ACMS$L_STATUS field of the ACMS$PROCESSING_STATUS workspace. ACMS translates that value and performs the following operations:

1. Stores in the ACMS$T_SEVERITY_LEVEL field a single character string indicating the severity level of the error. These characters are:
   - S --- SUCCESS
   - I --- INFORMATION
   - W --- WARNING
   - E --- ERROR
   - F --- FATAL
   If the error returned by the procedure does not match any of these error severities, ACMS stores a question mark (?) in the ACMS$T_SEVERITY_LEVEL field.
2. Stores in the ACMS$T_STATUS_TYPE field a single character string indicating whether the severity level of the error is good or bad. These characters are:
   - G --- GOOD
   - B --- BAD
   If the severity level of the return status of the procedure is SUCCESS or INFORMATION, ACMS stores a G in the ACMS$T_STATUS_TYPE field. If the severity level is WARNING, ERROR, or FATAL, ACMS stores a B in that field.

ACMS can also use the return status value in the ACMS$L_STATUS field to get an error message from a message file. By default, it stores that message in the ACMS$T_STATUS_MESSAGE_LONG field. To retrieve the error message, you must use the GET ERROR MESSAGE clause, as explained later in this chapter.

Whether the conditional clause tests a field in a system workspace or in a workspace you define, the values it tests must be literal strings and the datatype of the field must be text. Table 2-2 summarizes the fields and values that conditional clauses can test.

Table 2-2 Field and Values Tested by Conditional Clauses
Workspace | Field | Value
--- | --- | ---
User-defined | Any | Quoted string
ACMS$PROCESSING_STATUS | ACMS$T_SEVERITY_LEVEL | S,I,W,E,F,?
ACMS$PROCESSING_STATUS | ACMS$T_STATUS_TYPE | G,B

The initial value of the ACMS$T_SEVERITY_LEVEL workspace is S. The initial value of the ACMS$T_STATUS_TYPE field is G.

#### 2.2.5.1.1 Using the CONTROL FIELD Clause in an Exchange Step

One special condition you want to allow for is letting the terminal user press a key to stop running the task. The form stores a value associated with that key in a workspace field. You can then use the CONTROL FIELD clause to test the contents of that field.

In the Add Car Reservation task, you want to let the user stop running the task when the form displays a panel asking for rental information. To do this, you need to define a key, such as the PF4 key, as the exit or quit key. DECforms refers to such a key as a function key. In your form definition, you must make the function declaration after the LAYOUT specification. In the following example, the function is PF4 and its name is QUIT_KEY.

    FORM ADD_RESERVE_FORM
    .
    .
    .
      Layout VT_LAYOUT
          .
          .
          .
          Size 24 lines by 80 columns

          Function QUIT_KEY
              is %PF4
          End Function

You must also declare a function response in the IFDL source file. A function response alters the way DECforms processes the form. In this example, when the terminal user presses `[PF4]`, the function response directs DECforms to return the value "QUIT" to an ACMS workspace. Place the function response at the beginning of the panel declaration.

           Panel ADD_RESERVE_PANEL
               Function Response QUIT_KEY
                    Let QUIT_KEY = "QUIT"
                    Return Immediate
               End Response

For more information about declaring function responses, see DECforms Guide to Developing an Application.

In your exchange step, you need to identify the workspace where DECforms stores the value "QUIT". In the example below, the QUIT_KEY field is in the QUIT_CTRL_WKSP workspace. The form record used for the receive part of the exchange is a record list. ADD_RESERVE_FORM_REC_LIS contains form records for ADD_RESERVE_WKSP and QUIT_CTRL_WKSP. Then, in the action part of the exchange step, you can use the CONTROL FIELD clause to test the workspace field. For example:

    EXCHANGE
      TRANSCEIVE FORM RECORD ADD_RESERVE_FORM_REC,
                             ADD_RESERVE_FORM_REC_LIS
       SENDING ADD_RESERVE_WKSP
       RECEIVING ADD_RESERVE_WKSP, QUIT_CTRL_WKSP;
    ACTION IS
       CONTROL FIELD QUIT_CTRL_WKSP.QUIT_KEY
       "QUIT"  :  EXIT TASK;
       END CONTROL FIELD;

The CONTROL FIELD clause tests the QUIT_KEY field of QUIT_CTRL_WKSP. When you use the CONTROL FIELD clause, you can name the workspace and the workspace field, or just the workspace field. ACMS checks all of the workspaces defined for the task until it finds the field named in the CONTROL FIELD clause. However, including the workspace name is a good way to keep track of the location of information that the task uses. When you name the workspace in the CONTROL FIELD clause, use a period to separate it from the name of the control field.

If the value "QUIT" is in the QUIT_KEY field, ACMS exits or stops processing the task. Otherwise, ACMS goes on to process the next step in the definition. You must end each action clause, such as EXIT TASK, with a semicolon (;). End the CONTROL FIELD clause with the keywords END CONTROL FIELD and a semicolon (;).

When ACMS processes the EXIT TASK clause, it ends the task and returns the user to a selection menu without returning a message to the user. You can also use the CANCEL TASK clause to end a task. When ACMS processes the CANCEL TASK clause, it records the ending of the task as an abnormal ending or interruption, and returns a message to the user before returning the user to a selection menu.

In general, you use the EXIT TASK clause if the user wants to end the task and if there is no chance that data will be left in an inconsistent state. You use the CANCEL TASK clause if there is an abnormal reason for ending the task.

#### 2.2.5.1.2 Using the IF THEN ELSE Clause in a Processing Step

Suppose the user does not cancel the task in the first step of the task but types information and presses `[Return]` or `[Enter]`. In this case, the processing step calls a procedure to write that information to a file. This procedure can encounter errors.

You want the task to take different actions depending on the kind of error encountered. There are two kinds of errors: recoverable errors and nonrecoverable errors. Recoverable errors are those a user can correct, such as typing the wrong customer number. Nonrecoverable errors are those a user cannot correct. For example, "file not found" is a nonrecoverable error in the Add Car Reservation task.

When a procedure encounters a recoverable error, you can tell the user about the error and let the user do something to correct the error. In the case of a nonrecoverable error, you generally want the procedure to cancel the task.

When a procedure runs, it returns a status value to ACMS. ACMS puts this value in the ACMS$L_STATUS field of the ACMS$PROCESSING_STATUS system workspace. ACMS translates the return status value and stores, in the ACMS$T_SEVERITY_LEVEL field, a value indicating the severity level of the error. ACMS also stores in the ACMS$T_STATUS_TYPE field a GOOD or BAD value. You can use the IF THEN ELSE clause to test the contents of the ACMS$T_STATUS_TYPE field.

ACMS can also use the return status value in ACMS$L_STATUS field to retrieve an error message from a message file and then store that message in the ACMS$T_STATUS_MESSAGE field.

Suppose now that WRITE_RESERVE_PROC tries to write a reservation record to a file, but a record for that customer already exists. This is a recoverable error because the user can try a different customer number or enter information for a different customer. In this case, you want to tell the user about the error and let the user try again. Here is the processing step of the Add Car Reservation task:

    PROCESSING
      CALL WRITE_RESERVE_PROC IN RESERVE_SERVER
        USING ADD_RESERVE_WKSP;
      IF (ACMS$T_STATUS_TYPE EQ "B")
      THEN  GET ERROR MESSAGE;
            MOVE ACMS$T_STATUS_MESSAGE TO MSG_WKSP.MESSAGE_PANEL;
            GOTO STEP ERROR_PROCESS_MSG;
      ELSE  GOTO PREVIOUS EXCHANGE;
      END IF;

In this step, WRITE_RESERVE_PROC tries to write the information in the ADD_RESERVE_WKSP workspace to a file. It returns a status value to the ACMS$L_STATUS field of the ACMS$PROCESSING_STATUS workspace. ACMS translates that value and stores a B or G in the ACMS$T_STATUS_TYPE field. If the record already exists, the value in that field is a B.

The IF THEN ELSE clause tests a Boolean expression to determine which course of action to follow. You must enclose the Boolean expression within parentheses. See the Compaq ACMS for OpenVMS ADU Reference Manual for more information about using Boolean expressions. If the Boolean expression evaluates to true, ACMS performs the actions associated with the THEN keyword. In this example, if the record already exists, ACMS performs the following steps:

1. Retrieves the error message from a message file
2. Stores the error message in the MESSAGE_PANEL field of the MSG_WKSP workspace
3. Goes to the ERROR_PROCESS_MSG exchange step in the task

To display the error message to the terminal user, you need to include the following exchange step in your task definition:

    ERROR_PROCESS_MSG:
     EXCHANGE WORK
      SEND FORM RECORD MSG_FORM_REC
       SENDING MSG_WKSP;

This exchange step sends the error message stored in the MSG_WKSP workspace to the MSG_FORM_REC form record for display. The IFDL file for the ADD_RESERVE_FORM form must include the form record definition for MSG_FORM_REC.

If the Boolean expression evaluates to false, ACMS performs the actions associated with the ELSE keyword. In this example, the GOTO PREVIOUS EXCHANGE clause directs ACMS to repeat the task. You must end the IF THEN ELSE clause with the END IF keywords and a semicolon (;).

Figure 2-3 shows the process of retrieving and displaying error messages.

Figure 2-3 Retrieving Messages

Although you can use action clauses in any order you want, ACMS always processes them in the same order. For example, ACMS always processes the GET ERROR MESSAGE clause before any sequencing clauses, such as GOTO PREVIOUS EXCHANGE.

For more information on returning status and using the system workspace ACMS$PROCESSING_STATUS, see Compaq ACMS for OpenVMS Writing Server Procedures.

Previous | Next | Contents | Index