# Compaq BASIC for OpenVMS
Alpha and VAX Systems
User Manual

Previous | Contents | Index

## 14.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%

## 14.7.3 STATUS, VMSSTATUS, and RMSSTATUS Functions

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:

- If bit 0 is set, the device type is a record-oriented device.
- If bit 1 is set, the device type is a carriage control device.
- If bit 2 is set, the device type is a terminal.
- If bit 3 is set, the device type is a directory oriented device.
- If bit 4 is set, the device type is a single directory device.
- If bit 5 is set, the device type is a sequential block-oriented device (magnetic tape or TK50).

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 16 and the Compaq BASIC for OpenVMS Alpha and VAX Systems Reference Manual.

# 14.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 as follows:

> BUCKETSIZE
> BUFFER
> CONNECT
> CONTIGUOUS
> DEFAULTNAME
> EXTENDSIZE
> FILESIZE
> NOSPAN
> RECORDTYPE
> TEMPORARY
> USEROPEN
> WINDOWSIZE

## 14.8.1 BUCKETSIZE Clause

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.

The default bucket size assigned to relative and indexed files is as small as possible. A small bucket size, however, is rarely desirable.

A default bucket size is selected depending on:

- The record length
- The file organization (relative or indexed)
- The record format

If you do not define the BUCKETSIZE clause in the OPEN statement, BASIC does the following:

- Assumes that there is a minimum of one record in the bucket
- Calculates a size
- Assigns the appropriate number of blocks

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.

## 14.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:

- If (0 < BUFFER < 127), RMS allocates enough space for the specified number of buckets.
- If (-128 < BUFFER < 0), BASIC allocates the absolute value of the specified number of buffers.
- If (BUFFER=0), BASIC allocates the process default for the particular file organization and device---this value is usually adequate.

## 14.8.3 CONNECT Clause

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 nodes.

## 14.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.

## 14.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.

## 14.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:

- It must be specified when you create the file
- It cannot exceed 65,535 disk blocks

If you specify zero, the extension size equals the RMS default value. The EXTENDSIZE value can be overridden for single OPEN operations.

## 14.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:

- The system can create a complete directory structure for the file, instead of allocating and mapping additional disk blocks when needed.
- You reserve the needed disk space for your application. This ensures that you do not run out of space when the program is running.
- Pre-extension can make some of the file's disk blocks contiguous, especially when used with the CONTIGUOUS keyword.

Note that pre-extension can be a disadvantage if it allocates disk space needed by other users. The FILESIZE clause is ignored when BASIC opens an existing file.

## 14.8.8 NOSPAN Clause

By default, sequential files allow records to cross or span block boundaries. If records cross block boundaries, RMS packs records into the file end-to-end throughout the file, leaving space for control information and padding.

The NOSPAN clause overrides this default, forcing records to fit into individual blocks (with space provided for control information and padding). When block boundaries restrict records, fixed-length records must be less than 512 bytes, and variable-length records less than 510 bytes. This can waste extra bytes at the end of each block. However, when records span block boundaries, RMS writes records end-to-end without regard for block boundaries. For example, if you specify NOSPAN, only four 120-byte records fit into a disk block. If you do not specify NOSPAN, BASIC begins writing the fifth record in the block, and continues writing that record in the next block. This minimizes wasted disk space and improves the file's capacity, at the minimal expense of increased processing overhead.

## 14.8.9 RECORDTYPE Clause

The RECORDTYPE clause lets you specify record formats that are compatible with files created by other language processors. You can choose one of four qualifiers: LIST, FORTRAN, ANY, and NONE. The default for BASIC is LIST, which specifies carriage return format. This is standard for ASCII text files and means that carriage control is performed by RMS when writing the file to a unit-record device.

If your program accesses a file created with a Fortran language processor, use the FORTRAN qualifier. In the following example, the FORTRAN qualifier sets the FORTRAN carriage control attribute in the RAT field in the FAB. For more information about the FAB control structure, see Section 14.8.11. The first byte of the record is assumed to be the carriage control information. For example:

    OPEN "FIL.DAT" FOR INPUT AS FILE #1%,      &
         ORGANIZATION SEQUENTIAL, RECORDTYPE FORTRAN

If your program accesses a file created by an unknown language processor or by DCL, use the ANY qualifier; this qualifier causes BASIC to handle any record attribute type. If you create a file with the ANY qualifier, BASIC uses the default of LIST. For example:

    OPEN "FIL.DAT" FOR INPUT AS FILE #1%,       &
         ORGANIZATION INDEXED, RECORDTYPE ANY

## 14.8.10 TEMPORARY Clause

If you specify the TEMPORARY clause in the OPEN statement, BASIC deletes that file in any one of the following cases:

- When you close the file
- When the program aborts or exits
- When your process terminates

No entry for this file is made in any directory.

## 14.8.11 USEROPEN Clause

