[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP BASIC for OpenVMS
User Manual


Previous Contents Index

18.1.5 Writing Records to a File

The PUT statement writes sequential records to the file. The following program writes a record to the file. Successive PUT operations write successive records.


OPEN "MT0:TEST.DAT" FOR OUTPUT AS FILE #2, &
               SEQUENTIAL FIXED, RECORDSIZE 20%
B$ = ""
WHILE B$ <> "NO"
     LINPUT "Name"; A$
     MOVE TO #2, A$ = 20
     PUT #2
     LINPUT "Write another record"; B$
NEXT
CLOSE #2
END

Each PUT writes one record to the file. If your OPEN statement specifies a RECORDSIZE clause, the record buffer length equals RECORDSIZE or the map size. For example:


RECORDSIZE 60%

This clause specifies a record length and a record buffer size of 60 bytes. You can specify a record length from 18 to 8192 bytes. The default is 132 bytes.

If you specify a MAP clause and no RECORDSIZE clause, then the record size is the size of the map.

If you also specify BLOCKSIZE, the size of the buffer equals the value in BLOCKSIZE multiplied by the record size. For example:


RECORDSIZE 60%, BLOCKSIZE 4%

These clauses specify a logical record length of 60 bytes and a physical tape record size of 240 bytes (60 * 4). You specify BLOCKSIZE as an integer number of records. RMS rounds the resulting value to the next multiple of four. The total I/O buffer length cannot exceed 8192 bytes. The default is a buffer (tape block) containing one record.

To write true variable-length records, use the COUNT clause with the PUT statement to specify the number of bytes of data written to the file. Without COUNT, all records equal the length specified by the RECORDSIZE clause when you opened the file.

18.1.6 Reading Records from a File

The GET statement reads one logical record into the buffer. In the following example, the first GET reads a group of four records (a total of 80 bytes) from the file on channel #5 and transfers the first 20 bytes to the record buffers. Successive GET operations read 20 byte records to the record buffer performing an I/O to the tape every 4 records.


OPEN "MT0:TEST.DAT" FOR INPUT AS FILE #5%, &
       ORGANIZATION SEQUENTIAL FIXED, RECORDSIZE 20%, &
       BLOCKSIZE 4%, ACCESS READ
B$ = ""
WHILE B$ <> "NO"
      GET #5
      MOVE FROM #5, A$ = 20
      PRINT A$
      LINPUT "Do you want another record"; B$
NEXT
CLOSE #5
END

18.1.7 Controlling Tape Output Format

Magnetic tape physical records range from 18 to 8192 bytes. With RMS tapes, you can optionally specify this size in the BLOCKSIZE clause as a positive integer indicating the number of records in each block. HP BASIC then calculates the actual size in bytes. Thus, a fixed-length file on tape with 126 byte records can have a block size from 1 to 64, inclusive. The default is 126 bytes (one record per block).

In the following example of an OPEN statement, the RECORDSIZE clause defines the size of the records in the file as 90 bytes, and BLOCKSIZE defines the size of a block as 12 records (1080 bytes). Thus, your program contains an I/O buffer of 1080 bytes. Each physical read or write operation moves 1080 bytes of data between the tape and this buffer. Every twelfth GET or PUT operation causes a physical read or write. The next eleven GET or PUT operations only move data into or out of the I/O buffer. Specifying a block size larger than the default can reduce overhead by eliminating some physical reading and writing to the tape. In addition, specifying a large block size conserves space on the tape by reducing the number of interrecord gaps (IRGs). In the example, a block size of 12 saves time by accessing the tape only after every twelfth record operation.


OPEN "MT0:[SMITH]TEST.SEQ" FOR OUTPUT AS FILE #12% &
               ,ORGANIZATION SEQUENTIAL FIXED, RECORDSIZE 90% &
               ,BLOCKSIZE 12%

Through RMS, HP BASIC controls the blocking and deblocking of records. RMS checks each PUT operation to see if the specified record fits in the tape block. If it does not, RMS fills the rest of the block with circumflexes (blanks) and starts the record in a new block. Records cannot span blocks in magnetic tape files.

When you read blocks of records, your program can issue successive GET statements until it locates the fields of the record you want. The following program finds and displays a record on the terminal. You can invoke the RECOUNT function to determine how many bytes were read in the GET operation.


MAP  (XXX)  NA.ME$ = 5%, address$ = 20%

OPEN "MTO:FILE.DAT" FOR INPUT AS FILE #4%, &
           SEQUENTIAL FIXED, MAP XXX, ACCESS READ

NA.ME$ = ""
GET #4 UNTIL NA.ME$ - "JONES"
PRINT NA.ME$;  "LIVES AT "; address$

CLOSE #4

END

18.1.8 Rewinding a Tape

With the RESTORE # statement, you can rewind the tape to the start of the currently open file. For example:


OPEN  "MTO:FTF.DAT" FOR INPUT AS FILE #2%, ACCESS READ
GET #2%
   .
   .
   .
RESTORE #2%
GET #2%

You cannot rewind past the beginning of the currently open file.

18.1.9 Closing a File

The CLOSE statement ends I/O to the file. The following statement ends input and output to the file open on channel #6:


CLOSE #6%

If you opened the file with ACCESS READ, CLOSE has no further effect. If you opened the file without specifying ACCESS READ and the tape is not write-locked (that is, if the plastic write ring is in place), HP BASIC does the following:

  • Writes the file trailer labels and two end-of-file marks following the last record
  • Backspaces over the last end-of-file mark

HP BASIC does not rewind the tape.

18.2 Device-Specific I/O

Device-specific I/O lets you perform I/O directly to a device. The following sections describe device-specific I/O to unit record devices, tapes, and disks.

18.2.1 Device-Specific I/O to Unit Record Devices

You perform device-specific I/O to unit record devices by using only the device name in the OPEN statement file specification. You should allocate the device at DCL command level before reading or writing to the device. For example, this command allocates a card reader:


$ ALLOCATE CR1:

Once the device is allocated, you can read records from it. For example:


MAP  (DNG)  A% = 80%
OPEN  "CR1:"  FOR INPUT AS FILE #1%, ACCESS READ, MAP DNG
GET #1%

HP BASIC treats the device as a file, and data is read from the card reader as a series of fixed-length records.

18.2.2 Device-Specific I/O to Magnetic Tape Devices

When performing device-specific I/O to a tape drive, you open the physical device and transfer data between the tape and your program. GET and PUT statements perform read and write operations. UPDATE and DELETE statements are invalid when you perform device-specific I/O.

18.2.2.1 Allocating and Mounting a Tape

You must allocate the tape unit to your process before starting file operations. The following command line assigns tape drive MT1: to your process:


$ ALLOCATE MT1:

Use the DCL command MOUNT and the /FOREIGN qualifier to mount the tape. For example:


$ MOUNT/FOREIGN MT1:

If your program needs a blocksize other than 512 bytes, or a particular tape density, specify these characteristics with the MOUNT command as well. For example:


$ MOUNT/FOREIGN/BLOCKSIZE=1024/DENSITY=1600 MT1:

When reading a foreign tape, you must make sure the /BLOCKSIZE qualifier has a value at least as large as the largest record on the tape.

18.2.2.2 Opening a Tape File for Output

To create and open the magnetic tape for output, you use the OPEN statement. The following statement opens tape drive MT1: for writing. It is important to use the SEQUENTIAL VARIABLE clause unless the records are fixed. In contrast to ANSI tape processing, RMS does not write record length headers or variable-length records to foreign tapes. If you specify SEQUENTIAL VARIABLE, you should have some way to determine where records begin and end.


OPEN  "MT1:"  FOR OUTPUT AS FILE #1%,         &
        ORGANIZATION SEQUENTIAL VARIABLE

18.2.2.3 Opening a Tape File for Input

To access a tape with existing data, you also use the OPEN statement. For example, the following statement opens the tape unit MT2:.


OPEN  "MT2:"  AS FILE #2%

Depending on how you access records, there are two ways to open a foreign magnetic tape. If your program uses dynamic buffering and MOVE statements, open the file with no RECORDSIZE clause. RMS will provide the correct buffer size for HP BASIC. Do not specify a BLOCKSIZE value or ORGANIZATION clause with the OPEN statement.

If your program uses MAP and REMAP statements, but you do not know how long the records are, specify a MAP that is as large as the value you specified for the BLOCKSIZE qualifier when mounting the tape. Do not specify a BLOCKSIZE value or ORGANIZATION clause with the OPEN statement.

When processing records, each GET operation will read one physical record whose size is returned in RECOUNT. If you are using a map only, the first n bytes (n is the value returned in RECOUNT) are valid.

18.2.2.4 Writing Records to a File

The PUT statement writes records to the file in sequential order. For example:


OPEN "MT0:" FOR OUTPUT AS FILE #9%, &
          SEQUENTIAL VARIABLE
INPUT "NAME";NA.ME$
MOVE TO #9%, NA.ME$
PUT #9%

The last line writes the contents of the record buffer to the device. Successive PUT operations write successive records.

The default record length (and, therefore, the size of the buffer) is 132 bytes. The RECORDSIZE attribute causes HP BASIC to read or write records of a specified length. For example, the following statement opens tape unit MT0: and specifies records of 900 characters. You must specify an even integer larger than or equal to 18. If you specify a buffer length less than 18, HP BASIC signals an error. If you try to write a record longer than the buffer, HP BASIC signals the error "Size of record invalid" (ERR=156).


OPEN "MT0:" FOR INPUT AS FILE #1%, RECORDSIZE 900%

To write records shorter than the buffer, include the COUNT clause with the PUT statement. The following statement writes a 56-character record to the file open on channel #6. If you do not specify COUNT, HP BASIC writes a full buffer. You can specify a minimum count of 18, and a maximum count equal to the buffer size. When writing records to a foreign magnetic tape, neither HP BASIC nor RMS prefixes the records with any count bytes.


PUT #6%, COUNT 56%

18.2.2.5 Reading Records from a File

The GET statement reads records into the buffer. The following program reads a record into the buffer, prints a string field, and rewinds the file before closing. Successive GET operations read successive records. HP BASIC signals the error "End of file on device" (ERR=11) if you encounter a tape mark during a GET operation. If you trap this error and continue, you can skip over any tape marks. The system variable RECOUNT is set to the number of bytes transferred after each GET operation.


OPEN "MT1:" FOR INPUT AS FILE #1%, ACCESS READ
GET #1%
MOVE FROM #1%, A$ = RECOUNT
PRINT A$
RESTORE #1%
CLOSE #1%

18.2.2.6 Rewinding a Tape

When you mount a magnetic tape, the system will position the tape at the load point (BOT). Your program can rewind the tape during program execution with the RESTORE statement. For example:


OPEN "MT1:" FOR OUTPUT AS FILE #2%, ACCESS READ
   .
   .
   .
PUT #2%
RESTORE #2%
INPUT "NEXT RECORD"; NXTRECBB%

If you rewind a tape opened without ACCESS READ before closing it, you erase all data written before the RESTORE operation.

18.2.2.7 Closing a Tape

The CLOSE statement ends I/O to the tape. For example, the following statement ends input and output to the tape open on channel #12.


CLOSE #12%

If you opened the file with ACCESS READ, CLOSE has no further effect. If you opened the file without specifying ACCESS READ and the tape is not write-locked (that is, if the plastic write ring is in place), HP BASIC does the following:

  • Writes file trailer labels and two end-of-file marks following the last record
  • Backspaces over the last end-of-file mark

The tape is not rewound unless you specified RESTORE in your program.

18.2.3 Device-Specific I/O to Disks

When performing device-specific I/O to disks, you write and read data with PUT and GET statements. The data must fit in 512-byte blocks, and you must do your own blocking and deblocking with MAP/REMAP or MOVE statements. Note that, when accessing disks with device-specific I/O operations, you are performing logical I/O. Because of this, you should be careful not to overwrite block number zero, which is often the disk's boot block. You must have LOG_IO privileges to perform these operations.

The following sections describe device-specific I/O to disks.

18.2.3.1 Assigning and Mounting a Disk

You must allocate a disk unit to your process before starting operations. The following command line assigns disk DUA3: to your process:


$ ALLOCATE DUA3:

When you perform I/O directly to a disk, you must mount the disk with the MOUNT command before accessing it. For example:


$ MOUNT/FOREIGN DUA3:

You can then open the disk for input or output.

18.2.3.2 Opening a Disk File for Output

To create and open the disk file, you use the OPEN statement. For example:


OPEN "DUA3:" FOR OUTPUT AS FILE #2%, SEQUENTIAL FIXED, &
       RECORDSIZE=512

You can then write data to the disk.

The record size determined by the MAP or RECORDSIZE clause must be an integer multiple of 512 bytes.

18.2.3.3 Opening a Disk File for Input

To open an existing disk file, you also use the OPEN statement. For example:


OPEN "DUA1:" FOR INPUT AS FILE #4%, SEQUENTIAL FIXED, &
       RECORDSIZE=512

You can then read data from the disk.

The record size determined by the MAP or RECORDSIZE clause must be an integer multiple of 512 bytes. The default is 512.

Specify ACCESS READ in the OPEN statement if you only plan to read from the disk.

18.2.3.4 Writing Records to a Disk File

You write data by defining a record buffer and writing the data to the file with PUT statements. The following program writes eight 64 byte records into each 512-byte block on the disk. When your program fills one block, writing continues in the next. The FILL field in the MOVE statement positions the data in the block.


INPUT "HOW MANY RECORDS TO WRITE"; J%
OPEN "DBB2: FOR OUTPUT AS FILE #2%, SEQUENTIAL FIXED, &
      RECORDSIZE=512
FOR K% = 1% TO J%
   FOR I% = 0% TO 7%
        INPUT "NAME OF BOOK"; BOOK_NAME$
        INPUT "RETRIEVAL NUMBER"; RET_NUM%
        INPUT "SUBJECT AREA"; SUBJ$
        MOVE TO #2%, FILL$ = I% * 64%, BOOK_NAME$, RET_NUM%, SUBJ$
   NEXT I%
PUT #2%
NEXT K%
CLOSE #2

When you write records, HP BASIC does not prefix the records with any count bytes.

18.2.3.5 Reading Records from a Disk File

You read data by defining a record buffer and reading the data from the device with GET statements. After the data has been retrieved with a GET statement you can deblock the data with MOVE or REMAP statements.

In the following example, each disk block contains twelve 40-byte records. Each record contains a 32-byte string, a 4-byte SINGLE number, and a 4-byte LONG integer. After each GET operation, the FOR...NEXT loop uses the REMAP statement to redefine the position of the variables in the record. At the end of the file, the program closes the file. See Chapter 7 and the HP BASIC for OpenVMS Reference Manual for more information about the MAP, MAP DYNAMIC, and REMAP statements.


MAP (SAM) FILL$ = 512
MAP DYNAMIC (SAM) STRING PRT_ID, SINGLE MAFLD, LONG ADIR_OLDN
OPEN "DUA1:" FOR INPUT AS FILE #2%, SEQUENTIAL FIXED, &
            ACCESS READ, MAP SAM
WHEN ERROR USE err_hand
WHILE 1% = 1%
     GET #2%
     FOR I% = 0% TO 11%
         REMAP (SAM) STRING FILL(I% * 40%), PRT_ID = 32, MAFLD, ADIR_OLDN
         PRINT PRT_ID, MAFLD, ADIR_OLDN
     NEXT I%
NEXT
END WHEN
HANDLER err_hand
  IF ERR <> 11%
    THEN
      EXIT HANDLER
  END IF
END HANDLER
CLOSE #2%
END

18.3 I/O to Mailboxes

A mailbox is a record I/O device that passes data from one process to another. You can use a valid mailbox name as a file name, and treat that mailbox as a normal record file. You must have TMPMBX or PRMMBX privilege to create mailboxes. Mailboxes are created and deleted by system services. For more information about using system services in HP BASIC programs, see Chapter 19.

Use the EXTERNAL statement to define the SYS$CREMBX system service that creates the mailbox. In HP BASIC programs, you create mailboxes by invoking SYS$CREMBX as a function passing either a channel argument and a string literal or a logical name for the mailbox. For example:


EXTERNAL INTEGER FUNCTION SYS$CREMBX
SYS$STATUS% = SYS$CREMBX(,CHAN%,,,,,"CONFIRMATION_MBX")

If you supply a logical name for the mailbox, be sure that it is in uppercase letters. Once you create the mailbox, you can use it as a logical file name.

The following two examples, when executed on two separate processes, allow you to send and receive data from one process to another.

Example 1


DECLARE STRING passenger_name, Confirm_msg
OPEN "CONFIRMATION_MBX" AS FILE #1%
INPUT "WHAT IS THE PASSENGER NAME"; passenger_name
PRINT #1%, passenger_name
LINPUT #1%, confirm_msg
PRINT confirm_msg
END

Example 2


MAP (res) STRING passenger_name = 32%
DECLARE WORD mbx_chan, LONG sys_status
EXTERNAL LONG FUNCTION sys$crembx (LONG, WORD, LONG, LONG,    &
                                     LONG, LONG, STRING)
WHEN ERROR USE err_trap
sys_status = sys$crembx ( ,mbx_chan,,,,,"CONFIRMATION_MBX")
OPEN "CONFIRMATION_MBX" FOR INPUT AS FILE #1%
LINPUT #1%, passenger_name
OPEN "RESER.LST" FOR INPUT AS FILE #2%,            &
        ORGANIZATION INDEXED, MAP RES, ACCESS READ            &
        PRIMARY passenger_name
FIND #2%, KEY #0% EQ passenger_name
RECEIVING.MSG$ = "Passenger reservation confirmed"
PRINT #1%, RECEIVING.MSG$
END WHEN
HANDLER err_trap
    IF (ERR = 155)
       THEN
       RECEIVING.MSG$ = "Reservation does not exist"
       ELSE
       EXIT HANDLER
    END IF
END HANDLER
CLOSE #2%, #1%
END PROGRAM

Example 1 requests a passenger name and sends it to the mailbox.

Example 2 looks up the name in an indexed file. If the passenger name exists, Example 2 writes the confirmation message to the mailbox. If the passenger name does not exist, the error handler writes an alternate message. Example 1 then reads the mailbox and returns the result.

HP BASIC treats the mailbox as a sequential file. You write to the file with the PRINT # or PUT statement, and read it with the INPUT #, LINPUT #, or GET statement.

When either program closes the mailbox, the other program receives an end-of-file error message when it attempts to read the mailbox.

Note

All mailbox operations are synchronous. Control does not pass back from a mailbox operation, such as a PUT, to your program until the other program completes the corresponding operation, such as a GET.


Previous Next Contents Index