HP OpenVMS Systems Documentation
OpenVMS User's Manual
14.16.5 Using the GOTO Command
The GOTO command passes control to a labeled line in a command procedure. (For additional information on label usage, refer to Chapter 13.) The GOTO command is especially useful within a THEN clause to cause a procedure to branch forward or backward. For example, when you use parameters in a command procedure, you can test the parameters at the beginning of the procedure and branch to the appropriate label.
The target label of a GOTO or GOSUB command cannot be inside either a separate IF-THEN-ELSE construct or a separate subroutine.
In the following example, the IF command checks that P1 is not a null string:
If P1 is a null string, the GOTO command is not executed and the INQUIRE command prompts for a parameter value. Otherwise, the GOTO command causes a branch around the INQUIRE command. In either case, the procedure executes the PRINT command following the line labeled OKAY.
In the following example the GOTO command returns an error message because its target (TEST_1) is within an IF-THEN construct:
18.104.22.168 Avoiding Reexecution
You can also use the GOTO command to avoid reexecuting parts of the job that have completed successfully. To do this, follow these steps:
$RESTART is a reserved global symbol that the system maintains for you. $RESTART is true if one of your batch jobs was restarted after it was interrupted. Otherwise, $RESTART is false. You cannot delete the reserved global symbol $RESTART.
If a command procedure has SET RESTART_VALUE commands in it but you want the job to reexecute in its entirety, enter the SET ENTRY/NOCHECKPOINT command to delete the global symbol BATCH$RESTART. If you restart a job that was interrupted, the job starts executing in the section where it was interrupted.
This command procedure shows how to use restart values in a batch job:
To submit this command procedure as a batch job that can be restarted, use the /RESTART qualifier to the SUBMIT command when you submit the job. Because interrupted jobs begin executing in the section where they are interrupted, if this job is interrupted during the SORT_FILE routine, it starts executing at the label SORT_FILE when it is restarted.
Most of your process environment is not maintained when the system
fails. The only symbols maintained across a system failure are $RESTART
and BATCH$RESTART. Therefore, you should redefine any symbols or
process logical names used in your command procedure after each SET
RESTART_VALUE command or in a THEN block that executes if $RESTART is
The GOSUB command transfers control to a labeled subroutine in a command procedure. If the label does not exist in the command procedure, the procedure cannot continue executing and is forced to exit. (For complete information on labels, refer to Chapter 13.) You can nest the GOSUB command up to 16 times per procedure level.
The GOSUB command is a local subroutine call; it does not create a new procedure level. Consequently, all labels and local symbols defined in the current command level are available to a subroutine invoked with GOSUB.
The RETURN command terminates a subroutine and returns control to the command following the GOSUB command. You can specify a value for $STATUS with the RETURN command that overrides the value that DCL assigns to $STATUS at the end of the subroutine. This value must be an integer between zero and four or an equivalent expression. If you specify a value for $STATUS, DCL interprets this value as a condition code. If you do not specify a value for $STATUS, the current value of $STATUS is saved.
The following example shows how you can use the GOSUB command to transfer control to subroutines:
As you examine the example, note the following:
14.17 Creating New Command Levels
There are two ways to create new command levels:
14.17.1 Using the CALL Command
The CALL command transfers control to a labeled subroutine in a command procedure and creates a new procedure level. The CALL command allows you to keep more than one related command procedure in a single file, making the procedures easier to manage. The subroutine label, which must be unique, can precede or follow the CALL command in the command procedure. Chapter 13 contains rules for entering subroutine labels.
In addition to the label, you can pass up to eight optional parameters to the subroutine. For complete information on parameters, refer to Section 14.2.
Following are rules for using the CALL command:
22.214.171.124 CALL Command Defaults
Following are additional defaults associated with using the CALL command:
126.96.36.199 Beginning and Ending Subroutines
The SUBROUTINE and ENDSUBROUTINE commands define the beginning and the end of a CALL subroutine. The label defining the entry point to the subroutine immediately precedes the SUBROUTINE command. You can place the EXIT command immediately before the ENDSUBROUTINE command but it is not required to terminate the subroutine. The ENDSUBROUTINE command terminates the subroutine and transfers control to the command line immediately following the CALL command.
Command lines in a subroutine execute only when the subroutine is called with the CALL command. During the line-by-line execution of the command procedure, the command language interpreter skips all commands between the SUBROUTINE and the ENDSUBROUTINE commands.
The following restrictions apply to defining the scope of subroutine entry points and the use of label references:
In the following example, the call is not valid because the CALL BAR command is located outside of the MAIN subroutine:
For this CALL command to work, it must be placed within the SUBROUTINE and ENDSUBROUTINE points.
The call shown in this example in not allowed because it is within an IF-THEN-ELSE block:
The following example includes two subroutines called SUB1 and SUB2. The subroutines do not execute until they are called with the CALL command.
The CALL command invokes the subroutine SUB1 and directs output to the
file NAMES.LOG. Subroutine SUB1 calls subroutine SUB2. The procedure
executes SUB2, invoking the command procedure FILE.COM with the execute
procedure (@) command. When all the commands in SUB1 have executed, the
CALL command in the main procedure calls SUB2 a second time. The
procedure exits when SUB2 finishes executing.
A case statement is a special form of conditional code that executes one out of a set of command blocks, depending on the value of a variable or expression. Typically, the valid values for the case statement are labels at the beginning of each command block. The case statement passes control to the appropriate block of code by using the specified value as the target label in a GOTO statement.
To write a case statement, you must:
14.18.1 Listing the Labels
To list the labels, equate a symbol to a string that contains a list of the labels delimited by slashes (or any character you choose to act as a delimiter). This symbol definition should precede the command blocks.
The following example equates the symbol COMMAND_LIST to the labels PURGE, DELETE and EXIT:
14.18.2 Writing the Case Statement
To write the case statement, follow this procedure:
In the following example, the label is equated to the full command name. Therefore, F$LOCATE includes the delimiters in its search for the command name to ensure that the command is not abbreviated.
14.18.3 Writing the Command Blocks
Each block of commands may contain one or more commands. Begin each command block with a unique label. End each command block by passing control to a label outside the list of command blocks.
In the following example, each block of commands begins with a unique label (PURGE:, DELETE:) and is ended by passing control to a label (GOTO GET_COMMAND) outside of the current command block:
14.19 Writing Loops
You can write loops that test variables at the beginning of the command block (as described in Chapter 13). However, you can also write loops that test the termination variable at the end of the loop, by following this procedure:
Note that when you test the termination variable at the end of the loop, the commands in the body of the loop are executed at least once, regardless of the value in the termination variable.
Both of the command blocks shown in this example execute a loop that terminates when COMMAND equals "EX" (EXIT). F$EXTRACT truncates COMMAND to its first two characters. In the first example, COMMAND, the termination variable, is tested at the beginning of the loop; in the second, it is tested at the end of the loop.
To perform a loop a specific number of times, use a counter as the termination variable. In the following example, 10 file names are input by the user and placed into the local symbols FIL1, FIL2, ..., FIL10:
The following example uses a counter to control the number of times a loop executes. The loop executes 10 times; the termination variable is tested at the end of the loop:
The symbol COUNT is used to record the number of times the commands in the loop are executed. COUNT is also used to create the symbol names FILE_1, FILE_2, and so on to FILE_10. Note that the value of COUNT is incremented at the beginning of the loop but is tested at the end of the loop. Therefore, when COUNT is incremented from 9 to 10, the loop executes a last time (obtaining a value for FILE_10) before the IF statement finds a false result.
To perform a loop for a known sequence of values, use the F$ELEMENT lexical function. The F$ELEMENT lexical function obtains items from a list of items separated by delimiters. You must supply the item number, the item delimiter, and the list as arguments for F$ELEMENT.
For more information on how to use the F$ELEMENT lexical function, refer to the OpenVMS DCL Dictionary.
In the following example, the files CHAP1, CHAP2, CHAP3, CHAPA, CHAPB, and CHAPC are processed in order:
In the following example, the command procedure uses a loop to copy the files listed in the symbol FILE_LIST to a directory on another node:
The first file returned by the F$ELEMENT lexical function is CHAP1, the
next file is CHAP2, and so on. Each time through the loop, the value of
NUM is increased so that the next file name is obtained. When the
F$ELEMENT returns a slash, all the items from FILE_LIST have been
processed and the loop is terminated.
The PIPE command executes one or more DCL command strings from the same command line. It enables you to perform UNIX-style command processing, such as command pipelining, input/output redirection, and conditional and background execution.
This style of command processing supports the development and use of Internet software, which often expects some form of pipeline command parsing to be present on both host and target systems.
The following sections describe different methods of using the PIPE command to execute DCL commands, how to interrupt a PIPE command, and how to improve subprocess performance. There are also examples.
You can specify multiple DCL commands in a single PIPE command. The DCL commands are then executed sequentially. Use the following format:
A command sequence is executed conditionally depending on the execution result of the preceding command sequence. Use the format:
Note that command-sequence2 executes if and only if command-sequence1 succeeds. If you use the following format, command-sequence2 executes if and only if command-sequence1 fails.