The USEROPEN clause specifies an external long function that BASIC executes when you open or create a file. (You do not need to declare the USEROPEN routine with an EXTERNAL FUNCTION statement.) This procedure can then specify additional OPEN parameters for the file. For example:

    OPEN "FILE.DAT" FOR INPUT AS FILE #2%,      &
         ORGANIZATION INDEXED, USEROPEN Myopen, MAP ABC

The code in Myopen determines how the file FILE.DAT is opened. The Run-Time Library sets up six RMS control structures before calling the USEROPEN procedure. Table 14-4 defines these structures and their meanings.

Table 14-4 RMS Control Structures Set for the USEROPEN Clause
Structure | Definition
--- | ---
FAB | File Access Block
RAB | Record Access Block
NAM | Name Block
XAB | FHC Extended Attributes Block
ESA | Expanded Name String
RSA | Resultant Name String

A USEROPEN procedure should not alter the allocation of these structures, although it can modify the contents of many of the fields. You should not modify fields set by other OPEN statement keywords. For example, you should use the RECORDSIZE clause, not a USEROPEN routine, to set the record length.

The allocation of the RMS control structures (except for the RAB) lasts only for the duration of the OPEN statement. Therefore, your USEROPEN can retain only the RAB address for use after the OPEN operation is complete. Note that any additional structures that you allocate and link into the RMS structures must be unlinked before exiting the USEROPEN.

Note Future releases of the OpenVMS Run-Time Library might alter the use of some RMS fields. Therefore, you might have to alter your USEROPEN procedures accordingly.

The following steps describe the execution of the USEROPEN routine:

1. BASIC performs normal OPEN statement processing up to the point where it would call the RMS OPEN/CREATE and CONNECT routines. BASIC then passes control to the USEROPEN routine.
2. BASIC passes the address of the FAB as the first parameter, the address of the RAB as the second parameter, and the address of the user-specified channel number as the third parameter to the routine.
3. The USEROPEN routine can modify the contents of the RMS control structures, and it must call the RMS OPEN or RMS CREATE routine and the RMS CONNECT routine and return the status in R0.

Example 14-1 shows how to create a USEROPEN routine to obtain a RAB address.

Example 14-1 Creating a USEROPEN Routine

    %TITLE  "Example USEROPEN"
    %SBTTL  "Useropen Routine to obtain RAB address"
    %IDENT  "Version 1.1"

    FUNCTION LONG Get_rab_address ( Fabdef User_fab, Rabdef User_rab, LONG Channel )
    !++
    ! FUNCTIONAL DESCRIPTION:
    !
    !   Save the address of the RMS Record Access Block allocated by the caller
    !   in a global symbol.  Open the file and return the status from RMS.
    !
    ! FORMAL PARAMETERS (Standard for all BASIC USEROPEN procedures)
    !
    !   User_fab    Address of RMS File Access Block
    !   User_rab    Address of RMS Record Access Block
    !   Channel     Logical Unit assigned to file by caller.
    !
    ! RETURN VALUE:    RMS Status value
    !
    ! GLOBAL COMMON USAGE
    !
    !   RAB_ptr     Single longword PSECT used to pass RAB address to caller.
    !
    !--
        OPTION  INACTIVE = SETUP,           &
             CONSTANT TYPE = INTEGER,       &
             TYPE = EXPLICIT

        %NOLIST
        %INCLUDE "$FABDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET"
        %INCLUDE "$RABDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET"
        %INCLUDE "$RMSDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET"
        %INCLUDE "STARLET" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET"
        %LIST
        !+
        !   Common area used to pass RAB address to caller.
        !-
        COMMON     (RAB_ptr)    LONG     rab_address

        DECLARE LONG    Rms_status
        !+
        !   Save RAB address in global symbol known to caller.
        !   Perform standard RMS open sequence
        !-
        Rab_address = LOC(User_rab::rab$b_bid)

        Rms_status = Sys$open( User_fab )

        IF Rms_status AND Rms$_normal
        THEN
            Rms_status = Sys$connect( User_rab )
        END IF

    END FUNCTION Rms_status

Note You cannot use a USEROPEN routine to fill the RBF, UBF, BKS, or CTX fields in the RAB. These fields are filled in after the USEROPEN routine returns; any values placed there by the USEROPEN routine are overwritten. Also, you must not set RMS Locate mode when using a USEROPEN routine on sequential files.

## 14.8.12 WINDOWSIZE Clause

The WINDOWSIZE clause specifies the number of block retrieval pointers in memory for the file. WINDOWSIZE is not a file attribute, and therefore can be changed any time you open a file.

Retrieval pointers are associated with the file header and point to contiguous blocks on disk. By keeping retrieval pointers in memory, you can reduce the I/O associated with locating a record because the operating system does not have to access the file header for pointers as frequently. The number of retrieval pointers in memory at any one time is determined by the system default or by the value you supply in the WINDOWSIZE clause. The usual default number of retrieval pointers is 7.

A value of zero specifies the default number of retrieval pointers. A value of -1 specifies mapping the entire file, if possible. Values from -128 to -2 are reserved.

Previous | Next | Contents | Index