HP OpenVMS Systems Documentation
HP BASIC for OpenVMS
Because an RFA requires six bytes of storage, BASIC has a special data type, RFA, that denotes variables that contain RFA information. Variables of data type RFA can be used only with the I/O statements and functions that use RFA information, and in comparison and assignment statements. You cannot print these variables or use them in any arithmetic operation. However, you can compare RFA variables using the equal to (=) and not equal to (<>) relational operators.
You cannot create named constants of the RFA data type. However, you can assign values from one RFA variable to another, and you can use RFA variables as parameters.
Accessing a record by RFA requires the following steps:
The GETRFA function returns the RFA of the last record accessed on a channel. Therefore, you must access a record in the file with a GET, FIND, or PUT statement before using the GETRFA function. Otherwise, GETRFA returns a zero, which is an invalid RFA.
The following example declares an array of type RFA containing 100 elements. After each PUT operation, the RFA of the record is assigned to an element of the array. Once the RFA information is assigned to a program variable or array element, you can use the RFA clause on a GET or FIND statement to retrieve the record.
DECLARE RFA R_array(1 TO 100) DECLARE LONG I MAP (XYZ) STRING A = 80 OPEN "TEST.DAT" FOR OUTPUT AS FILE #1, & SEQUENTIAL, MAP XYZ FOR I = 1% TO 100% . . . PUT #1 R_array(I) = GETRFA(1%) NEXT I
You can use the RFA clause on GET or FIND statements for any file organization; the only restriction is that the file must reside on a disk that is accessible to the node that is executing the program. An RFA value is only valid for the life of a specific version of a file. If a new version of a file is created, the RFA values might change. If you attempt to access a record with an invalid RFA value, HP BASIC signals a run-time error.
The following example continues the previous one. It randomly retrieves the records in a sequential file by using RFAs stored in the array.
DECLARE RFA R_array(1% TO 100%) DECLARE LONG I MAP (XYZ) STRING A = 80 OPEN "TEST.DAT" FOR OUTPUT AS FILE #1, & SEQUENTIAL, MAP XYZ FOR I = 1% TO 100% . . . PUT #1 R_array(I) = GETRFA(1%) NEXT I WHILE -1% PRINT "Which record would you like to see"; INPUT "(type a carriage return to exit)";Rec_num% EXIT PROGRAM IF Rec_num% = 0% GET #1, RFA R_array(Rec_num%) PRINT A NEXT
The PRINT # statement transfers program data to a terminal-format file. In the following example, the INPUT statements prompt the user for three values: S_name$, Area$, and Quantity%. Once these values are entered, the PRINT # statement writes these values to a terminal-format file that is open on channel #4.
FOR I% = 1% TO 10% INPUT "Name of salesperson":S_name$ INPUT "Sales district";Area$ INPUT "Quantity sold";Quantity% PRINT #4%, S_name$, Area$, Quantity% NEXT I%
If you do not specify an output list in the PRINT # statement, a blank
line is written to the terminal-format file. A PRINT statement without
a channel number transfers program data to a terminal. See
Chapter 5 for more information.
13.6.12 Resetting the File Position
The RESTORE # statement resets the current record pointer to the beginning of the file; it does not change the file. RESET # is a synonym for RESTORE. For example:
RESTORE #3%, KEY #2% RESET #3%
The RESTORE # statement restores the file in terms of the second alternate key. The RESET # statement restores the file in terms of the primary key.
The RESTORE # statement can be used by all RMS file organizations.
RESTORE without a channel number resets the data pointer for READ and
DATA statements but does not affect any files.
13.6.13 Truncating Files
The SCRATCH statement is valid only on sequential files. Although you cannot delete individual records from a sequential file, you can delete all records starting with the current record through to the end of the file. In order to do this, you must first specify ACCESS SCRATCH when you open the file.
To truncate the file, locate the first record to be deleted. Once the current record pointer points to this record, execute the SCRATCH statement. The following program locates the thirty-third record and truncates the file beginning with that record.
OPEN "MMM.DAT" AS FILE #2%, & SEQUENTIAL FIXED, ACCESS SCRATCH first_bad_record = 33% FIND #2%, RECORD first_bad_record SCRATCH #2% CLOSE #2% END
SCRATCH does not change the physical size of the file; it reduces the
amount of information contained in the file. (You can use the DCL
command SET FILE/TRUNCATE to truncate the excess file space.)
Therefore, you can write records with the PUT statement immediately
after a SCRATCH operation.
13.6.14 Renaming Files
If the security constraints permit, you can change the name or directory of a file with the NAME...AS statement. For example:
NAME "MONEY.DAT" AS "ACCOUNTS.DAT"
This statement changes the name of the file MONEY.DAT to ACCOUNTS.DAT.
The NAME...AS statement can change only the name and directory of a file; it cannot be used to change the device name.
You must always include an output file type because there is no
default. If you use the NAME...AS statement on an open file, the new
name does not take effect until you close the file.
13.6.15 Closing Files and Ending I/O
All programs should close files before the program terminates. However, files are automatically closed in the following situations:
Files are not closed after executing a STOP, END SUB, END FUNCTION, or END PICTURE statement.
The CLOSE statement closes files and disassociates these files and their buffers from the channel numbers. If the file is a magnetic tape device and the data is written to a tape, CLOSE writes trailer labels at the end of the file. The following is an example of the CLOSE statement:
CLOSE #1% B% = 4% CLOSE #2%, B%, 7% CLOSE I% FOR I% = 1% TO 20%
If the security constraints permit, you can delete a file with the KILL statement. For example:
This statement deletes the file named TEST.DAT. Note that this statement deletes only the most current version of the file. Do not omit the file type, because there is no default. You can delete only one file at a time; to delete all versions of a file matching a file specification, use the Run-Time Library routine LIB$DELETE_FILE.
You can delete a file that is currently being accessed by other users; however, the file is not deleted until all users have closed it. You cannot open or access a file once you have deleted it.
1 Record File Addresses do not exist for terminal-format files.
The following built-in functions are provided for finding:
These functions are discussed in the following sections.
13.7.1 FSP$ Function
If you do not know the organization of a file, you can find out by opening the file for input with the ORGANIZATION UNDEFINED and RECORDTYPE ANY clauses. Your program can then use the FSP$ function to determine the characteristics of that file. Your program must execute FSP$ immediately after the OPEN FOR INPUT statement. For example:
RECORD FSP_data VARIANT CASE BYTE Org BYTE Rat WORD Max_record_size LONG File_size WORD Bucketsize_blocksize WORD Num_keys LONG Max_record_number CASE STRING Ret_string = 16 END VARIANT END RECORD DECLARE FSP_data File_chars OPEN "FIL.DAT" FOR INPUT AS FILE #1%, & ORGANIZATION UNDEFINED, & RECORDTYPE ANY, ACCESS READ File_chars::Ret_string = FSP$(1%)
The following list explains the above example:
Note that FSP$ returns zeros in bytes 9 to 12. For more information,
see the OpenVMS Record Management Services Reference Manual.
13.7.2 RECOUNT Function
Read operations can transfer varying amounts of data. The system variable RECOUNT contains the number of characters (bytes) read after each read operation.
After a read operation from your terminal, RECOUNT contains the number of characters transferred, including the line terminator. After accessing a record, RECOUNT contains the number of characters in the record.
RECOUNT is reset by every read operation on any channel, including the controlling terminal. Therefore, if you need to use the value of RECOUNT, copy it to another variable before executing another read operation. RECOUNT is undefined if an error occurs during a read operation.
RECOUNT is often used as the argument to the COUNT clause in the UPDATE or PUT statement for variable-length files. The following sequence of statements ensures that the output record on channel #5 is the same length as the input record on channel #4:
GET #4% bytes_read% = RECOUNT . . . PUT #5%, COUNT bytes_read%
The STATUS function accesses the status longword that contains characteristics of the last opened file. If an error occurs during an input operation, the value of STATUS is undefined. If an error does not occur, the six low-order bits of the returned value contain information about the type of device accessed by the last input operation. These bits correspond to the following devices:
Both the VMSSTATUS and RMSSTATUS functions are used to determine which
non-BASIC error caused a resulting BASIC error. In particular,
VMSSTATUS can be used for any non-BASIC errors, while RMSSTATUS is used
specifically for RMS errors. For more information about these
functions, see Chapter 15 and the HP BASIC for OpenVMS Reference Manual.
13.8 OPEN Statement Options
This section explains the OPEN statement keywords that enable you to control how a file is created or opened. These keywords are:
The BUCKETSIZE clause applies only to relative and indexed files. A bucket is a logical storage structure that RMS uses to build and maintain relative and indexed files on disk devices. A bucket consists of one or more disk blocks. The default bucket size is the record size rounded up to a block boundary. Although RMS defines the bucket size in terms of disk blocks, the BUCKETSIZE clause specifies the number of records a bucket contains. For example:
OPEN "STOCK_DATA.DAT" FOR OUTPUT AS FILE #1%, & ORGANIZATION RELATIVE FIXED, BUCKETSIZE 12%
This example specifies a bucket containing approximately 12 records. RMS reads in entire buckets into the I/O buffer at once, and a GET statement transfers one record from the I/O buffer to your program's record buffer.
When you open an existing relative or indexed file and specify a bucket size other than that originally assigned to the file, BASIC signals the error, "File attributes not matched" (ERR=160).
Records cannot span bucket boundaries. Therefore, when you specify a bucket size in your program, you must consider the size of the largest record in the file. Note that a bucket must contain at least one record. Buckets in both relative and indexed files contain information in addition to the records stored in the bucket. You should take this into consideration.
There are two ways to establish the number of blocks in a bucket. The first is to use the default. The second is to specify the approximate number of records you want in each bucket. A bucket size based on that number is then calculated.
A default bucket size is selected depending on the:
If you do not define the BUCKETSIZE clause in the OPEN statement, BASIC does the following:
Note that when you specify a bucket size for files in your program, you must keep in mind the space versus speed tradeoffs. A large bucket size increases file processing speed because a greater amount of data is available in memory at one time; however, it also increases the memory space needed for buffer allocation and the processing time required to search the bucket. Conversely, a small bucket size minimizes buffer requirements, but increases the number of accesses to the storage device, thereby decreasing the speed of operations.
It is recommended that you use the DCL command EDIT/FDL to design files
used in production applications where performance is a concern.
13.8.2 BUFFER Clause
The BUFFER clause applies to disk files of any organization. In the case of sequential files, the BUFFER clause sets the number of blocks read in on each disk access. For relative and indexed files, the BUFFER clause determines the number of I/O buffers that are allocated. In general, the OpenVMS operating system supplies adequate defaults for all file types; therefore, the BUFFER clause is rarely necessary.
You can specify up to 127 buffers as either a positive or a negative number:
The CONNECT clause can be used only on indexed files. CONNECT lets you process different groups of records on different indexed keys or on the same key without incurring all of the RMS overhead of opening the same file more than once. For example, a program can read records in an indexed file sequentially by one key and randomly by another. Each stream is an independent, active series of record operations.
MAP (Indmap) WORD Emp_num, & STRING Emp_last_name = 20, & SINGLE Salary, & STRING Wage_code = 2 OPEN "IND.DAT" FOR INPUT AS FILE #1%, & ORGANIZATION INDEXED, & MAP Indmap, & PRIMARY KEY Emp_num, & ALTERNATE KEY Emp_last_name . . . OPEN "IND.DAT" FOR INPUT AS FILE #2% & ORGANIZATION INDEXED, & MAP Indmap, & CONNECT 1
The channel on which you open the file for the first time is called the parent. The CONNECT clause specifies another channel on which you access the same file; connected channels are called children. More than one OPEN statement can connect to the parent channel; however, you cannot connect to a channel that has already been connected to another channel.
Do not use the CONNECT clause when accessing files on remote DECnet
13.8.4 CONTIGUOUS Clause
A contiguous file with physically adjoining blocks minimizes disk searching and decreases file access time. Once the system knows where a contiguous file starts on the disk, it does not need to use as many retrieval pointers to locate the pieces of that file. Rather, it can access data by calculating the distance from the beginning of the file to the desired data. If there is not enough contiguous disk space, BASIC allocates as much contiguous space as possible. (For truly contiguous records, you must use the USEROPEN clause and set the CTG bit in the FAB FOP field---see the OpenVMS Record Management Services Reference Manual.)
Opening a file with both the FILESIZE and CONTIGUOUS clauses
pre-extends the file contiguously or in as few disk extents as possible.
13.8.5 DEFAULTNAME Clause
The DEFAULTNAME clause in the OPEN statement lets you specify a default file specification for the file to be opened. It is valid with all file organizations. BASIC uses the DEFAULTNAME clause for any part of the file specification that is not explicitly supplied.
LINPUT "Next data file";Fil$ OPEN Fil$ FOR INPUT AS FILE #5%, & ORGANIZATION SEQUENTIAL, & DEFAULTNAME "USER$DEVICE:.DAT"
The DEFAULTNAME clause supplies default values for the device, directory, and file type portions of the file specification. Typing ABC in response to the Next data file? prompt causes BASIC to try to open USER$DEVICE:ABC.DAT.
BASIC uses the DEFAULTNAME values only if you do not supply those parts
of the file specification appearing in the DEFAULTNAME clause. For
example, if you type SYS$DEVICE:ABC in response to the prompt, BASIC
tries to open SYS$DEVICE:ABC.DAT. In this case, SYS$DEVICE: overrides
the device default in the DEFAULTNAME clause. Any part of the file
specification still missing is filled in from the current default
device and directory of the process.
13.8.6 EXTENDSIZE Clause
The EXTENDSIZE attribute determines how many disk blocks RMS adds to the file when the current allocation is exhausted. The EXTENDSIZE clause only has an effect when creating a file. You specify EXTENDSIZE as a number of blocks. For example:
OPEN "TSK.ORN" FOR OUTPUT AS FILE #2%, & ORGANIZATION RELATIVE, EXTENDSIZE 128%
The EXTENDSIZE clause causes RMS to add 128 disk blocks whenever the current space allocation is exhausted and the file must be extended.
The value you specify must conform to the following requirements:
If you specify zero, the extension size equals the RMS default value.
The EXTENDSIZE value can be overridden for single OPEN operations.
13.8.7 FILESIZE Clause
With the FILESIZE attribute, you can allocate disk space for a file when you create it. The following statement allocates 50 blocks of disk space for the file VALUES.DAT:
OPEN "VALUES.DAT" FOR OUTPUT AS FILE #3%, FILESIZE 50%
Pre-extending a file has several advantages: