OpenVMS User's Manual
14.12.2 Using the /INDEX and /KEY Qualifiers
To read records randomly from indexed sequential files, use the READ
command qualifiers /INDEX and /KEY. These qualifiers specify that a
record should be read from the file by finding the specified key in the
index and returning the record associated with that key. If you do not
specify an index, the primary index (0) is used.
After you read a record randomly, you can read the remainder of the
file sequentially by using READ commands without the /KEY or /INDEX
qualifiers.
14.12.3 Using the /DELETE Qualifier
You can use the READ command with the /DELETE qualifier to delete
records from indexed sequential files. The /DELETE qualifier causes a
record to be deleted from a file after it has been read. Use the
/DELETE qualifier with the /INDEX and /KEY qualifiers to delete a
record specified by a given key.
For more information about the /DELETE, /INDEX, and /KEY qualifiers,
refer to the description of the READ command in the OpenVMS DCL Dictionary.
14.13 Using the Close Command
The CLOSE command closes a file and deassigns the logical name created
by the OPEN command. Be sure to close all files you open in a command
procedure before the command procedure terminates. If you fail to close
an open file, the file remains open when the command procedure
terminates and the logical name assigned to the open file is not
deleted from the process logical name table.
In the following example, the CLOSE command closes the file STATS.DAT
and deassigns the logical name INFILE:
$ OPEN INFILE DISK4:[MURPHY]STATS.DAT
.
.
.
$ CLOSE INFILE
|
14.14 Modifying Files
This section describes three methods of modifying files:
- Updating records
- Creating new output files
- Appending records
14.14.1 Updating Records
When you use the updating method to modify records, you can make minor
changes to a small number of records in a file. Because this method
does not allow you to change the size of a record or the number of
records in the file, use it only for files with formatted records (for
example, in a data file).
To make minor changes in a file, use this procedure:
| Step |
Action |
|
1
|
Open the file for both read and write access.
|
|
2
|
Use the READ command to read through the file until you reach the
record that you want to modify.
|
|
3
|
Modify the record.
In a sequential file, the text of this record must be exactly the
same size as the original record. If the text of the modified record is
shorter, pad the record with spaces, adding spaces to the end of the
modified record until it is the same length as the original record. If
the text of the modified record is longer, you need to create a new
file.
|
|
4
|
Use the WRITE/UPDATE command to write the modified record back to the
file.
|
|
5
|
Repeat steps 2 to 4 until you have changed all records you intend to
change.
|
|
6
|
Use the CLOSE command to close the file.
After you close the file, it contains the same version number as
when you started, even though individual records have been changed.
|
The following command procedure shows how to make changes to a
sequential file by reading and updating individual records:
$! Open STATS.DAT and assign it the logical name FILE
$!
$ OPEN/READ/WRITE FILE DISK4:[MURPHY]STATS.DAT
$ BEGIN_LOOP:
$! Read the next record from FILE into the symbol RECORD
$ READ/END_OF_FILE=END_LOOP FILE RECORD
$! Display the record and see if the user wants to change it
$! If yes, get the new record. If no, repeat loop
$!
$ PROMPT:
$ WRITE SYS$OUTPUT RECORD
$ INQUIRE/NOPUNCTUATION OK "Change? Y or N [Y] "
$ IF OK .EQS. "N" THEN GOTO BEGIN_LOOP
$ INQUIRE NEW_RECORD "New record"
$! Compare the old and new records
$! If old record is shorter than new record, issue an
$! error message. If old record and new record are the
$! same length, write the record. Otherwise pad the new
$! record with spaces so it is correct length
$!
$ OLD_LEN = F$LENGTH(RECORD)
$ NEW_LEN = F$LENGTH(NEW_RECORD)
$ IF OLD_LEN .LT. NEW_LEN THEN GOTO ERROR
$ IF OLD_LEN .EQ. NEW_LEN THEN GOTO WRITE_RECORD
$ SPACES = " "
$ PAD = F$EXTRACT(0,OLD_LEN-NEW_LEN,SPACES)
$ NEW_RECORD = NEW_RECORD + PAD
$!
$ WRITE_RECORD:
$ WRITE/UPDATE FILE NEW_RECORD
$ GOTO BEGIN_LOOP
$!
$ ERROR:
$ WRITE SYS$OUTPUT "Error -- New record is too long"
$ GOTO PROMPT
$!
$ END_LOOP:
$ CLOSE FILE
$ EXIT
|
The system displays the record on the terminal and you are asked
whether the record needs to be modified. If you choose to modify the
record, a new record is read from the terminal and its length is
compared to the length of the original record. If the original record
is longer, extra spaces make the new record the same size. If the
original record is shorter, the system displays an error message and
you are again prompted for a new record.
14.14.2 Creating New Output Files
To make extensive changes to a file, open that file for read access and
open a new file for write access. Because you are creating a new output
file, you can modify the size of records, add records, delete records,
or insert records.
The OPEN/WRITE command opens a new file for write access. The new file
can have the same name as the original file and a version number one
higher than the version number of the old file.
Note
To ensure that the correct file is opened for reading, you must open
the existing file for read access before you open the new version for
write access.
|
To create files that you can modify, use the following procedure:
| Step |
Action |
|
1
|
Open the file for read access.
This is the input file, the file you are modifying.
|
|
2
|
Open a new file for write access.
This is the output file, the file that you are creating. If you
give the output file the same name as the input file, the output file
will have a version number one greater than the input file.
|
|
3
|
Use the READ command to read each record from the file you are
modifying.
As you read each record from the original file, decide how the
record is to be treated.
|
|
4
|
Continue reading and processing records until you have finished.
|
|
5
|
Use the CLOSE command to close both the input file and the output file.
|
In the following table, the symbol RECORD contains the record read from
the original file:
| If The Record is |
Then |
|
Not changed
|
Write the same symbol to the new file.
|
|
Changed
|
Use the INQUIRE command to read a different record into the symbol,
then write the modified symbol to the new file.
|
|
Deleted
|
Do not write the symbol to the new file.
|
|
Inserted
|
Use a loop to read records into the symbol and to write the symbol to
the new file.
|
Examples: Modifying Records
- In the following example, the symbol NEW_FILE is written to a new
file:
$ ! No change
$ WRITE NEW_FILE RECORD
|
- In the following example, the INQUIRE command is used to write a
modified symbol to a new file:
$ ! Change
$ INQUIRE NEW_RECORD "New record"
$ WRITE NEW_FILE NEW_RECORD
|
- In the following example, a loop is used to write the symbol to a
new file:
$ ! Insertion
$LOOP:
$ !Get new records to insert
$ INQUIRE NEW_RECORD "New record"
$ IF RECORD .EQS. "" THEN GOTO END_LOOP
$ WRITE NEW_FILE NEW_RECORD
$ GOTO LOOP
$END_LOOP:
|
Example: Creating Output Files
The following example shows a command procedure that reads a record
from an input file, processes the record, and copies the record into an
output file:
$! Open STATS.DAT for reading and assign it
$! the logical name INFILE
$! Open a new version of STATS.DAT for writing
$! and assign it the logical name OUTFILE
$!
$ OPEN/READ INFILE DISK4:[MURPHY]STATS.DAT
$ OPEN/WRITE OUTFILE DISK4:[MURPHY]STATS.DAT
$!
$ BEGIN_LOOP:
$! Read the next record from INFILE into the symbol RECORD
$!
$ READ/END_OF_FILE=END_LOOP INFILE RECORD
$! Display the record and see if the user wants to change it
$! If yes, get the new record
$! If no, write record directly to OUTFILE
$!
$ PROMPT:
$ WRITE SYS$OUTPUT RECORD
$ INQUIRE/NOPUNCTUATION OK "Change? Y or N [Y] "
$ IF OK .EQS. "N" THEN GOTO WRITE_RECORD
$ INQUIRE RECORD "New record"
$!
$ WRITE_RECORD:
$ WRITE OUTFILE RECORD
$ GOTO BEGIN_LOOP
$!
$! Close input and output files
$ END_LOOP:
$ CLOSE INFILE
$ CLOSE OUTFILE
$ EXIT
|
14.14.3 Appending Records to Files
Use the following procedure (OPEN/APPEND command) to append records to
the end of existing files:
| Step |
Action |
|
1
|
Use the OPEN command with the /APPEND qualifier to position the record
pointer at the end of the file.
The /APPEND qualifier does not create a new version of the file.
|
|
2
|
Use the WRITE command to write new data records.
|
|
3
|
Continue adding records until you are finished.
|
|
4
|
Use the CLOSE command to close the file.
|
The following command procedure appends records to the end of the file
named STATS.DAT:
$! Open STATS.DAT to append files and assign
$! it the logical name FILE
$!
$ OPEN/APPEND FILE DISK4:[MURPHY]STATS.DAT
$!
$ BEGIN_LOOP:
$! Obtain record to be appended and place this
$! record in the symbol RECORD
$!
$ PROMPT:
$ INQUIRE RECORD -
"Enter new record (press RET to quit) "
$ IF RECORD .EQS. "" THEN GOTO END_LOOP
$! Write record to FILE
$!
$ WRITE FILE RECORD
$ GOTO BEGIN_LOOP
$!
$! Close FILE and exit
$!
$ END_LOOP:
$ CLOSE FILE
$ EXIT
|
14.15 Handling File I/O Errors
Use the /ERROR qualifier with the OPEN, READ, or WRITE command to
suppress system error messages and to pass control to a specified
label. If an error occurs during an input or output operation, the
/ERROR qualifier overrides all other error-control mechanisms (except
the /END_OF_FILE qualifier on the READ command).
The following example uses the /ERROR qualifier with the OPEN command:
$ OPEN/READ/ERROR=CHECK FILE CONTINGEN.DOC
.
.
.
$ CHECK:
$ WRITE SYS$OUTPUT "Error opening file"
|
The OPEN command requests that the file CONTINGEN.DOC be opened for
reading. If the file cannot be opened (for example, if the file does
not exist), the OPEN command returns an error condition and transfers
control to the CHECK label.
The error path specified by the /ERROR qualifier overrides the current
ON condition established for the command level. If an error occurs and
the target label is successfully given control, the reserved global
symbol $STATUS retains the code for the error. You can use the
F$MESSAGE lexical function in your error-handling routine to display
the message in $STATUS.
In the following example, the lexical function F$MESSAGE is used to
display the contents of the F$STATUS lexical:
$ OPEN/READ/ERROR=CHECK FILE 'P1'
.
.
.
$ CHECK:
$ ERR_MESSAGE = F$MESSAGE($STATUS)
$ WRITE SYS$OUTPUT "Error opening file: ",P1
$ WRITE SYS$OUTPUT ERR_MESSAGE
.
.
.
|
14.15.1 Default Error Actions
If an error occurs while you are using the OPEN, READ, WRITE, or CLOSE
command and you do not specify an error action, the current ON command
action is taken.
When a READ command receives an end-of-file message, the error action
is determined as follows:
- If you use the /END_OF_FILE qualifier, control is passed to the
specified label.
- If you do not use the /END_OF_FILE qualifier, control is passed to
the label specified with the /ERROR qualifier.
- If you do not specify either qualifier (/END_OF_FILE or /ERROR),
the current ON command action is taken.
14.16 Techniques for Controlling Execution Flow
The normal flow of execution in a command procedure is sequential: the
commands in the procedure execute in order until the end of the file is
reached. However, you can also control whether certain statements are
executed or the conditions under which the procedure should continue
executing.
The following sections discuss:
- The DCL commands that you can use to control or alter the flow of
execution:
- IF, THEN, ELSE
- GOTO
- GOSUB
- CALL
- Using command blocks
- Writing case statements
- Writing loops
14.16.1 Using the IF Command
The IF command tests the value of an expression and executes a command
or block of commands when the result of the expression is true. When
the result of the expression is false, one of the following occurs:
- When one command follows the THEN command, it is not executed and
the following command executes.
- When a block of commands follows the THEN command and the ELSE
command is not specified, the command immediately following the ENDIF
command executes.
- When the ELSE command is specified, the command or block of
commands following the ELSE command executes.
DCL provides two distinct formats for the IF command. The first format
executes a single command when the expression specified to the IF
command is true, as discussed in Chapter 13.
DCL also provides a block-structured IF format. The block-structured IF
command executes more than one command if the expression specified is
true and accepts an optional ELSE statement, which executes one or more
commands if the expression is false.
14.16.2 Using the THEN Command
To execute more than one command when an expression is true, specify
the THEN command as a verb (a DCL command preceded by a dollar sign)
and terminate the resulting block-structured statement with an ENDIF
statement.
In the following example, the THEN statement is used as a verb:
$ IF expression
$ THEN
$ command
$ command
.
.
.
$ ENDIF
|
14.16.3 Using the ELSE Command
To execute one or more commands when an expression is false, specify
the ELSE statement as a verb and terminate the resulting
block-structured statement with an ENDIF statement.
In the following example, the ELSE command is used as a verb:
$ IF expression
$ THEN
$ command
$ command
.
.
.
$ ELSE
$ command
$ command
.
.
.
$ ENDIF
|
14.16.4 Using Command Blocks
Command blocks can be executed in several ways, depending on whether
you leave the commands in the same command procedure or put them in
another command procedure and execute them there. The guidelines are as
follows:
- If you leave the commands in the command procedure, place them
after the THEN statement. For example:
$ IF condition
$ THEN command
command
.
.
.
$ ENDIF
|
- If you place the commands in a separate procedure, make the call to
that command procedure as part of the THEN statement. For example:
$ IF condition
$ THEN @command_procedure
$ ELSE command
$ command
$ ENDIF
|
- You can continue to specify the nonblock-structured IF format and
direct flow to a labeled region when the condition specified is met.
For example:
$ IF not condition THEN GOTO END_LABEL
.
.
.
$END_LABEL:
|
You can execute a block of commands after the THEN command when the
result of the IF expression is true. When you use a block of commands,
place the THEN command as the first command on the line following the
IF command.
In the following example, two SET TERMINAL commands execute and the
procedure transfers control to the label PROCEED when F$MODE equals
"INTERACTIVE". When F$MODE does not equal
"INTERACTIVE", the procedure exits.
$ IF F$MODE () .EQS. "INTERACTIVE"
$ THEN
$ SET TERMINAL/DEVICE=VT320
$ SET TERMINAL/WIDTH=132
$ GOTO PROCEED
$ ENDIF
$ EXIT
$PROCEED:
|
The following example illustrates how to use a block of commands with
the IF command in conjunction with the ELSE command:
$ INQUIRE DEV "Device to check"
$ IF F$GETDVI(DEV, "EXISTS")
$ THEN
$ WRITE SYS$OUTPUT "The device exists."
$ SHOW DEVICE 'DEV'
$ SET DEVICE/ERROR_LOGGING 'DEV'
$ ELSE
$ WRITE SYS$OUTPUT "The device does not exist."
$ WRITE SYS$OUTPUT "Error logging has not been enabled."
$ ENDIF
$ EXIT
|
When the condition is true, the procedure writes a message to
SYS$OUTPUT and executes the SHOW DEVICE and SET DEVICE commands. When
the condition is not true, the procedure writes two messages to
SYS$OUTPUT.
When you use the IF-THEN-ELSE language construct, observe the following
restrictions:
- Include no more than 15 levels of nested IF statements.
- Terminate a command block started by a THEN statement with either
an ELSE or an ENDIF statement.
- Terminate a command block started by an ELSE statement with an
ENDIF statement.
- Include a THEN statement as the first executable statement
following an IF statement.
- Do not specify a label on a line containing a THEN or an ELSE
statement. You can, however, specify a label on a line containing an
ENDIF statement. Programs can branch within the current command block
but branching into the middle of another command block is not
recommended.
True Expressions
The expression following the IF command can consist of one or more
numeric constants, string literals, symbolic names, or lexical
functions separated by logical, arithmetic, or string operators. An
expression is true when it has one of the following values:
- An odd integer value
- A character string value that begins with any of the letters Y, y,
T, or t
- A character string value that contains numbers that form an integer
with an odd value (for example, the string "27")
False Expressions
An expression is false when it has one of the following values:
- An even integer value
- A character string value that begins with any letter other than Y,
y, T, or t
- A character string value that contains numbers that form an integer
with an even value (for example, the string "28")
Writing Expressions
When you write an expression for an IF command, adhere to the following
rules:
- When you use symbols in IF statements, their values are
automatically substituted. Do not use apostrophes (') as substitution
operators unless you need to force iterative translation.
- String comparison operators end in the letter S. For example, use
operators such as .EQS., .LTS., and .GTS. to compare strings. By
contrast, the operators .EQ., .LT., and .GT. are used for comparing
integers.
- When you test to see whether two strings are equal, the strings
must use the same case in order for DCL to find a match. That is, the
string "COPY" does not equal the string "copy" or
the string "CoPy."
The following examples illustrate expressions that can be used with the
IF command. For additional examples, refer to the description of the IF
command in the OpenVMS DCL Dictionary.
The first example uses a logical operator and executes only one command
following the THEN statement. When the symbol CONT is not true, the
procedure exits.
$ INQUIRE CONT "Do you want to continue [Y/N]"
$ IF .NOT. CONT THEN EXIT
.
.
.
|
The following example uses a symbol and a label within the IF
expression:
$ INQUIRE CHANGE "Do you want to change the record [Y/N]"
$ IF CHANGE THEN GOTO GET_CHANGE
.
.
.
$ GET_CHANGE:
.
.
.
|
When the symbol CHANGE is true, the procedure transfers control to the
label GET_CHANGE. Otherwise, the procedure executes the command
following the IF command.
The next example illustrates two different IF commands:
$ COUNT = 0
$ LOOP:
$ COUNT = COUNT + 1
$ IF COUNT .EQ. 9 THEN EXIT
$ IF P'COUNT' .EQS. "" THEN EXIT
.
.
.
$ GOTO LOOP
|
The first IF command compares two integers; the second IF command
compares two strings. Note that the .EQ. operator is used for the
integer comparison and the .EQS. operator is used for the string
comparison.
First, the value of COUNT is compared to the integer 9. When the values
are equal, the procedure exits; when the values are not equal, the
procedure continues. The loop terminates after eight parameters (the
maximum number allowed) have been processed.
In the second IF expression, the string value of the symbol P'COUNT' is
compared to a null string to see whether the symbol is undefined. Note
that you must use apostrophes to force iterative substitution of the
symbol COUNT. For example, when COUNT is 2, the result of the first
translation is P2. Then, the value of P2 is used in the string
comparison.
You can also execute a separate command procedure when the result of
the IF expression is true. The following example executes the command
procedure EXIT_ROUTINE.COM when the result of the IF expression is true:
$ GET_COMMAND_LOOP:
$ INQUIRE COMMAND -
"Enter command (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE)"
$ IF COMMAND .EQS. "EXIT" THEN @EXIT_ROUTINE
|
|