forked from KolibriOS/kolibrios
232 lines
10 KiB
Plaintext
232 lines
10 KiB
Plaintext
|
[Quoting from a C/370 manual, courtesy of Carl Forde.]
|
||
|
|
||
|
C/370 supports three types of input and output: text streams, binary
|
||
|
streams, and record I/O. Text and binary streams are both ANSI
|
||
|
standards; record I/O is a C/370 extension.
|
||
|
|
||
|
[...]
|
||
|
|
||
|
Record I/O is a C/370 extension to the ANSI standard. For files
|
||
|
opened in record format, C/370 reads and writes one record at a
|
||
|
time. If you try to write more data to a record than the record
|
||
|
can hold, the data is truncated. For record I/O, C/370 only allows
|
||
|
the use of fread() and fwrite() to read and write to the files. Any
|
||
|
other functions (such as fprintf(), fscanf(), getc(), and putc())
|
||
|
fail. For record-orientated files, records do not change size when
|
||
|
you update them. If the new data has fewer characters than the
|
||
|
original record, the new data fills the first n characters, where
|
||
|
n is the number of characters of the new data. The record will
|
||
|
remain the same size, and the old characters (those after) n are
|
||
|
left unchanged. A subsequent update begins at the next boundary.
|
||
|
For example, if you have the string "abcdefgh":
|
||
|
|
||
|
abcdefgh
|
||
|
|
||
|
and you overwrite it with the string "1234", the record will look
|
||
|
like this:
|
||
|
|
||
|
1234efgh
|
||
|
|
||
|
C/370 record I/O is binary. That is, it does not interpret any of
|
||
|
the data in a record file and therefore does not recognize control
|
||
|
characters.
|
||
|
|
||
|
|
||
|
The record model consists of:
|
||
|
|
||
|
* A record, which is the unit of data transmitted to and from a
|
||
|
program
|
||
|
* A block, which is the unit of data transmitted to and from a
|
||
|
device. Each block may contain one or more records.
|
||
|
|
||
|
In the record model of I/O, records and blocks have the following
|
||
|
attributes:
|
||
|
|
||
|
RECFM Specifies the format of the data or how the data is organized
|
||
|
on the physical device.
|
||
|
LRECL Specifies the length of logical records (as opposed to
|
||
|
physical ones).
|
||
|
|
||
|
BLKSIZE Specifies the length of physical records (blocks on the
|
||
|
physical device).
|
||
|
|
||
|
|
||
|
Opening a File by Filename
|
||
|
|
||
|
The filename that you specify on the call to fopen() or freopen()
|
||
|
must be in the following format:
|
||
|
|
||
|
>> ----filename---- ----filetype--------------------
|
||
|
| | | |
|
||
|
--.-- -- --filemode--
|
||
|
| |
|
||
|
--.--
|
||
|
where
|
||
|
|
||
|
filename is a 1- to 8-character string of any of the characters,
|
||
|
A-Z, a-z, 0-9, and +, -, $, #, @, :, and _. You can separate it
|
||
|
from the filetype with one or more spaces, or with a period.
|
||
|
[Further note: filenames are fully case-sensitive, as in Unix.]
|
||
|
|
||
|
filetype is a 1- to 8-character string of any of the characters,
|
||
|
A-Z, a-z, 0-9, and +, -, $, #, @, :, and _. You can separate it
|
||
|
from the filemode with one or more spaces, or with a period. The
|
||
|
separator between filetype and filemode must be the same as the
|
||
|
one between filename and filetype.
|
||
|
|
||
|
filemode is a 1- to 2-character string. The first must be any of
|
||
|
the characters A-Z, a-z, or *. If you use the asis parameter on
|
||
|
the fopen() or freopen() call, the first character of the filemode
|
||
|
must be a capital letter or an asterisk. Otherwise, the function
|
||
|
call fails. The second character of filemode is optional; if you
|
||
|
specify it, it must be any of the digits 0-6. You cannot specify
|
||
|
the second character if you have specified * for the first one.
|
||
|
|
||
|
If you do not use periods as separators, there is no limit to how
|
||
|
much whitespace you can have before and after the filename, the
|
||
|
filetype, and filemode.
|
||
|
|
||
|
|
||
|
Opening a File without a File Mode Specified
|
||
|
|
||
|
If you omit the file mode or specify * for it, C/370 does one
|
||
|
of the following when you call fopen() or freopen():
|
||
|
|
||
|
* If you have specified a read mode, C/370 looks for the named file
|
||
|
on all the accessed readable disks, in order. If it does not find
|
||
|
the file, the fopen() or freopen() call fails.
|
||
|
* If you have specified any of the write modes, C/370 writes the file
|
||
|
on the first writable disk you have accessed. Specifying a write
|
||
|
mode on an fopen() or freopen() call that contains the filename of
|
||
|
an existing file destroys that file. If you do not have any
|
||
|
writable disks accessed, the call fails.
|
||
|
|
||
|
|
||
|
fopen() and freopen() parameters
|
||
|
|
||
|
recfm
|
||
|
CMS supports only two RECFMs, V and F. [note that MVS supports
|
||
|
27(!) different RECFMs.] If you do not specify the RECFM for a
|
||
|
file, C/370 determines whether is is in fixed or variable format.
|
||
|
|
||
|
lrecl and blksize
|
||
|
For files in fixed format, CMS allows records to be read and
|
||
|
written in blocks. To have a fixed format CMS file treated as a
|
||
|
fixed blocked CMS file, you can open the file with recfm=fb and
|
||
|
specify the lrecl and blksize. If you do not specify a recfm on
|
||
|
the open, the blksize can be a multiple of the lrecl, and the
|
||
|
file is treated as if it were blocked.
|
||
|
|
||
|
For files in variable format, the CMS LRECL is different from the
|
||
|
LRECL for the record model. In the record model, the LRECL is
|
||
|
equal to the data length plus 4 bytes (for the record descriptor
|
||
|
word), and the BLKSIZE is equal to the LRECL plus 4 bytes (for
|
||
|
the block descriptor word). In CMS, BDWs and RDWs do not exist,
|
||
|
but because CMS follows the record model, you must still account
|
||
|
for them. When you specify V, you must still allocate the record
|
||
|
descriptor word and block descriptor word. That is, if you want
|
||
|
a maximum of n bytes per record, you must specify a minimum LRECL
|
||
|
of n+4 and a minimum BLKSIZE of n+8.
|
||
|
|
||
|
When you are appending to V files, you can enlarge the record size
|
||
|
dynamically, but only if you have not specified LRECL or BLKSIZE
|
||
|
on the fopen() or freopen() command that opened the file.
|
||
|
|
||
|
type
|
||
|
If you specify this parameter, the only valid value for CMS disk
|
||
|
files is type =record. This opens a file for record I/O.
|
||
|
|
||
|
asis
|
||
|
If you use this parameter, you can open files with mixed-case
|
||
|
filenames such as JaMeS dAtA or pErCy.FILE. If you specify this
|
||
|
parameter, the file mode that you specify must be a capital letter
|
||
|
(if it is not an asterisk); otherwise; the function call fails and
|
||
|
the value returned is NULL.
|
||
|
|
||
|
|
||
|
Reading from Record I/O Files
|
||
|
fread() is the only interface allowed for reading record I/O files.
|
||
|
Each time you call fread() for a record I/O file, fread() reads
|
||
|
one record from the system. If you call fread() with a request for
|
||
|
less than a complete record, the requested bytes are copied to your
|
||
|
buffer, and the file position is set to the start fo the next
|
||
|
record. If the request is for more bytes that are in the record,
|
||
|
one record is read and the position is set to the start of the next
|
||
|
record. C/370 does not strip any blank characters or interpret any
|
||
|
data.
|
||
|
|
||
|
fread() returns the number of items read successfully, so if you
|
||
|
pass a size argument equal to 1 and a count argument equal to the
|
||
|
maximum expected length of the record, fread() returns the length,
|
||
|
in bytes, of the record read. If you pass a size argument equal
|
||
|
to the maximum expected length of the record, and a count argument
|
||
|
equal to 1, fread() returns either 0 or 1, indicating whether a
|
||
|
record of length size read. If a record is read successfully but
|
||
|
is less than size bytes long, fread() returns 0.
|
||
|
|
||
|
|
||
|
Writing to Record I/O Files
|
||
|
fwrite() is the only interface allowed for writing to a file
|
||
|
opened for record I/O. Only one record is written at a time. If
|
||
|
you attempt to write more new data than a full record can hold or
|
||
|
try to update a record with more data than it currently has, C/370
|
||
|
truncates your output at the record boundary. When C/370 performs
|
||
|
a truncation, it sets errno and raises SIGIOERR, if SIGIOERR is not
|
||
|
set to SIG_IGN.
|
||
|
|
||
|
When you are writing new records to a fixed-record I/O file, if you
|
||
|
try to write a short record, C/370 pads the record with nulls out
|
||
|
to LRECL.
|
||
|
|
||
|
At the completion of an fwrite(), the file position is at the start
|
||
|
of the next record. For new data, the block is flushed out to the
|
||
|
system as soon as it is full.
|
||
|
|
||
|
|
||
|
fldata() Behavior
|
||
|
When you call the fldata() function for an open CMS minidisk file,
|
||
|
it returns a data structure that looks like this:
|
||
|
|
||
|
struct __filedata {
|
||
|
unsigned int __recfmF : 1, /* fixed length records */
|
||
|
__recfmV : 1, /* variable length records */
|
||
|
__recfmU : 1, /* n/a */
|
||
|
__recfmS : 1, /* n/a */
|
||
|
__recfmBlk : 1, /* n/a */
|
||
|
__recfmASA : 1, /* text mode and ASA */
|
||
|
__recfmM : 1, /* n/a */
|
||
|
__dsorgPO : 1, /* n/a */
|
||
|
__dsorgPDSmem : 1, /* n/a */
|
||
|
__dsorgPDSdir : 1, /* n/a */
|
||
|
__dsorgPS : 1, /* sequential data set */
|
||
|
__dsorgConcat : 1, /* n/a */
|
||
|
__dsorgMem : 1, /* n/a */
|
||
|
__dsorgHiper : 1, /* n/a */
|
||
|
__dsorgTemp : 1, /* created with tmpfile() */
|
||
|
__dsorgVSAM : 1, /* n/a */
|
||
|
__reserve1 : 1, /* n/a */
|
||
|
__openmode : 2, /* see below 1 */
|
||
|
__modeflag : 4, /* see below 2 */
|
||
|
__reserve2 : 9, /* n/a */
|
||
|
|
||
|
char __device; __DISK
|
||
|
unsigned long __blksize, /* see below 3 */
|
||
|
__maxreclen; /* see below 4 */
|
||
|
unsigned short __vsamtype; /* n/a */
|
||
|
unsigned long __vsamkeylen; /* n/a */
|
||
|
unsigned long __vsamRKP; /* n/a */
|
||
|
char * __dsname; /* fname ftype fmode */
|
||
|
unsigned int __reserve4; /* n/a */
|
||
|
|
||
|
/* note 1: values are: __TEXT, __BINARY, __RECORD
|
||
|
note 2: values are: __READ, __WRITE, __APPEND, __UPDATE
|
||
|
these values can be added together to determine
|
||
|
the return value; for example, a file opened with
|
||
|
a+ will have the value __READ + __APPEND.
|
||
|
note 3: total block size of the file, including ASA
|
||
|
characters as well as RDW information
|
||
|
note 4: maximum record length of the data only (includes
|
||
|
ASA characters but excludes RDW information).
|
||
|
*/
|
||
|
};
|