(FORTRAN 77 Only) These routines provide an alternative way to manipulate magnetic tape:
topen |
Associate a device name with a tape logical unit. |
tclose |
Write EOF, close tape device channel, and remove association with tlu. |
tread |
Read next physical record from tape into buffer. |
twrite |
Write the next physical record from buffer to tape. |
trewin |
Rewind the tape to the beginning of the first data file. |
tskipf |
Skip forward over files and/or records, and reset EOF status. |
tstate |
Determine the logical state of the tape I/O channel. |
On any one unit, do not mix these functions with standard FORTRAN I/O.
You must first use topen() to open a tape logical unit, tlu, for the specified device. Then you do all other operations on the specified tlu. tlu has no relationship at all to any normal FORTRAN logical unit.
Before you use one of these functions, its name must be in an INTEGER*4 type statement.
INTEGER*4 topen n = topen( tlu, devnam, islabeled ) |
|||
---|---|---|---|
tlu |
INTEGER*4 |
Input |
Tape logical unit, in the range 0 to 7. |
devnam |
CHARACTER |
Input |
Device name; for example: '/dev/rst0' |
islabeled |
LOGICAL |
Input |
True=the tape is labeled A label is the first file on the tape. |
Return value |
INTEGER*4 |
Output |
n=0: OK n<0: Error |
This function does not move the tape. See perror(3F) for details.
Example: topen()--open a 1/4-inch tape file:
CHARACTER devnam*9 / '/dev/rst0' / INTEGER*4 n / 0 /, tlu / 1 /, topen LOGICAL islabeled / .false. / n = topen( tlu, devnam, islabeled ) IF ( n .LT. 0 ) STOP "topen: cannot open" WRITE(*,'("topen ok:", 2I3, 1X, A10)') n, tlu, devnam END
topen ok: 0 1 /dev/rst0
INTEGER*4 tclose n = tclose ( tlu ) |
|||
---|---|---|---|
tlu |
INTEGER*4 |
Input |
Tape logical unit, in range 0 to 7 |
n |
INTEGER*4 |
Return value |
n=0: OK n<0: Error |
tclose() places an EOF marker immediately after the current location of the unit pointer, and then closes the unit. So if you trewin() a unit before you tclose() it, its contents are discarded.
Example: tclose()--close an opened 1/4-inch tape file:
CHARACTER devnam*9 / '/dev/rst0' / INTEGER*4 n / 0 /, tlu / 1 /, tclose, topen LOGICAL islabeled / .false. / n = topen( tlu, devnam, islabeled ) n = tclose( tlu ) IF ( n .LT. 0 ) STOP "tclose: cannot close" WRITE(*, '("tclose ok:", 2I3, 1X, A10)') n, tlu, devnam END
tclose ok: 0 1 /dev/rst0
INTEGER*4 twrite n = twrite( tlu, buffer ) |
|||
---|---|---|---|
tlu |
INTEGER*4 |
Input |
Tape logical unit, in range 0 to 7 |
buffer |
character |
Input |
Must be sized at a multiple of 512 |
n |
INTEGER*4 |
Return value |
n>0: OK, and n = the number of bytes written n=0: End of Tape n<0: Error |
The physical record length is the size of buffer.
Example: twrite()--write a 2-record file:
CHARACTER devnam*9 / '/dev/rst0' /, rec1*512 / "abcd" /, & rec2*512 / "wxyz" / INTEGER*4 n / 0 /, tlu / 1 /, tclose, topen, twrite LOGICAL islabeled / .false. / n = topen( tlu, devnam, islabeled ) IF ( n .LT. 0 ) STOP "topen: cannot open" n = twrite( tlu, rec1 ) IF ( n .LT. 0 ) STOP "twrite: cannot write 1" n = twrite( tlu, rec2 ) IF ( n .LT. 0 ) STOP "twrite: cannot write 2" WRITE(*, '("twrite ok:", 2I4, 1X, A10)') n, tlu, devnam END
twrite ok: 512 1 /dev/rst0
INTEGER*4 tread n = tread( tlu, buffer ) |
|||
---|---|---|---|
tlu |
INTEGER*4 |
Input |
Tape logical unit, in range 0 to 7. |
buffer |
character |
Input |
Must be sized at a multiple of 512, and must be large enough to hold the largest physical record to be read. |
n |
INTEGER*4 |
Return value |
n>0: OK, and n is the number of bytes read. n<0: Error n=0: EOF |
If the tape is at EOF or EOT, then tread does a return; it does not read tapes.
Example: tread()--read the first record of the file written above:
CHARACTER devnam*9 / '/dev/rst0' /, onerec*512 / " " / INTEGER*4 n / 0 /, tlu / 1 /, topen, tread LOGICAL islabeled / .false. / n = topen( tlu, devnam, islabeled ) IF ( n .LT. 0 ) STOP "topen: cannot open" n = tread( tlu, onerec ) IF ( n .LT. 0 ) STOP "tread: cannot read" WRITE(*,'("tread ok:", 2I4, 1X, A10)') n, tlu, devnam WRITE(*,'( A4)') onerec END
tread ok: 512 1 /dev/rst0 abcd
INTEGER*4 trewin n = trewin ( tlu ) |
|||
---|---|---|---|
tlu |
INTEGER*4 |
Input |
Tape logical unit, in range 0 to 7 |
n |
INTEGER*4 |
Return value |
n=0: OK n<0: Error |
If the tape is labeled, then the label is skipped over after rewinding.
Example 1: trewin()--typical fragment:
CHARACTER devnam*9 / '/dev/rst0' / INTEGER*4 n /0/, tlu /1/, tclose, topen, tread, trewin ... n = trewin( tlu ) IF ( n .LT. 0 ) STOP "trewin: cannot rewind" WRITE(*, '("trewin ok:", 2I4, 1X, A10)') n, tlu, devnam ... END
Example 2: trewin()--in a two-record file, try to read three records, rewind, read one record:
CHARACTER devnam*9 / '/dev/rst0' /, onerec*512 / " " / INTEGER*4 n / 0 /, r, tlu / 1 /, topen, tread, trewin LOGICAL islabeled / .false. / n = topen( tlu, devnam, islabeled ) IF ( n .LT. 0 ) STOP "topen: cannot open" DO r = 1, 3 n = tread( tlu, onerec ) WRITE(*,'(1X, I2, 1X, A4)') r, onerec END DO n = trewin( tlu ) IF ( n .LT. 0 ) STOP "trewin: cannot rewind" WRITE(*, '("trewin ok:" 2I4, 1X, A10)') n, tlu, devnam n = tread( tlu, onerec ) IF ( n .LT. 0 ) STOP "tread: cannot read after rewind" WRITE(*,'(A4)') onerec END
1 abcd 2 wxyz 3 wxyz trewin ok: 0 1 /dev/rst0 abcd
INTEGER*4 tskipf n = tskipf( tlu, nf, nr ) |
|||
---|---|---|---|
tlu |
INTEGER*4 |
Input |
Tape logical unit, in range 0 to 7 |
nf |
INTEGER*4 |
Input |
Number of end-of-file marks to skip over first |
nr |
INTEGER*4 |
Input |
Number of physical records to skip over after skipping files |
n |
INTEGER*4 |
Return value |
n=0: OK n<0: Error |
This function does not skip backward.
First, the function skips forward over nf end-of-file marks. Then, it skips forward over nr physical records. If the current file is at EOF, this counts as one file to skip. This function also resets the EOF status.
Example: tskipf()--typical fragment: skip four files and then skip one record:
INTEGER*4 nfiles / 4 /, nrecords / 1 /, tskipf, tlu / 1 / ... n = tskipf( tlu, nfiles, nrecords ) IF ( n .LT. 0 ) STOP "tskipf: cannot skip" ...
Compare with tstate() .
INTEGER*4 tstate n = tstate( tlu, fileno, recno, errf, eoff, eotf, tcsr ) |
|||
---|---|---|---|
tlu |
INTEGER*4 |
Input |
Tape logical unit, in range 0 to 7 |
fileno |
INTEGER*4 |
Output |
Current file number |
recno |
INTEGER*4 |
Output |
Current record number |
errf |
LOGICAL |
Output |
True=an error occurred |
eoff |
LOGICAL |
Output |
True=the current file is at EOF |
eotf |
LOGICAL |
Output |
True=tape has reached logical end-of-tape |
tcsr |
INTEGER*4 |
Output |
True=hardware errors on the device. It contains the tape drive control status register. If the error is software, then tcsr is returned as zero. The values returned in this status register vary grossly with the brand and size of tape drive. |
For details, see st(4s).
While eoff is true, you cannot read from that tlu. You can set this EOF status flag to false by using tskipf() to skip one file and zero records:
n = tskipf( tlu, 1, 0).
Then you can read any valid record that follows.
End-of-tape (EOT) is indicated by an empty file, often referred to as a double EOF mark. You cannot read past EOT, but you can write past it.
Example: Write three files of two records each:
CHARACTER devnam*10 / '/dev/nrst0' /, & f0rec1*512 / "eins" /, f0rec2*512 / "zwei" /, & f1rec1*512 / "ichi" /, f1rec2*512 / "ni__" /, & f2rec1*512 / "un__" /, f2rec2*512 / "deux" / INTEGER*4 n / 0 /, tlu / 1 /, tclose, topen, trewin, twrite LOGICAL islabeled / .false. / n = topen( tlu, devnam, islabeled ) n = trewin( tlu ) n = twrite( tlu, f0rec1 ) n = twrite( tlu, f0rec2 ) n = tclose( tlu ) n = topen( tlu, devnam, islabeled ) n = twrite( tlu, f1rec1 ) n = twrite( tlu, f1rec2 ) n = tclose( tlu ) n = topen( tlu, devnam, islabeled ) n = twrite( tlu, f2rec1 ) n = twrite( tlu, f2rec2 ) n = tclose( tlu ) END
The next example uses tstate() to trap EOF and get at all files.
Example: Use tstate() in a loop that reads all records of the 3 files written in the previous example:
CHARACTER devnam*10 / '/dev/nrst0' /, onerec*512 / " " / INTEGER*4 f, n / 0 /, tlu / 1 /, tcsr, topen, tread, & trewin, tskipf, tstate LOGICAL errf, eoff, eotf, islabeled / .false. / n = topen( tlu, devnam, islabeled ) n = tstate( tlu, fn, rn, errf, eoff, eotf, tcsr ) WRITE(*,1) 'open:', fn, rn, errf, eoff, eotf, tcsr 1 FORMAT(1X, A10, 2I2, 1X, 1L, 1X, 1L,1X, 1L, 1X, I2 ) 2 FORMAT(1X, A10,1X,A4,1X,2I2,1X,1L,1X,1L,1X,1L,1X,I2) n = trewin( tlu ) n = tstate( tlu, fn, rn, errf, eoff, eotf, tcsr ) WRITE(*,1) 'rewind:', fn, rn, errf, eoff, eotf, tcsr DO f = 1, 3 eoff = .false. DO WHILE ( .NOT. eoff ) n = tread( tlu, onerec ) n = tstate( tlu, fn, rn, errf, eoff, eotf, tcsr ) IF (.NOT. eoff) WRITE(*,2) 'read:', onerec, & fn, rn, errf, eoff, eotf, tcsr END DO n = tskipf( tlu, 1, 0 ) n = tstate( tlu, fn, rn, errf, eoff, eotf, tcsr ) WRITE(*,1) 'tskip: ', fn, rn, errf, eoff, eotf, tcsr END DO END
open: 0 0 F F F 0 rewind: 0 0 F F F 0 read: eins 0 1 F F F 0 read: zwei 0 2 F F F 0 tskip: 1 0 F F F 0 read: ichi 1 1 F F F 0 read: ni__ 1 2 F F F 0 tskip: 2 0 F F F 0 read: un__ 2 1 F F F 0 read: deux 2 2 F F F 0 tskip: 3 0 F F F 0
A summary of EOF and EOT follows:
If you are at either EOF or EOT, then:
Any tread() just returns; it does not read the tape.
A successful tskipf(tlu,1,0) resets the EOF status to false, and returns; it does not advance the tape pointer.
A successful twrite() resets the EOF and EOT status flags to false.
A successful tclose() resets all those flags to false.
tclose() truncates; it places an EOF marker immediately after the current location of the unit pointer, and then closes the unit. So, if you use trewin() to rewind a unit before you use tclose() to close it, its contents are discarded. This behavior of tclose() is inherited from the Berkeley code.
See also: ioctl(2), mtio(4s), perror(3F), read(2), st(4s), and write(2).