The following section describes how to perform input and output using the functions provided in the SAS/C library. This section is important if you use SAS/C I/O facilities, whether you are developing new programs or porting existing programs from other environments.
In addition to the traditional C I/O facilities described in this section, the library offers for both CMS and MVS a set of functions to perform low-level I/O, making direct use of native I/O facilities. These facilities are described in Chapter 2, "CMS Low-Level I/O Functions," and Chapter 3, "MVS Low-Level I/O Functions," in SAS/C Library Reference, Volume 2
The library's I/O implementation is designed to
As described later in this chapter, the library provides several I/O techniques to meet the needs of different applications. To achieve the best results, you must make an informed choice about the techniques to use. Criteria that should influence this choice are
To make these choices, you need to understand general C I/O concepts as well as the native I/O types and file structures supported by the 370 operating systems, MVS and CMS. These topics are addressed in this chapter. The description is aimed primarily at the knowledgeable C programmer who should be familiar with 370 I/O concepts. In many cases, understanding the 370 I/O concepts is necessary to control and anticipate program behavior. Where possible, this chapter addresses these issues, but familiarizing yourself with 370 I/O concepts using other sources is highly recommended. Chapter 1, "Introduction," of the SAS/C Compiler and Library User's Guide, Fourth Edition lists the documents from International Business Machines Corporation that may be of particular value.
Some parts of this chapter are intended for knowledgeable 370 programmers who may be interested in the relationship between SAS/C I/O and traditional 370 I/O techniques. These portions are identified as such, and you can skip them if you do not have the necessary background in 370 I/O concepts.
This chapter is divided into two sections: technical background and technical summaries. For the most effective use of SAS/C I/O techniques, you should become familiar with the concepts presented in the next section, "Technical Background." Skim Technical Summaries for information relevant to your application, and consult specific I/O function descriptions for details on the functions. Much of the material in the last two sections is reference information of limited applicability, but understanding the technical background section is essential for effective use of the library I/O functions.
In addition, many useful C programs were first developed under UNIX operating systems, and such programs frequently are unaware of the existence of other systems or I/O techniques. Such programs cannot run on systems as different from UNIX as CMS or MVS without carefully considering their original environment.
UNIX operating systems also support a mixed-level form of I/O, wherein a file is accessed simultaneously with standard I/O and low-level I/O. C implementations that support the UNIX low-level functions may be unable to support mixed-level I/O, if the two forms of I/O are not closely related in the UNIX manner.
UNIX low-level I/O is not included in the ISO/ANSI C standard, so it may be unavailable with recently developed C compilers. Also, do not assume that this form of I/O is truly low-level on any system other than UNIX.
Many systems other than UNIX use other conventions for separating lines of text. For instance, the IBM PC operating system, PC DOS, separates lines of text with two characters, a carriage return followed by a line feed. The IBM 370 uses yet another method. To enable a line-oriented C program written for UNIX to execute under PC DOS, a C implementation must translate a carriage return and line feed to a new-line character on input, and must translate a new-line character to a carriage return and line feed on output. Although this translation is appropriate for a line-oriented program, it is not appropriate for other programs. For instance, a program that writes object code to a file cannot tolerate replacement of a new-line character in its output by a carriage return and a line feed. For this reason, most systems other than UNIX require two distinct forms of file access: text access and binary access.
The ISO/ANSI I/O definition requires that when a program opens a file, it must specify whether the file is to be accessed as a text stream or a binary stream. When a file is accessed as a binary stream, the implementation must read or write the characters without modification. When a file is accessed as a text stream, the implementation must present the file to the program as a series of lines separated by new-line characters, even if a new-line character is not used by the system as a physical line separator. Thus, under PC DOS, when a program writes a file using a binary stream, any new-line characters in the output data are written to the output file without modification. But when a program writes a file using a text stream, a new-line character in the output data is replaced by a carriage return and a line feed to serve as a standard PC DOS line separator.
If a file contains a real new-line character (one that is not a line separator) and the file is read as a text stream, the program will probably misinterpret the new-line character as a line separator. Similarly, a program that writes a carriage return to a text stream may generate a line separator unintentionally. For this reason, the ISO/ANSI library definition leaves the results undefined when any nonprintable characters (other than horizontal tab, vertical tab, form feed, and the new-line character) are read from or written to a text stream. Therefore, text access should be used only for files that truly contain text, that is, lines of printable data.
Programs that open a file without explicitly specifying binary access are assumed to require text access, because the formats of binary data, such as object code, vary widely from system to system. Thus, portable programs are more likely to require text access than binary access.
The ISO/ANSI C library definition deals with fixed data blocks by permitting output files accessed as binary streams to be padded with null ('\0') characters. This padding permits systems that use fixed-size data blocks to always write blocks of the correct size. Because of the possibility of padding, files created with binary streams on such systems may contain one or more null characters after the last character written by the program. Programs that use binary streams and require an exact end-of-file indication must write their own end-of-file marker (which may be a control character or sequence of control characters) to be portable.
A similar padding concern can occur with text access. Some systems support files where all lines must be the same length. (Files defined under MVS or CMS with record format F are of this sort.) ISO/ANSI permits the implementation to pad output lines with blanks when these files are written and to remove the blanks at the end of lines when the files are read. (A blank is used in place of a null character, because text access requires a printable padding character.) Therefore, portable programs write lines containing trailing blanks and expect to read the blanks back if the file will be processed later as input.
Similarly, some systems (such as CMS) support only nonempty lines. Again, ISO/ANSI permits padding to circumvent such system limitations. When a text stream is written, the Standard permits the implementation to write a line containing a single blank, rather than one containing no characters, provided that this line is always read back as one containing no characters. Therefore, portable programs should distinguish empty lines from ones that contain a single blank.
Finally, some systems (such as CMS) do not permit files containing no characters. A program is nonportable if it assumes a file can be created merely by opening it and closing it, without writing any characters.
ftell
and fseek
enable you to obtain the current file position
and return to that position, no matter how the system implements text
and binary access.
Consider a system such as PC DOS, where the combination of carriage return and line feed is used as a line separator. Because of the translation, a program that counts the characters it reads is likely to determine a different character position from the position maintained by the operating system. (A line that the program interprets as n characters, including a final new-line character, is known by the operating system to contain n+1 characters.)
Some systems, such as the 370 operating systems, do not record
physical characters to indicate line breaks. Consider a file on such
a system composed of two lines of data, the first containing the
single character 1
and the second containing the single character
2
. A program accessing this file as a text stream receives the
characters 1\n2\n
. The program must process four characters,
although only two are physically present in the file. A request to
position to the second character is ambiguous. The library
cannot determine whether the next character read should be \n
or
2
.
Even if you resolve the ambiguity of file positioning in favor of portability (by counting the characters seen by the program rather than physical characters), implementation difficulties may preclude seeking to characters by number using a text stream. Under PC DOS, the only way to seek accurately to the 10,000th character of a file is to read 10,000 characters because the number of carriage return and line feed pairs in the file is not known in advance. If the file is opened for both reading and writing, replacing a printable character with a new-line character requires replacing one physical character with two. This replacement requires rewriting the entire file after the point of change. Such difficulties make it impractical on many systems to seek for text streams based on a character number.
Situations such as those discussed in this section show that on most systems where text and binary access are not identical, positioning in a text stream by character number cannot be implemented easily. Therefore, the ISO/ANSI standard permits a library to implement random access to a text stream using some indicator of file position other than character number. For instance, a file position may be defined as a value derived from the line number and the offset of the character in the line.
File positions in text streams cannot be used arithmetically. For
instance, you cannot assume that adding 1 to the position of a
particular character results in the position of the next character.
Such file positions can be used only as tokens. This means that
you can obtain the current file position (using the ftell
function) and later return to that position (using the fseek
function), but no other portable use of the file position is possible.
This change from UNIX behavior applies only to text streams. When you
use fseek
and ftell
with a binary stream, the ISO/ANSI
standard still requires that the file position be the physical
character number.
fsetpos
and fgetpos
.
File systems like the MVS file system have two difficulties implementing random access in the UNIX (ISO/ANSI binary) fashion:
long int
value. Because UNIX operating systems and the Standard
define the file position to have type long int
, random access
to all such enormous files cannot be supported. The functions
fgetpos
and fsetpos
are defined by the Standard to perform
operations similar to those of fseek
and ftell
, except
that the representation of a file position is completely
implementation-defined. This allows an implementation to choose a
representation for the file position that is large enough to address
all characters of the largest possible file and that can take into
account all the idiosyncrasies of the host operating system. (For
example, the file position may reference a disk track number rather
than a record number or byte number.) Thus, using fgetpos
and
fsetpos
for random access produces the greatest likelihood that
a program will run on a system dissimilar to UNIX.
The fsetpos
and fgetpos
functions did not exist prior to
the definition of the ISO/ANSI C standard. Because many C libraries have
not yet implemented them, they are at this time less portable than
fseek
and ftell
, which are compatible with UNIX
operating systems.
However, it is a relatively straightforward task to implement them as
macros that call fseek
and ftell
in such systems. After
these macros have been written, fsetpos
and fgetpos
are
essentially as portable as their UNIX counterparts and will offer
substantial additional functionality where provided by the library on
systems such as MVS.
'\n'
).
The effects of reading or writing control characters using a text
stream are not predictable. An implementation is permitted to record
line separators using some technique other than physical new-line
characters.
For each file organization, there is a corresponding MVS access method for processing such files. (An MVS access method is a collection of routines that can be called by a program to perform I/O.) For instance, files with sequential organization are normally processed with the Basic Sequential Access Method (BSAM). Sometimes, a file can be processed in more than one way. For example, files with direct organization can be processed either with BSAM or with the Basic Direct Access Method (BDAM).
The file organizations of most interest to C programmers are sequential and partitioned. The remainder of this section relates primarily to these file organizations, but many of the considerations apply equally to the others. A number of additional considerations apply specifically to files with partitioned organization. These considerations are summarized in MVS partitioned data sets.
Note: An important type of MVS file, the Virtual Storage Access Method (VSAM) file, was omitted from the previous list. VSAM files are organized as records identified by a character string or a binary key. Because these files differ so greatly from the expected C file organization, they are difficult to access using standard C functions. Because of the importance of VSAM files in the MVS environment, full access to them is provided by nonportable extensions to the standard C library.
Note: Also, if your system supports OpenEdition MVS, it provides a hierarchical file system similar to the system offered on UNIX. The behavior of files in the hierarchical file system is described in UNIX Low-Level I/O . Only traditional MVS file behavior is described here.
The characteristics of a sequential or partitioned file are defined by a set of attributes called data control block (DCB) parameters. The three DCB parameters of most interest are record format (RECFM), logical record length (LRECL), and block size (BLKSIZE).
As stated earlier, MVS files are stored as a sequence of records. To improve I/O performance, records are usually combined into blocks before they are written to a device. The record format of a file describes how record lengths are allowed to vary and how records are combined into blocks. The logical record length of a file is the maximum length of any record in a file, possibly including control information. The block size of a file is the maximum size of a block of data.
The three primary record formats for files are F (fixed), V (variable), and U (undefined). Files with record format F contain records that are all of equal length. Files with format V or U may contain records of different lengths. (The differences between V and U are mostly technical.) Files of both F and V format are frequently used; the preferred format for specific kinds of data (for instance, program source) varies from site to site.
Ideally, the DCB parameters for a file are not relevant to the C program that processes it, but sometimes a C program has to vary its processing based on the format of a file, or to require a file to have a particular format. Some of the reasons for this are as follows:
Therefore, CMS files are classified first by the type of I/O simulation (or lack thereof) used to read or write to them. The three types are
CMS I/O simulation can be used to read files created by OS or VSE, but these operating systems cannot read files created by CMS, even when the files are created using CMS's simulation of their I/O system. In general, CMS adequately simulates OS and VSE file organizations, and the rules that apply in the real operating system also apply under CMS. However, the simulation is not exact. CMS's simulation differs in some details and some facilities are not supported at all.
CMS-format files, particularly disk files, are of most interest to C programmers. CMS disk files have a logical record length (LRECL) and a record format (RECFM). The LRECL is the length of the largest record; it may vary between 1 and 65,535. The RECFM may be F (for files with fixed-length records) or V (for files with variable-length records). Other file attributes are handled transparently under CMS. Files are grouped by minidisk, a logical representation of a physical direct-access device. The attributes of the minidisk, such as writability and block size, apply to the files it contains. Files in the shared file system are organized into directories, conceptually similar to UNIX directories.
Records in RECFM F files must all have the same LRECL. The LRECL is assigned when the file is created and may not be changed. Some CMS commands require that input data be in a RECFM F file. To support RECFM F files, a C implementation must either pad or split lines of output data to conform to the LRECL, and remove the padding from input records.
RECFM V files have records of varying length. The LRECL is the length of the longest record in the file, so it may be changed at any time by appending a new record that is longer than any other record. However, changing the record length of RECFM V files causes any following records to be erased. The length of any given record can be determined only by reading the record. (Note that the CMS LRECL concept is different from the MVS concept for V format files, as the LRECL under MVS includes extra bytes used for control information.)
Some rules apply for both RECFM F and RECFM V files. Records in CMS files contain only data. No control information is embedded in the records. Records may be updated without causing loss of data. Files may be read sequentially or accessed randomly by record number.
As under MVS, files that are intended to be printed reserve the first character of each record for an ANSI carriage control character. Under CMS, these files can be given a filetype of LISTING, which is recognized and treated specially by commands such as PRINT. If a C program writes layout characters, such as form feeds or carriage returns, to a file to effect page formatting, the file should have the filetype LISTING to ensure proper interpretation by CMS.
Be aware that the standard C language does not provide any way for you to interrogate or define file attributes. In cases in which a program depends on file attribute information, you have two choices. You can use the FILEDEF command to define file attributes (if your program uses DDnames), or you can use nonportable mechanisms to access or specify this information during execution.
Partitioned data sets have several properties that make them particularly difficult for programs that were written for other file systems to handle:
These limitations may cause ISO/ANSI-conforming programs to fail when they use PDS members as input or output files. For instance, it is reasonable for a program to assume that it can append data to the end of a file. But due to the nature of PDS members, it is not feasible for a C implementation to support this, except by saving a copy of the member and then replacing the member with the copy. Although this technique is viable, it is very inefficient in both time and disk space. (This tradeoff between poor performance and reduced functionality is one that must be faced frequently when using C I/O on the 370. PDS members, which are perhaps the most commonly used kind of MVS file, are the most prominent examples of such a tradeoff.)
Note: Recent versions of MVS support an extended form of PDS, called a PDSE. Some of the previously described restrictions on a PDS do not apply to a PDSE. For example, unused space is reclaimed automatically in a PDSE.
In general, MACLIBs and TXTLIBs may not be written by OS-simulated I/O. Instead, data are added or removed a member at a time by CMS commands. Input from MACLIBs and TXTLIBs can be performed using either OS-simulation or native CMS I/O.
In the traditional MVS file system, all files occupy a single name space. (This is an oversimplification, but a necessary one.) Programs that open files by a physical filename are limited to the use of exactly one file at a site. You can use several techniques to increase program flexibility in this area, none of which is completely satisfactory. These techniques include the following:
Because most traditional filenames include periods, which are not permitted in DDnames, programs from other environments may need to be modified if they are to use DDnames, and if the logic of the program will withstand such a change.
Under CMS, you can use other techniques to increase program flexibility:
xyz.c
as /tools/asm/main.c
is the same as the shared filename
MAIN C TOOLS.ASM.
An alternate interpretation of file existence under MVS that avoids this problem is to declare that a file exists after a program has opened it for output. By this interpretation, a file created by control language immediately before execution does not yet exist. Unfortunately, this definition of existence cannot be implemented because of the following technicalities:
A third interpretation of existence is to say that an MVS file exists if it contains any data (as recorded in the VTOC). This has the disadvantage of making it impossible to read an empty file but the much stronger advantage that a file created by control language immediately before program execution is perceived as not existing. This is the interpretation used in the SAS/C implementation.
This ambiguity about the meaning of existence applies only to files with sequential organization. For files with partitioned organization, only the file as a whole is created by control language; the individual members are created by program action. This means that existence has its natural meaning for PDS members, and that it is possible to create a PDS member containing no characters.
CMS does not allow the existence of files containing no characters, and it is not possible to create such a file.
For the reasons detailed in IBM 370 I/O Concepts , C I/O on the 370 cannot support all three of these properties simultaneously. The library provides several different kinds of I/O to allow the programmer to select the properties that are most important.
The library offers two separate I/O packages:
Details on both of these I/O packages are presented in the following sections.
Two other I/O packages are provided: CMS low-level I/O, defined for low-level access to CMS disk files, and OS low-level I/O, which performs OS-style sequential I/O. These forms of I/O are nonportable and are discussed in Chapter 2, "CMS Low-Level I/O Functions," and Chapter 3, "MVS Low-Level I/O Functions," in SAS/C Library Reference, Volume 2.
Besides the I/O functions defined by the Standard, several augmented
functions are provided to exploit 370-specific features. For instance,
the afopen
function is provided to allow the program to specify
370-dependent file attributes, and the afread
routine is
provided to allow the program to process records that may include
control characters. Both standard I/O functions and augmented
functions may be used with the same file.
"term"
, "seq"
, "rel"
, "kvs"
, and "fd"
.
When a file is opened, the library ordinarily selects the access
method to be used. However, when you use the afopen
function to
open a file, you can specify one of these particular access methods.
"term"
access method to perform terminal
I/O; this access method applies only to terminal files. (See
Terminal I/O for more information on this access method.)
"rel"
access method is used for nonterminal files whose attributes
permit them to support UNIX file behavior when accessed as binary
streams.
"kvs"
access method is used for VSAM files when access is via
the SAS/C nonstandard keyed I/O functions. (See
Using VSAM Files .)
"fd"
access method is used for files in the OpenEdition
hierarchical file system.
"seq"
access method is used with all text streams
and for binary streams that cannot support the "rel"
access
method, except when "fd"
is used.
"rel"
access method Under MVS, the "rel"
access
method can be used for files with sequential organization and RECFM F,
FS, or FBS. (The limitation to sequential organization means that the
"rel"
access method cannot be used to process a PDS member.) Under
CMS, the "rel"
access method can be used for disk files with RECFM F.
The "rel"
access method is designed to behave like UNIX disk I/O:
"rel"
access method.
\0
)' will be added at the end of file, if
necessary to complete a record when the file is closed. If you define
a file processed by the "rel"
access method to have a record length of
1, you can avoid this padding.
"kvs"
access method The "kvs"
access method
processes any file opened with the extension open mode "k"
(indicating keyed I/O). This access method is discussed
in more detail in Using VSAM Files .
The "fd"
access method The "fd"
access method
processes any file residing in the OpenEdition MVS hierarchical file
system. These files are fully compatible with UNIX.
In files processed with the "fd"
access method, there is no
difference between text and binary access.
The "seq"
access method The "seq"
access method
processes a nonterminal non OpenEdition file if any one of the following
apply:
"rel"
access
"seq"
access method is specifically requested.
In general, the "seq"
access method is implemented to use efficient
native interfaces, forsaking compatibility with UNIX operating systems
where necessary. Some specific incompatibilities are listed here:
fsetpos
and fgetpos
functions are fully supported, except for
certain files with unusual attributes such as multivolume disk files.
(See Tables 3.5 and 3.6 for a complete list of restricted file types.)
The fseek
and ftell
functions are supported only for
text streams. This restriction is necessary because the C Standard
requires that the file position be defined as a relative character
number for binary streams, which cannot be efficiently determined on
370 systems. If an application requires access to binary data by
character number, it should be either restricted to using files that
can be processed by the "rel"
access method, or it should use the
UNIX style I/O package.
afopen
function gives you
some control over the way padding is performed.
afopen
, the program can inform the library of any
dependence on truncation or lack of truncation. For CMS disk files,
truncation is optional and you can use afopen
to indicate
whether truncation should occur.
open
,
read
, write
, lseek
, and close
. This
allows programs that use these functions to run easily with the SAS/C
library.
The library connects the use of the UNIX low-level I/O interface and the ability to do seeking by character number because UNIX documentation has traditionally stressed that seeking by character number is not guaranteed when standard I/O is used. The UNIX Version 7 Programmer's Manual states that the file position used by standard I/O "is measured in bytes only on UNIX; on some other systems it is a magic cookie."
As a result of the second property, UNIX style I/O is less efficient
than standard I/O for the same file, unless the file is suitable for
"rel"
access, or it is in the OpenEdition hierarchical file system.
In these cases, there is little additional overhead.
For files suitable for "rel"
access, UNIX style I/O simply translates
I/O requests into corresponding calls to standard I/O routines. Thus,
for these files there is no decrease in performance.
For files in the OpenEdition hierarchical file system, UNIX style I/O calls the operating system low-level I/O routines directly. For these files, use of standard I/O by UNIX style I/O is completely avoided.
For other files, UNIX style I/O copies the file to a temporary file
using the "rel"
access method and then performs all requested I/O to
this file. When the file is closed, the temporary file is copied back
to the user's file, and the temporary file is then removed. This
means that UNIX style I/O for files not suitable for "rel"
access has
the following characteristics:
close
of an output file, when all the
data must be copied back. As an optimization, input data are copied
from the user's file only as necessary, rather than copying all the
data when the file is opened.
All of the discussion within this section assumes that the user's file is accessed as a binary file: that is, without reference to any line structure. Occasionally, there are programs that want to use this interface to access a file as a text file. (Most frequently, such programs come from non UNIX environments like the IBM PC.)
As an extension, the library supports using UNIX style I/O to process a file as text. However, file positioning by character number is not supported in this case, and no copying of data takes place. Instead, UNIX style I/O translates I/O requests to calls equivalent to standard I/O routines.
Note that UNIX style I/O represents open files as small integers called file descriptors. Unlike UNIX, with MVS and CMS, file descriptors have no inherent significance. Some UNIX programs assume that certain file descriptors (0, 1, and 2) are always associated with standard input, output, and error files. This assumption is nonportable, but the library attempts to support it where possible. Programs that use file 0 only for input, and files 1 and 2 only for output, and that do not issue seeks to these files, are likely to execute successfully. Programs that use these file numbers in other ways or that mix UNIX style and standard I/O access to these files are likely to fail.
UNIX operating systems follow specific rules when assigning file descriptors to open files. The library follows these rules for OpenEdition files and for sockets. However, MVS or CMS files accessed using UNIX I/O are assigned file descriptors outside of the normal UNIX range to avoid affecting the number of OpenEdition files or sockets the program can open. UNIX programs that use UNIX style I/O to access MVS or CMS files may therefore need to be changed if they require the UNIX algorithm for allocation of file descriptors.
"term"
access method uses TPUT ASIS to write to the terminal and
TGET EDIT to read from the terminal. Access to SYSTERM in batch is
performed using QSAM.
"seq"
access method uses BSAM and BPAM for both input and output.
VSAM is used for access to VSAM ESDS and KSDS data sets.
"rel"
access method uses XDAP and BSAM. XDAP is used for input
and to update all blocks of the file except the last block. BSAM is
used to update the last block of the file or to add new blocks.
VSAM is used to access VSAM relative record data sets, and DIV is used
to access VSAM linear data sets.
"kvs"
access method uses VSAM for all operations.
"fd"
access method uses OpenEdition service routines for all
operations.
Although BDAM is not used by the "rel"
access method, direct
organization files that are normally processed by BDAM are supported,
provided they have fixed-length records and no physical keys.
"term"
access method uses TYPLIN or LINEWRT to write to the
terminal and WAITRD or LINERD to read from the terminal.
"seq"
access method uses device-dependent techniques. For CMS
disk files, it uses FSCB macros (FSREAD, FSWRITE, and so on). For access
to shared files, it uses the CSL DMSOPEN, DMSREAD, and DMSWRITE services.
For access to shared file system directories, it uses the DMSOPDIR and
DMSGETDI services.
For spool files, it uses CMS native macros such as RDCARD. For tape files, filemode 4 disk files, and files on OS disks, it uses simulated MVS BSAM. VSAM KSDS and ESDS data sets are processed using simulated VSE/VSAM.
"rel"
access method uses FSCB macros. Where appropriate, it
creates sparse CMS files. VSAM RRDS data sets are processed using
simulated VSE VSAM.
"kvs"
access method uses VSE VSAM for all operations.
"rel"
access under MVS"rel"
access method if it is
not a PDS or PDS member, and if it has RECFM F, FS, or FBS. These
record formats ensure that there are no short blocks or unfilled
tracks in the file, except the last, and make it possible to reliably
convert a character number into a block address (in CCHHR form) for
the use of XDAP. Use of "rel"
may also be specified for regular files
in the OpenEdition file system (in which case the "fd"
access method
is used).
If the LRECL of an FBS file is 1, then an accurate end-of-file pointer can be maintained without adding any padding characters. Because of the use of BSAM and XDAP to process the file, use of this tiny record size does not affect program efficiency (data are still transferred a block at a time). However, it may lead to inefficient processing of the file by other programs or languages, notably ones that use QSAM.
"rel"
access method if it is
a CMS disk file (not filemode 4) with RECFM F. Use of RECFM F ensures
that a character number can be converted reliably to a record number
and an offset within the record.
If the LRECL of a RECFM F file is 1, then an accurate end-of-file pointer can be maintained without ever adding any padding characters. Because the file is processed in large blocks (using the multiple record feature of the FSREAD and FSWRITE macros), use of this tiny record size does not affect program efficiency. Nor does it lead to inefficient use of disk space, because the files are physically blocked according to the minidisk block size. However, it may lead to inefficient processing of the file by other programs or languages that process one record at a time.
tmpfile
function.
One of two methods is used to create the temporary file whose number is nn. First, a check is made for a SYSTMPnn DD statement. If this DDname is allocated and defines a temporary data set, then this data set is associated with the temporary file. If no SYSTMP nn DDname is allocated, the library uses dynamic allocation to create a new temporary file whose data set name depends on the file number. (The system is allowed to select the DDname, so there is no dependency on the SYSTMPnn style of name.) The data set name depends also on information associated with the running C programs, so that several C programs can run in the same address space without conflicts occurring between temporary filenames.
If a program is compiled with the posix
compiler option, then
temporary files are created in the OpenEdition hierarchical file system,
rather than as MVS temporary files. The OpenEdition temporary files
are created in the /tmp
HFS directory.
Temporary files are normally allocated using a unit name of VIO and a space allocation of 50 tracks. The unit name and default space allocation can be changed by a site, as described in the SAS/C installation instructions. If a particular application requires a larger space allocation than the default, use of a SYSTMPnn DD statement specifying the required amount of space is recommended.
tmpfile
function.
A program can create more than one temporary file during its execution. Each temporary file is assigned a temporary file number, starting sequentially at 1.
One of two methods is used to create the temporary file whose number is nn. First, a check is made for a FILEDEF of the DDname SYSTMP nn. If this DDname is defined, then it is associated with the temporary file. If no SYSTMPnn DDname is defined, the library creates a file whose name has the form $$$$$$nn $$$$xxxx, where nn is the temporary file number, and the xxxx part of the filetype is associated with the calling C program. This naming convention allows several C programs to execute simultaneously without conflicts occurring between temporary filenames.
Temporary files are normally created by the library on the write-accessed minidisk with the most available space. Using FILEDEF to define a SYSTMPnn DDname with another filemode allows you to use some other technique if necessary.
Be aware that these temporary files are not known to CMS as temporary files. Therefore, they are not erased if a program terminates abnormally or if the system fails during its execution.
Any kind of VSAM file may be used via standard access. Restrictions apply to particular file types, for example, a KSDS may not be opened for output using standard I/O.
"rel"
access method
because it is not possible, given a character position, to determine
the RBA (relative byte address) of the record containing the
character.
fseek
or fsetpos
is not supported, because records are ordered by key, and
it is not possible to transform a key value into the file position formats
used for other library file types. When a KSDS is used for input, records
are always presented to the program in key order, not in the order of their
physical appearance in the data set. Note that KSDS output is available when
keyed access is used.
"rel"
access method only. Only RRDS data sets with a fixed record length are
supported. As with all other files accessed via "rel"
, file
positioning using fseek
and ftell
are fully supported.
"rel"
access method.
As with all other files accessed via "rel"
, file
positioning using fseek
and ftell
are fully supported.
VSAM ESDS, KSDS and RRDS files are processed using a single RPL. Move mode
is used to support spanned records. A VSAM file cannot be
opened for write only (open mode "w"
) unless it was defined by Access
Method Services to be a reusable file.
fseek
and ftell
functions, which are more widely available
than fsetpos
or fgetpos
. Note that you cannot use file
positions arithmetically with these functions. (You may be forced to
use fsetpos
and fgetpos
rather than fseek
and
ftell
if you need to support very large files.)
fsetpos
and fgetpos
, or restrict the
application to using files suitable for "rel"
access. The advantage
of UNIX style I/O is that it is applicable to most files and is
somewhat portable. The advantage of fsetpos
and fgetpos
is that they are defined by the C Standard, so they are portable. The
advantage of restricting the application to files suitable for "rel"
access is that maximum efficiency is achieved with the most portable
interface. If the file is only used by C programs (for example, if the
file is a work file, or if it is not accessed by the outside world),
then requiring suitable file attributes is clearly the best solution.
If your application does not have to be portable, there are several additional possibilities. Note, however, that even if portability is not a requirement, one of the portable techniques described earlier may still be most appropriate.
afread
and
afwrite
. These routines are especially useful if the records
may contain control characters (which makes standard I/O text access
inappropriate).
fsetpos
and fgetpos
rather than fseek
and ftell
for file positioning. These
routines have fewer restrictions and their results are more easily
interpreted.
fseek
and ftell
for file positioning, you must modify
the program or restrict it to use only the "rel"
access method.
(Such an application could be modified to use UNIX style I/O or to use
fsetpos
and fgetpos
for positioning.) Further modifications
or restrictions on file type may be required if the program cannot
tolerate the addition of trailing nulls at end of file.
"rel"
access, because then the file can be
processed without copying. If the program does not depend on some of
the details of UNIX style I/O (for instance, if it is not sensitive to
the exact nature of file positions), it can be converted to use
standard I/O for better performance.
lseek
to do file positioning, it requires substantial
modification. The library does not support file positioning by
character number when UNIX style I/O is used to access a file as text.
In general, a program that uses standard I/O accesses a file in the following steps:
fopen
or the
augmented function afopen
. This establishes a connection
between the program and the external file. The name of the file to
open is passed as an argument to fopen
or afopen
.
The fopen
and afopen
functions return a pointer to an object of type
FILE
. (This type is defined in the header file <stdio.h>
,
which should be included with a #include
statement by any
program that uses standard I/O.) The data addressed by this
FILE
pointer are used to control all further program access to the
file.
FILE
pointer returned by fopen
is
passed to the other functions to identify the file to be processed.
FILE
pointer is no longer valid.
When a program terminates (except as the result of an ABEND), all
files that have not been closed by the program are closed
automatically by the library.
For convenience, three standard files are opened before program
execution, accessible with the FILE
pointers stdin
,
stdout
, and stderr
. These identify the standard input
stream, standard output stream, and standard error stream,
respectively. For TSO or CMS programs, these FILE
objects
normally identify the terminal, but they can be redirected to other
files by use of command-line options. For programs running under the
OpenEdition shell, these FILE
objects reference the standard
files for the program that invoked them. More information on the
standard streams is available later in this section.
Standard I/O functions may be grouped into several categories. The functions in each category and their purposes are listed in Table 3.1.
Table 3.1 Standard I/O Functions
Function Purpose
Control Functions control basic access to files fopen + opens a file afopen *+ opens a file with system-dependent options freopen + reopens a file afreopen *+ reopens a file with system-dependent options tmpfile creates and opens a temporary file tmpnam generates a unique filename fflush writes any buffered output data afflush + forces any buffered output data to be written immediately fclose + closes a file setbuf + changes stream buffering setvbuf + changes stream buffering Character I/O Functions read or write single characters fgetc reads a character getc reads a character (macro version) ungetc pushes back a previously read character getchar reads a character from stdin fputc writes a character putc writes a character (macro version) putchar writes a character to stdout String I/O Functions read or write character strings fgets reads a line into a string gets reads a line from stdin into a string fputs writes a string puts writes a line to stdout Array I/O Functions read or write arrays or objects of any data type fread reads one or more data elements fwrite writes one or more data elements Record I/O Functions read or write entire records afread * reads a record afread0 * reads a record (possibly length 0) afreadh * reads the initial part of a record afwrite * writes a record afwrite0 * writes a record (possibly length 0) afwriteh * writes the initial part of a record Formatted I/O Functions easily read or write formatted data fprintf writes one or more formatted items printf writes one or more formatted items to stdout sprintf formats items into a string snprintf * formats items into a string (with maximum length) fscanf reads one or more formatted items scanf reads one or more formatted items from stdin sscanf obtains formatted data from a string vfprintf writes formatted data to a file vprintf writes formatted data to standard output stream vsprintf writes formatted data to a string vsnprintf writes formatted data to a string (with maximum length) File Positioning Functions interrogate and change the file position fseek positions a file fsetpos positions a file rewind positions a file to the first byte ftell returns current file position for fseek fgetpos returns current file position for fsetpos Keyed Access Functions read, write and position a keyed stream kdelete *+ delete a record from a keyed file kgetpos *+ return position of current keyed file record kinsert *+ add a new record to a keyed file kreplace *+ replace a new record in a keyed file kretrv *+ retrieve a record from a keyed file ksearch *+ search for a record in a keyed file kseek *+ reposition a keyed file ktell *+ return RBA of current record of keyed file Error-Handling Functions test for and continue execution after I/O errors and other I/O conditions feof + tests for end of file ferror + tests for error clearerr + resets previous error condition clrerr *+ resets previous error condition File Inquiry Functions obtain information about an open file at execution time fattr *+ returns file attributes fileno * returns file number ffixed *+ tests whether a file has fixed length records fnm *+ returns the name of a file fterm *+ tests whether a file is the user's terminal*These functions are not defined in the ANSI standard. Programs that use them should include
lcio.h
rather than stdio.h
. open
or
aopen
.
(aopen
is not compatible with UNIX operating systems
but permits the program to specify 370-dependent file processing
options.) The name of the file to open is passed as an argument to
open
or aopen
.
open
and aopen
return an integer called the file number
(sometimes file descriptor). The file number is passed to the other
UNIX style functions to identify the file. It indexes a table
containing information used to access all files accessed with
UNIX style I/O. Be sure to use the right kind of object to identify a
file: a FILE
pointer with standard I/O, but an integer file
number with UNIX style I/O.
By convention, UNIX assigns the file numbers 0, 1, and 2 to the
standard input, output, and error streams. Some programs use
UNIX style I/O with these file numbers in place of
standard I/O to stdin
, stdout
, and stderr
, but
this practice is nonportable. The library attempts to honor this kind
of usage in simple cases, but for the best results the use of standard
I/O is recommended.
UNIX style I/O offers fewer functions than standard I/O. No formatted
I/O functions or error-handling functions are provided. In general,
programs that require elaborately formatted output or control of error
processing should, where possible, use standard I/O rather than
UNIX style I/O. Some UNIX style I/O functions, such as fcntl
and ftruncate
are supported only for files in the OpenEdition
hierarchical file system.
The functions supported by UNIX style I/O and their purposes are
listed in Table 3.2. Note that the aopen
function is not
defined by UNIX operating systems. Also note that some POSIX-defined
functions, such as ftruncate
, are not implemented by all
versions of UNIX.
Table 3.2 UNIX Style I/O Functions
Function Purpose
Control Functions aopen * opens a file with system-dependent options close + closes a file creat creates a file and opens it for output dup - duplicates a file descriptor dup2 - duplicates a file descriptor fcntl +- controls file options and attributes fdopen +- associates a file descriptor with a FILE pointer fsync forces output to be written to disk ftruncate - truncates a file mkfifo - creates an OpenEdition FIFO special file mknod - creates an OpenEdition special file open - opens a file for UNIX style I/O pipe - creates an OpenEdition pipe Character I/O Functions read + reads characters from a file write + writes characters to a file File Positioning Functions lseek positions a file File Inquiry Functions ctermid returns the terminal filename isatty + tests whether a file is the user's terminal ttyname returns the name of the terminal associated with a file descriptor*This function is not defined by UNIX operating systems.
fopen
, afopen
, and
open
), they all have certain points of similarity. The filename (or
pathname) and an open mode are passed as arguments to each of these
functions. The filename identifies the file to be opened. The open
mode defines how the file will be processed. For example, the
function call fopen("input", "rb")
opens the file whose name is
input
for binary read-only processing.
Some of the open functions enable the caller to specify a C library
access method name, such as "rel"
, and access method parameters (or
amparms) such as "recfm=v"
. Access method parameters allow the
program to specify system or access-method-dependent information such
as file characteristics (for example, record format) and processing
options (for example, the number of lines per page). The details for
each of these specifications are described in this section.
style
: name
, where the portion of the name before
the colon defines the filename style, and the portion after the colon is
the name proper. For example, the style ddn
indicates that the
filename is a DDname, while the style cms
indicates that the
filename is a CMS fileid or device name.
Note:
The //
before the rest of the pathname is optional, except for
programs compiled with the posix
option. See OpenEdition I/O Considerations
for a discussion of filenames for posix
-compiled programs.
The
part of the filename is optional. If no style
is specified, the style is chosen as follows:
style
:
//
prefix, the default style is
tso
in MVS, or cms
in CMS.
_style
with an initial
value, then that value is used as the style. (See Chapter 9 in the
SAS/C Compiler and Library User's Guide, Fourth Edition for more information on the external variable _style
.)
For instance, if the initial value of _style
is tso
,
then the filename XYZ.DATA is interpreted as tso:xyz.data
.
_style
is defined, the default style is
ddn
under MVS, and cms
under CMS. This means that by
default, filenames are interpreted as DDnames under MVS and as fileids
or device names under CMS.
As an aid to migration of programs between MVS and CMS, filenames
oriented toward one system, such as cms:user maclib
and
tso:output.list
, are accepted by the other system when a clearly
equivalent filename can be established. (See the next section for
details.)
The rules just described apply only to programs that are not compiled
with the posix
compiler option. For posix
-compiled
programs, all pathnames are treated as hierarchical file system names,
unless they are preceded by the //
prefix, even if they appear to contain
a style prefix.
ddn
, dsn
, tso
, and hfs
. A ddn
-style
filename is a DDname, a dsn
-style filename is a data set name in
JCL syntax, a tso
-style filename is a data set name in TSO syntax,
and an hfs
-style filename is a pathname referencing the OpenEdition
hierarchical file system.
ddn-style filenames A filename in ddn
style is a
valid DDname, possibly preceded by leading white space. The filename
can be in uppercase or lowercase letters, although it is translated to
uppercase letters during processing. The following alternate forms
are also allowed, permitting access to PDS members and to the TSO
terminal:
*
*ddname
ddname*
ddname( member-name
)
A ddn
-style filename of *
always references the user's
TSO terminal. If you use this filename in a batch job, it references
the SYSTERM DDname, if the file is being opened for output or append.
(See Open modes for more information.) The filename *
is not supported for input in batch.
For a program executing under the OpenEdition shell, a ddn
-style
filename of *
is interpreted as referencing /dev/tty
in the hierarchical file system.
A ddn
style filename of *ddname
references the terminal
for a TSO session or the DDname indicated for a batch job. For
example, the filename *sysin
requests use of the terminal under
TSO or of the DDname SYSIN in batch.
A ddn
-style filename of ddname*
references the indicated
DDname, if that DDname is defined. If the DDname is not defined,
ddname*
references the TSO terminal or SYSTERM in batch (for an
open for output or append). For example, the filename LOG*
requests the use of the DDname LOG, if defined, and otherwise, the
user's TSO terminal.
A ddn
-style filename of ddname(
references a member of the PDS identified by the DDname. For example,
the filename member-name
)SYSLIB(fcntl)
requests the member FCNTL of the
data set whose DDname is SYSLIB. If the DD statement also specifies a
member name, the member name specified by the program overrides it.
With the availability of OpenEdition, another ddn
-style filename is
possible:
ddname/filenameHere,
ddname
is a valid MVS filename, and filename
is a
valid POSIX filename (not containing any slashes).
For more information on this form, see Using HFS directories and PDS members interchangeably .
Note:
Programs invoked via the OpenEdition exec
system
call do not ordinarily have access to DD statements. A SAS/C extension
allows environment variables to be used in place of DD statements,
as described in OpenEdition I/O Considerations .
dsn-stylefilenames A filename in dsn
style is a
valid, fully qualified data set name (possibly including a member
name), optionally preceded by leading white space. The data set name
can be in uppercase or lowercase letters, although it is translated to
uppercase letters during processing. The data set name must be
completely specified; that is, there is no attempt to prefix the name
with a userid, even for programs running under TSO. (Programs that
want to have the prefix added should use the tso
filename
style.) For more information on data set names and their syntax,
consult the IBM manual MVS/ESA JCL Reference.
The following alternate forms for dsn
-style names are also
allowed, permitting access to temporary data sets, the TSO terminal,
DUMMY files, and SYSOUT files:
* nullfile sysout=Aclass
tmpname
dsn
-style filename of *
always references the user's
TSO terminal. If this filename is used in a batch job, it references
the SYSTERM DDname, if the file is being opened for output or append.
(See Open modes .) The filename *
is not supported
for input in batch.
For a program running under the OpenEdition shell, *
is interpreted
as referencing /dev/tty
.
A dsn
-style filename of nullfile
references a DUMMY
(null) data set. Reading a DUMMY data set produces an immediate end
of file; data written to a DUMMY data set are discarded.
A dsn
-style filename of sysout=
references a
SYSOUT (printer or punch) data set of the class specified. The
class
must be a single alphabetic or numeric character,
or an asterisk.
class
A dsn
-style filename of &
references a new
temporary data set, whose name is tmpname
&
. The name is
limited to eight characters.
tmpname
tso-style filenames A filename in tso
style is a
data set name (possibly including a member name) specified according
to TSO conventions, optionally preceded by leading white space. The
data set name can be in uppercase or lowercase letters, although it is
translated to uppercase letters during processing. If the data set
name is not enclosed in single quotation marks, the name is prefixed with the
user's TSO prefix (normally the userid), as defined by the TSO PROFILE
command. If the data set name is enclosed in single quotation marks, the
quotes are removed and the result is interpreted as a fully qualified
data set name. For more information on TSO data set names and their
syntax, consult the IBM manual TSO Extensions User's Guide.
Note:
tso
-style filenames are not guaranteed to be available, except for
programs executing under TSO. If you attempt to open
a tso
-style filename in MVS batch (or under the OpenEdition shell),
the userid associated with the batch job is used as the data set prefix.
Determining the userid generally requires RACF or some other security
product to be installed on the system. If the userid cannot be
determined, the open call will fail.
The following alternate forms for tso
-style names are also
allowed, permitting access to the TSO terminal and DUMMY files.
* 'nullfile'A
tso
-style filename of *
always references the user's
TSO terminal.
For programs running under the OpenEdition shell, it is interpreted as
referencing the HFS file called /dev/tty
.
A tso
-style filename of 'nullfile'
references a DUMMY
data set. Reading a DUMMY data set produces an immediate end of file;
data written to a DUMMY data set are discarded.
cms-style filenames For compatibility with CMS, the MVS
version of the SAS/C library accepts cms
-style filenames, where
possible, by transforming them into equivalent tso
-style
filenames. See the next section, "Filename specification under CMS,"
for details on the format of
cms
style filenames.
A cms
-style filename is transformed into a tso
-style
filename by replacing spaces between the filename components with
periods, removing the MEMBER keyword, and adding a closing parenthesis
after the member name, if necessary. Also, the filenames
cms: *
and cms:
are interpreted as tso: *
and
tso: 'nullfile'
, respectively. For instance, the following
transformations from cms
-style to tso
-style names are
performed:
cms: profile exec a1 tso: profile.exec.a1 cms: lc370 maclib (member stdio tso: lc370.maclib(stdio) cms: reader tso: reader cms: * tso: * cms: tso: 'nullfile'hfs-style filenames A filename in
hfs
style is
a pathname in the OpenEdition hierarchical file system. If the
pathname begins with a /
, the pathname is an absolute pathname,
starting at the root directory. If the pathname does not begin with a
/
, it is interpreted relative to the current directory.
Note:
You cannot open an HFS directory using fopen
or open
.
The opendir
function must be used for this purpose.
cms
, xed
, ddn
, sf
, and sfd
. A
cms
- or xed
-style filename is a CMS fileid or device
name. A ddn
-style file is a DDname (FILEDEF or DLBL name).
A sf
-style filename is the name of a CMS shared file system
file, and a sfd
-style filename is a pattern defining a subset
of a CMS shared file system directory.
The only difference between the cms
and xed
styles is
that, if a program is running under XEDIT, use of the xed
prefix allows reading of the file from XEDIT, rather than from disk.
cms- and xed-style filenames A filename in cms
style is a CMS fileid or device name. You can specify fileids in one
of two formats: a CMS standard format, or a compressed format. The
compressed format contains no blanks, so it can be used in cases in
which the presence of blanks is not allowed, such as in command-line
redirections. The xed
style permits a subset of the valid
cms
specifications, as described in Advanced CMS I/O Facilities .
Here is the standard form for a cms
-style filename:
The brackets indicate optional components. The filename may be preceded by white space and can be in uppercase or lowercase letters, although it is translated to uppercase letters during processing. Detailed rules for this style of filename are as follows:filename
[filetype
[filemode
]] [(MEMbermember-name
)]]
FILE
is assumed,
unless the MEMBER keyword is present, in which case, the filetype
MACLIB
is assumed.
*
, a search is made
for an existing file on an accessed disk using the standard CMS search
order. If no existing file can be located, and the open mode permits
output, a filemode of A1 is assumed.
member-name
only for files whose
filetype is MACLIB
or TXTLIB
, opened for input. The
keyword MEMber
may be abbreviated to MEM
. (The
xed
style does not allow a member name to be specified.)
Here is the compressed form for a cms
-style filename:
This form of filename is interpreted in exactly the same way as the corresponding standard name. For example,filename
[.filetype
[.filemode
]] [(member-name
)]
cms: freds maclib (mem smith)
and cms: freds.maclib(smith)
are equivalent specifications. For more information on CMS fileids,
consult the IBM CMS manuals listed in Chapter 1, "Introduction," in the SAS/C Compiler and Library User's Guide, Fourth Edition .
The following alternate forms for cms
-style names are also
allowed, permitting access to unit record devices and members of
GLOBAL MACLIBs or TXTLIBs. (See Advanced CMS I/O Facilities for a
description of access to GLOBAL MACLIBs and TXTLIBs.) After each form,
valid abbreviations are given. (None of these forms can be used with
the xed
style.)
Alternate Forms Abbreviations
TERMINAL TERM, * READER RDR PRINTER PRT PUNCH PUN, PCH %MACLIB(membermember-name
) %MACLIB(member-name
) %TXTLIB(membermember-name
) %TXTLIB(member-name
)
""
) may be used to open a dummy file.
Note: To open a CMS disk file whose filename is the same as one of the above device names, you must specify both the filename and the filetype.
ddn-style filenames A filename in ddn
style is a
valid DDname, possibly preceded by white space. The filename can be
in uppercase or lowercase letters, although it is translated to
uppercase letters during processing. The DDname must be previously
defined using the FILEDEF command (or the DLBL command for a VSAM
file). The following alternate forms are also allowed, permitting
access to members of MACLIBs, TXTLIBs, and MVS PDSs, and to the CMS
terminal. (All forms have approximately the same meaning as under
MVS.) For more information, see Filename specification under MVS .
*
*ddname
ddname*
ddname( member-name
)
A ddn
-style filename of *
always references the user's
CMS terminal.
A ddn
-style filename of *ddname
also references the
terminal. (The DDname is never used because the terminal is always
defined under CMS.)
A ddn
-style filename of ddname*
references the indicated
DDname, if that DDname is defined. If the DDname is not defined, it
references the CMS terminal. For example, the filename LOG*
requests the use of the DDname LOG, if defined, and otherwise, the
user's terminal.
A ddn
-style filename of ddname(
references a member of the MACLIB, TXTLIB, or MVS PDS identified by
the DDname. For example, the filename member-name
)SYSLIB(fcntl)
requests
the member FCNTL of the file whose DDname is SYSLIB. If the FILEDEF
command also specifies a member name, the member name specified by the
program overrides it.
tso-style filenames For compatibility with MVS, the CMS
version of the library accepts tso
-style filenames where
possible, by transforming them into equivalent cms
-style
filenames. See Filename specification under MVS for details on the format
of such filenames.
A tso
-style filename is transformed into a cms
-style
filename by removing single quotation marks, if present, and treating the
resulting name as a compressed format fileid. (The result must be a
valid CMS fileid or the open fails.) In addition, the specification
tso: *
is interpreted as cms: terminal
. For instance,
the following transformations from tso
-style to cms
-style
names are performed:
tso: input.data cms: input data tso: parser.source.c cms: parser source c tso: 'sys1.maclib(dcb)' cms: sys1 maclib (member dcb tso: * cms: terminal
sf-style filenames A sf
-style filename references
a file in the CMS shared file system. See Using the CMS Shared File System
for detailed information on the syntax of sf
-style filenames.
sfd-style filenames A sfd
-style filename
references a CMS shared file system directory or directory subset.
See Using the CMS Shared File System for detailed information of the syntax
of sfd
-style filenames.
Standard I/O open modes When you open a file using standard I/O, the open mode is a character string consisting of one to three enquoted characters. The syntax for this string is as follows:
r|w|a[+][b|k]The first character must be
'r'
, 'w'
, or 'a'
.
After the first character, a '+'
may appear, and after the
'+'
(or after the first character, if '+'
is omitted),
'b'
or 'k'
may appear. No blanks may appear in the string,
and all characters must be lowercase letters.
The 'r|w|a'
character specifies whether the file is to be
opened for reading, writing, or appending. If a '+'
appears,
both reading and writing are permitted.
If a 'b'
appears, the file is accessed as a binary stream.
If a 'k'
appears, the file is accessed as a keyed stream.
If neither 'b'
nor 'k'
appears, the file is accessed as text.
See Text access and binary access for detailed information on the differences
between text and binary access. See Using VSAM Files for information
on keyed access.
The effect of the 'r|w|a'
specification and the '+'
are
closely linked and must be explained together.
'r'
or 'rb'
is a read-only
file. The file must already exist. (See File existence .)
'rk'
is a read-only file suitable
for keyed access. Records can be retrieved, but not replaced, deleted,
or inserted. If the file has not been loaded, the open will fail.
'r+'
or 'r+b'
can be both
read and written. The file must already exist. (See
File existence .)
'r+k'
can be read, or written
using keyed access, or both. All file operations are permitted. If the file has
not been loaded, the open will fail.
'w'
or 'wb'
is a write-only
file. If the file already exists, its previous contents are discarded.
'wk'
is a write-only file
suitable for keyed access. If the file contains any records, they are
erased. If the file is not defined as REUSABLE and it contains any records,
the open will fail. This open mode enables records to be added to the
file, but not to be retrieved, updated, or deleted.
'w+'
or 'w+b'
can be both
read and written. If the file already exists, its contents are
discarded when it is opened.
'w+k'
can be read, or written
using keyed access, or both. If the file contains any records, they are erased.
If the file is not defined as REUSABLE and it contains any records, the
open will fail. All file operations are permitted.
'a'
or 'ab'
can only be
written. If the file exists, its contents are preserved. All output
is appended to the end of file.
'ak'
is a write-only file suitable
for keyed access. Records can be inserted, but not retrieved, replaced,
or deleted. (Records can be inserted at any point in the file, not just
at the end.) The file does not have to be loaded in advance.
'a+'
or 'a+b'
can be both
read and written. If the file exists, its contents are preserved.
Whenever an output request is made, the file is positioned to the end
of file first; however, reading may be performed at any file position.
The file is initially positioned to the start of the file.
'a+k'
can be read and/or written
using keyed access. Records can be retrieved or inserted, but not
replaced or deleted. (Records can be inserted at any point in the file,
not just at the end.) The file does not have to be loaded in advance.
Note:
For compatibility with some PC C libraries, certain variant forms
of the open mode parameter are accepted. The order of the '+'
and the 'b'
may be reversed, and an 'a'
may appear in
place of the 'b'
to request that the file be accessed as text.
UNIX style I/O open modes When you open a file using
UNIX style I/O, the open mode is an integer, with open mode options
indicated by the presence or absence of particular bit settings. The
open mode is normally specified by ORing symbolic constants that
specify the options required. For instance, the specification
O_RDONLY|O_BINARY
is used for a read-only file to be accessed as
a binary stream. The symbolic constants listed here are all defined in
the header file <fcntl.h>
.
The following open mode options are supported by UNIX style I/O:
O_RDONLY
O_WRONLY
or O_RDWR
, O_RDONLY
is assumed.
O_WRONLY
O_RDWR
O_APPEND
O_CREAT
O_CREAT
is omitted, an attempt
to open a file that does not exist fails.
O_TRUNC
O_EXCL
O_CREAT
is also set. It excludes the use
of an already existing file.
O_NONBLOCK
O_NOCTTY
O_BINARY
O_TEXT
is not specified, O_BINARY
is assumed. (The synonym
O_RAW
is supported for compatibility with other compilers.)
O_TEXT
Note: UNIX I/O does not support keyed streams.
Table 3.3 defines equivalent forms for standard I/O and UNIX style I/O open modes. Some UNIX style I/O open modes have no standard I/O equivalents.
Table 3.3 Standard I/O and UNIX Style I/O Open Modes
Standard form UNIX style form
'r' O_RDONLY | O_TEXT 'rb' O_RDONLY 'r+' O_RDWR | O_TEXT 'r+b' O_RDWR 'w' O_WRONLY | O_CREAT | O_TRUNC | O_TEXT 'wb' O_WRONLY | O_CREAT | O_TRUNC 'w+' O_RDWR | O_CREAT | O_TRUNC | O_TEXT 'w+b' O_RDWR | O_CREAT | O_TRUNC 'a' O_WRONLY | O_APPEND | O_CREAT | O_TEXT 'ab' O_WRONLY | O_APPEND | O_CREAT 'a+' O_RDWR | O_APPEND | O_CREAT | O_TEXT 'a+b' O_RDWR | O_APPEND | O_CREAT
afopen
or afreopen
to open a file, you can
specify the library access method to be used. If you use some other
open routine, or specify the null string as the access method name,
the library selects the most appropriate access method for you. If
you specify an access method that is incompatible with the attributes
of the file being opened, the open fails, and a diagnostic message is
produced. Six possible access method specifications are available:
""
) access method name allows the library to select an
access method.
"term"
access method applies only to terminal files.
"seq"
access method is primarily oriented towards sequential
access. ("seq"
may also be specified for terminal files, in which
case, the "term"
access method is automatically substituted.)
"rel"
access method is primarily oriented toward access by
relative character number. The "rel"
access method can be used only
when the open mode specifies binary access. Additionally, the
external file must have appropriate attributes, as discussed in
370 Perspectives on SAS/C Library I/O .
"kvs"
access method provides keyed access to VSAM files.
"fd"
access method provides access to OpenEdition hierarchical
file system files.
When no specific access method is requested by the program, the library selects an access method as follows:
"term"
for a TSO or CMS terminal file
"kvs"
if the open mode specifies keyed access
"fd"
for a hierachical file system file
"rel"
if the open mode includes binary access and the file has
suitable attributes
"seq"
otherwise.
afopen
, afreopen
, or aopen
to open a
file, you can optionally specify one or more access method parameters
(or amparms). These are system-dependent options that supply
information about how the file will be processed or allocated.
The amparms are specified as character strings containing one or more
specifications of the form
, separated by
commas (for example, amparm=value
"recfm=v,reclen=100"
).
You can specify the amparms in any order and in uppercase or lowercase letters.
(However, the case of the value for the eof
and prompt
amparms is significant.)
There are two sorts of amparms: those that describe how the file will
be processed and those that specify how an MVS file will be created
when the filename is specified in dsn
or tso
style. All
amparms are accepted under both MVS and CMS, but their exact
interpretation and their defaults differ from system to system, as
described in the following section. Inapplicable amparms are ignored
rather than rejected whenever reasonable.
The function descriptions for afopen
, afreopen
, and
aopen
provide examples of typical amparm usage.
File processing amparms The file processing amparms may be classified into the following four categories:
File Characteristics
recfm=f/v/u
reclen=nnn|x
blksize=nnn
keylen=nnn
keyoff=nnn
org=value
File Usage
print=yes|no
page=nnn
pad=no|null|blank
trunc=yes|no
grow=yes|no
order=seq|random
commit=yes|no
dirsrch=value
Terminal Options
eof=string
prompt=string
VSAM Performance Options
bufnd=nnn
bufni=nnn
bufsp=nnn
bufsize=nnn
bufmax=n
eof
and
prompt
amparms. See VSAM-related amparms for
a discussion of the VSAM Performance amparms.
The default amparms vary greatly between MVS and CMS, so they are described separately for each system.
File characteristics amparms The recfm
,
reclen
, blksize
, keylen
, keyoff
, and
org
keywords specify the program's expectations
for record format, maximum record length, block size, key length, key
offset, and file organization. If the file is not compatible with
the program's recfm
, reclen
, or blksize
specifications, it is still opened, but a warning message is directed
to the standard error file. If the file is not compatible with the
program's keylen
, keyoff
, or org
specifications,
a diagnostic message is produced, and the open fails.
If the file is being opened for output and the previous file contents are discarded, the file will, if possible, be redefined to match the program's specifications, even if these are incompatible with the previous file attributes. This is not done if any of the file's contents are to be preserved, because changing the file characteristics may make this data unreadable. (One effect of this is that the characteristics of an MVS partitioned data set are never changed, because even if one member is completely rewritten, other members continue to exist.)
The effects of these amparms are sometimes different from similar specifications on a DD statement, a TSO ALLOCATE command, or a CMS FILEDEF. JCL or command specifications always override any previously established file characteristics, but amparms override only if the library can determine that this is safe.
Details of the file characteristics amparms include the following:
recfm
amparm defines the file's expected record format.
recfm=f
indicates fixed length records; recfm=v
and
recfm=u
indicate varying length records. Under MVS,
recfm=v
and recfm=u
request the DCB attributes RECFM=V and
RECFM=U, respectively. Under CMS, the two are equivalent, except when
a filemode 4 or OS data set is processed.
VSAM files are always treated by the library as RECFM V, because they are never restricted by the system to a single record length.
The recfm
amparm must be specified as exactly f
,
v
, or u
. The inclusion of other characters valid in a JCL
specification (for example, recfm=vba
) is not permitted.
reclen
amparm defines the maximum length record the program
expects to read or write. The specification reclen=x
(which is
not permitted with recfm
specifications other than v
)
indicates that there is no maximum record length.
Under MVS, the value of reclen
might not be the same as the
LRECL of the data set being opened. For RECFM=V data sets, the LRECL
includes 4 bytes of control information, but the reclen
value
contains only the length of the data portion of a record. This allows
a reclen
specification to have the same meaning under MVS and
CMS, despite the different definitions of LRECL in the two systems.
Under MVS, a reclen=x
output file is created with
RECFM=VBS,LRECL=X, which allows arbitrarily long records. Under CMS,
a reclen=x
output allows records up to 65,535 bytes, which is
the maximum permitted by CMS.
For VSAM ESDS and RRDS files, the value of reclen
must take into
account the four-byte key field maintained by the library at the start
of the records processed by the program. For example, if the
maximum physical record for an ESDS data set is 400 bytes, then you should
specify reclen=404
in the amparms.
blksize
amparm specifies the maximum block size for the
file as defined by the operating system. Under MVS and CMS for
filemode 4 files, this is equivalent to the DCB BLKSIZE parameter.
(Thus, for files with record format V, the V-format control bytes are
included in the blksize
value.)
For an OpenEdition HFS file, the blksize
amparm controls the
size of the buffer used by the library to access the file. For these
files, this is the only effect of specifying blksize
.
If a CMS disk file is opened for read-only with the "seq"
access
method and RECFM=F, the blksize
amparm specifies the library's
internal buffer size. If the buffer size is larger than the LRECL of
the file, each input operation performed by the library reads as many
records as will fit into the buffer.
When the "rel"
access method is used to open CMS files, the library
transfers data in the units specified. (For example, if you specify
blksize=10000
, the library reads or writes data 10,000
characters at a time.) Under either MVS or CMS, a large blksize
specification improves performance at the cost of additional memory for
buffers.
The blksize
amparm under MVS is also used during allocation of
a new data set specified with a dsn
- or tso
-style
filename.
keylen
amparm specifies the length of the key field for
a file accessed as keyed. You can also specify keylen=0
for a
file that is not accessed as keyed. For ESDS or RRDS files, if
you specify keylen
, the length must be 4. If the specified
length and the actual length do not agree, the open will fail.
If you open a KSDS that does not already exist, you must specify the
keylen
amparm to correctly create the file. If
you access a VSAM file through standard I/O (that is, using text or binary
access), keylen
must either not be specified or be specified
as 0.
keyoff
amparm specifies the offset of the key field in
the record for a file accessed as keyed. If keylen=0
is
specified, any keyoff=
specification is ignored. For ESDS or
RRDS data sets, you must specify the offset as 0. If you open
a VSAM data set that does not already exist and no keyoff
is
specified, then keyoff=0
is assumed.
org
amparm enables the program to specify a requirement
for a particular file organization. For an existing file, the library
validates that the file requested has the correct organization. For a
new file, the library creates the file with the requested organization,
if possible.
The following values are permitted for the org
amparm:
ps
ps
for a file that
is a PDS.
os
po
pds
pdse
ks
es
rr
ls
byte
Certain org
values are treated as equivalents in some systems
to permit programs to be ported from one environment to another.
Notably, the org
values pds
and pdse
are treated
like the value po
under systems not supporting PDSEs, and the
values os
and ps
are treated synonymously under MVS.
print=yes
or print=no
indicates
whether the file is destined to be printed. If you specify print=yes
,
ANSI carriage control characters are written to the first
column of each record of the file to effect page formatting, if the
file format permits this. In your C program, you can write the
'\f'
character to go to a new page and the '\r'
character to perform overprinting.
print=yes
is allowed only for files that are accessed as a text
stream and whose open mode is 'w'
or 'a'
. If these
conditions are satisfied but the file characteristics do not support
page formatting, a warning message is generated, and no page
formatting occurs.
If you specify print=no
, then the '\f'
and
'\r'
characters in output data are treated as normal characters,
even if the file characteristics will permit page formatting to occur.
page= nnn
specifies the maximum number of lines
that will be printed on a page. It is meaningful only for files
opened with print=yes
, or for which print=yes
is the
default. It is ignored if specified for any other file.
pad
specifies how file padding is to be performed.
pad=blank
requests padding with blanks, pad=null
requests padding with null characters, and pad=no
requests that
no padding be performed. If pad=no
is specified, a record that
requires padding is not written and a diagnostic message is generated.
The pad
amparm is meaningful only for files with fixed-length
records. For files accessed as text, pad characters are added as
necessary to each output record and removed from the end of each input
record. For output files accessed as binary, padding only applies to
the last record, and for input files accessed as binary, padding is
never performed.
trunc
specifies whether existing records following the current
file position are to be erased or preserved. trunc=yes
specifies erasure; trunc=no
specifies preservation. If the
trunc
specification cannot be honored, the open fails. The
primary use for this parameter is to indicate a program dependency on
truncation or nontruncation and thereby avoid inappropriate file updates.
You need to use the trunc
amparm only when you use open modes
'r+'
, 'r+b'
, 'w'
, 'w+'
, or 'w+b'
and one of the file positioning functions (fseek
,
rewind
, or fsetpos
) to position before the end of file.
Do not specify the trunc
amparm with UNIX style binary
I/O; UNIX style binary I/O always exhibits trunc=no
behavior.
You can change the length of a record in a file only if it is the last
record, or if trunc=yes
is in effect.
grow=yes
or grow=no
_ controls
whether new data can be added to a file. The default is always
grow=yes
, which permits the addition of new records. The no
specification is only permitted when the open mode is 'r+'
,
'r+b'
, or 'r+k'
, and when trunc=yes
is not specified.
When grow=no
is specified, attempts to add new records to the file
will fail. For some file types, notably MVS PDS members, use of grow=no
can lead to performance improvements. In particular, for PDSE members, the
fseek
and fsetpos
functions are supported if
you specify grow=no
,
but not with grow=yes
.
order=seq
or order=random
specifies whether records
for the file are normally processed in sequential or random order. This is
specified as order=seq
for sequential order, or order=random
for random order. This amparm is meaningful for VSAM files with keyed
access and for CMS shared files; correct specification can lead to
performance improvements. For all other file types, this amparm is
ignored. The default is determined by the access method. For VSAM, the
default is order=random
; for CMS shared files, the default is
selected by CMS.
commit=yes
or commit=no
specifies whether
modifications to the file should be committed when the file is closed. The
no
specification for the commit
amparm is supported only for CMS
Shared File System files, and this specification is rejected for any
other file type. When commit=no
is in effect, you must call the
afflush
function to commit updates to a shared file. If you
close without calling afflush
, the updates are rolled back, and
the file is left unchanged.
When commit=no
is specified in a call to aopen
(using
UNIX style I/O), the behavior is slightly different. See the
fsync
function description for a discussion of this case.
dirsrch
amparm opens a CMS Shared File System
directory to specify the information to be retrieved from the
directory.
File characteristics For input files, or output files in
which some or all of a file's previous contents are preserved, the
file characteristics amparms serve as advice to the library regarding
the file characteristics expected. If the actual file does not match
the program's assumptions, a warning message is generated. In some
cases, no warning is generated, even though the file characteristics
are not exactly what the program specified. For instance, if a
program specifies amparms of "recfm=v,reclen=80"
and opens an
input file with LRECL 40, no diagnostic is generated, because all
records of the input file are consistent with the program's assumption
of input records with a maximum length of 80 bytes.
To determine the characteristics of a file, the library merges information from the amparms, control language specifications, and the data set label. Unlike amparms information, control language specifications always override the physical file characteristics recorded in the label.
For each of these amparms, processing is as follows:
recfm
recfm=f
, the program expects records of equal
length, and a warning is generated if the file does not have
fixed-length records (blocked or unblocked).
If recfm=v
or recfm=u
is specified for a read-only file,
no diagnostic is ever generated. For a write-only or update file, a
warning is generated if the MVS RECFM does not match the amparm.
Note: VSAM linear and RRDS files are always considered to have RECFM F, and other VSAM files and OpenEdition HFS files are considered to have RECFM V.
reclen
reclen= nnn
for a read-only file, a warning
is generated if the file's record size is larger, or if it is not
equal and the record format is fixed. If reclen=x
is specified
for a read-only file, a diagnostic is never generated, except when the
record format is fixed. Note that under MVS, the program's
reclen
specification is compared to the LRECL - 4 for a V-format
file, not to the LRECL itself. (Additionally, for a file with
carriage control characters, the control character is not counted.)
If you specify reclen=
for a write-only or update
file, a warning is generated if the file's record size is not the same
as the nnn
reclen
specification. If you specify reclen=x
,
a warning is generated unless the file has RECFM=VBS or RECFM=VS and
LRECL=X.
VSAM linear data sets are always considered to have reclen=4096
.
blksize
blksize= nnn
, a warning is generated only
if the actual blksize is greater than that specified.
When a write-only or update file is opened and none of the file's previous contents are preserved, the file's characteristics are changed to correspond to the program's amparms specifications. The details of this process are outlined here:
recfm
specifications of f
, v
, and u
become
MVS RECFM's of FB, VB, and U, respectively. However, if you select the "rel"
access method, RECFM FBS is chosen. If the reclen
is x
or the blksize
is less than the reclen
with
recfm=v
, MVS RECFM VBS is requested. Finally, if
you also specify print=yes
,
ANSI carriage control characters (RECFM=A) are added.
reclen=x
specification requests use of LRECL=X.
reclen= nnn
requests a LRECL of nnn
, unless the
record format includes V, in which case, it requests nnn
+4.
blksize= nnn
specification requests an MVS BLKSIZE of
nnn
. If the requested BLKSIZE is not compatible with the
chosen RECFM and LRECL, the BLKSIZE is rounded, if possible.
When a file is opened and neither the file nor any amparms fully specify the file characteristics, the following rules apply:
"rel"
access method is in use, RECFM=F, FS, or FBS is required.
The default record length is 1, and the default blksize is 4080.
"seq"
access method, choices are made based on device type and
the presence or absence of a print
specification, as shown in
Table 3.4.
Table 3.4 MVS Default File Characteristics Amparms
Device Type recfm reclen blksize
Card punch f 80 80 Printer/SYSOUT/DUMMY v 132 141 Other (print=yes) v 132 6144 Other (print=no) v 255 6144
File usage The amparm print
has two uses: it
specifies whether the corresponding file includes ANSI carriage
control characters, and it specifies whether the C library should
process the control characters '\r'
and '\f'
to effect
page formatting. If print=no
is specified, then '\r'
and '\f'
are simply treated as data characters, even if the
file can support page formatting. If you specify print=yes
,
then the library attempts to perform page formatting. However, if the
associated file does not have the correct attributes, '\r'
and
'\f'
are treated as new lines, and a warning message is
generated when the file is opened. If neither print=no
nor
print=yes
is specified, the library chooses a default based on
the attributes of the external file. However, print=yes
is
supported only for a file accessed as a text stream.
Under MVS, a file is considered to be suitable for page formatting if it has the following characteristics:
reclen
specification made by the
program.
The page
amparm, which specifies the number of lines to be
printed on each page of a print=yes
file, does not have a
default. That is, if page
is not specified, page ejects will
occur only when a '\f'
is written to the file.
Note:
The print
and page
amparms are ignored when opening files
in the OpenEdition hierarchical file system. Control characters are
always written to an HFS file, regardless of whether
you specified print
.
The pad
amparm specifies whether padding of records will take
place, and, if so, whether a blank or a null character ('\0'
) will be
used as the pad character. The default depends on the library access
method and the open mode, as follows:
"rel"
, the default is pad=null
.
"seq"
and the file is accessed as text, the
default is pad=blank
.
"seq"
and the file is accessed as binary, the
default is pad=no
; that is, padding is not performed.
The trunc
amparm indicates to the library whether the program
requires that output before the end of file erase the following records
or leave them unchanged. Under MVS, whether existing data are
preserved in this situation depends only on file type and access
method. If trunc
is omitted, the value corresponding to the
file's actual behavior is used; if a conflicting trunc
specification is made, the file fails to open. If a file is processed
by the "rel"
access method, is a VSAM file, or is in the OpenEdition
HFS, only trunc=no
is supported. For all other MVS file types,
only trunc=yes
is supported.
The grow
amparm indicates to the library whether new data can
be added to a file opened for "r"
or "r+"
. The specification
grow=no
informs the library that the program will only replace
existing records of a file, rather than adding any data to the end. When
you specify grow=no
for a file processed with BSAM, the library can
open it for UPDAT rather than OUTIN. This allows the library to support use
of the fseek
or fsetpos
functions on a PDSE member.
grow=no
implies trunc=no
.
File creation amparms These amparms are used under MVS
with filenames specified in dsn
or tso
style when the
file does not exist and must be created. These amparms are accepted
under CMS, and for ddn
-style names or existing files under MVS,
but in these cases they are ignored.
Note: VSAM files can be created directly by a C program only in MVS, and only if the Storage Management Subsystem (SMS) is active. On CMS, or if SMS is not available, VSAM files must be created by the Access Method Services (AMS) utility before they can be accessed by a C program.
The file creation amparms are as follows:
alcunit=block|trk|cyl|rec|krec|mrec
space= nnn
extend= nnn
dir= nnn
vol=volser
unit=name
rlse=yes|no
dataclas=name
storclas=name
mgmtclas=name
alcunit
amparm defines how the values specified for
space
and extend
are to be interpreted.
If you specify alcunit=block
, the space
and extend
values
are interpreted as the number of physical blocks to allocate. (If
you specify alcunit=block
, you must also specify the
blksize
amparm to define the size of the blocks.) Similarly,
alcunit=trk
specifies that the space
and extend
values
are to be interpreted as the number of disk tracks, and
alcunit=cyl
specifies that they are to be interpreted as the number
of disk cylinders.
If you use the rec
specification, the space
and
extend
amparms
are expressed in numbers of records. The krec
specification
expresses these values in units of 1024 records, and the mrec
specification expresses these values in units of 1,048,576 records.
If you use one of these specifications,
you must also specify the reclen
amparm
to define the record length. Use of these options is
recommended only when the Storage Management Subsystem of MVS is
installed and active. If SMS is not active and either rec
,
krec
, or mrec
is specified for the alcunit
amparm, the library attempts to convert the specification to an
equivalent specification in blocks, tracks, or cylinders. However,
the conversion is at best approximate, and may allocate substantially
more or less space than actually required.
space
amparm specifies the amount of disk space to be
initially allocated to the file, in the units specified by
alcunit
.
For instance, the amparm string
"alcunit=block,blksize=5000,space=100"
requests enough space to hold
100 blocks of 5000 characters each. If there is not enough disk space
available, the open fails.
extend
amparm specifies the amount of additional disk space
allocated to a file if the existing space runs out during processing.
A file can be extended up to 15 times, after which any attempt to add
more data to the file fails. As with space
, the extend
value is interpreted in the units specified by alcunit
.
The amparms alcunit
, space
, and extend
must be
specified together. Specifying space
without alcunit
or
extend
without space
will cause the open to fail without
creating a file.
The amparm specification "alcunit=alc,space=spc,extend=ext"
is
equivalent to the JCL specification SPACE=(alc,(spc,ext)), where an
"alc" of "block" is replaced by the value of the blksize
amparm, and where an "alc" of "rec", "krec" or "mrec" is replaced
by an appropriate AVGREC JCL parameter.
When a nonexisting data set specified in dsn
or tso
style is opened and no space specification is supplied by the program,
a default amount of space is allocated. The standard default
allocation is that specified by "alcunit=block,blksize=1000
,
space=10,extend=3"
.
dir
amparm specifies the number of directory blocks to
allocate when a partitioned data set is created. (See
MVS/DFP Using Data Sets
for more information on PDS directories.)
The dir
amparm applies only to partitioned data sets. If
dir
is specified in the amparms but the filename does not include a
member name, a member name of TEMPNAME is assumed. If no dir
amparm is specified and the filename does not include a member name, a
sequential data set is created. If a member name is specified, a
default dir
value of 5 is assumed.
You do not have to specify the dir
amparm if you request creation
of a PDSE using the org=pdse
amparm, since pre-allocation of
directory blocks is not required.
vol
amparm specifies the volume serial on which a new data
set will be created. If no vol
amparm is specified for a new
data set, the system is allowed to select the volume on which to
create the data set.
unit
amparm specifies a unit name (such as SYSDA) to use
when allocating a new file. This has the same effect as the JCL UNIT
keyword. See the IBM publication MVS/XA ESA JCL Reference,
for more information. If unit
is not
specified, the normal procedures at your site for unit selection are
used. (For instance, for TSO users, the default unit name is defined
as part of the user profile.)
rlse
specifies whether unused file space should be released
when the file is closed. This option only has an effect when the file
is created at the time it is opened. The default is rlse=no
.
Use of rlse=yes
with a file that is opened and closed
repeatedly may cause the maximum file size to be smaller than if
rlse=no
had been specified, due to repeated release of temporarily
unused space. You should not specify the rlse
amparm for VSAM
files.
dataclas
specifies the data class for a new file. This amparm
is ignored if SMS is not active, or if the file already exists. Your
site may choose to ignore this specification.
storclas
specifies the storage class for a new file. This
amparm is ignored if SMS is not active, or if the file already exists.
Your site may choose to ignore this specification.
mgmtclas
specifies the management class for a new file. This
amparm is ignored if SMS is not active or if the file already exists.
Your site may choose to ignore this specification.
See the IBM publication MVS/DFP Storage Administration Reference for further information on SMS concepts such as data class and storage class.
File characteristics For input files, or output files in
which some or all of a file's previous contents are preserved, the
file characteristics amparms serve as advice to the library about the
file characteristics expected. If the actual file does not match the
program's assumptions, a warning message is generated. To determine
the characteristics of a file, the library tries to merge information
from the amparms, the FILEDEF options (for a ddn
-style
filename), and from an existing file with the same fileid.
The processing for each of the file characteristics amparms is described here. Unless otherwise specified, the description is for CMS disk files.
recfm
recfm=f
, the program expects records of equal length. If
the file is not a RECFM F file, a warning message is generated.
Similarly, if recfm=v
, the program expects records of varying
length. If the file is not a RECFM V file and the file is opened for
write-only or for update, a warning message is generated.
recfm=u
is treated as if it were recfm=v
.
reclen
reclen
specifies the
length of the records. If the record length specified by reclen
does not match the LRECL of the file, a warning message is generated.
reclen=x
cannot be used with fixed format files.
If the file has varying length records, reclen
specifies the
maximum length of the records. If the LRECL of the file exceeds that
specified by reclen
, a warning message is generated.
reclen=x
implies that the records may be of any length up to 65,535.
blksize
blksize
amparm is used with the "rel"
access method to
specify the internal buffer size used by the library, which in turn
specifies the number of records read or written by the library in each
I/O operation. The blksize
for the file should be a multiple
of the file's logical record length. If it is not, it is rounded to
the next higher multiple.
For files with fixed-length records opened for read only, blksize
can also be used with the "seq"
access method. In this case,
blksize
specifies the library's internal buffer size.
If the buffer size is larger than the LRECL of the file, each input
operation performed by the library reads as many records as can fit
into the buffer. For example, if the file has 80-character records,
specifying blksize=4000
causes the library to read 50 records
at each input operation.
When an existing write-only or update file is opened, and none of the file's previous contents are preserved, the old file is erased and a new file is created. The characteristics of the new file are those specified by the amparms.
recfm
recfm=f
and recfm=v
cause the file to be created as
RECFM F or RECFM V, respectively. Again, recfm=u
is treated
as if it were recfm=v
.
reclen
recfm=f
) logical record
length for the file. reclen=x
indicates that the records may
be of any length up to CMS's maximum of 65,535.
blksize
If the file characteristics are not completely described by the
amparms, the FILEDEF options (when the ddn
-style filename is
used), or the file, the following defaults apply:
"rel"
access method is in use, the amparms recfm=f
,
reclen=1
, blksize=4080
are assumed.
"seq"
access method, choices are based on the virtual device
type, filetype, and the presence of the print
amparm.
print=yes
specified, the defaults are
recfm=v
and reclen=132
.
recfm=f
and reclen=80
.
recfm
amparm is not specified, the
default is "v"
. If the recfm
is "f"
, the default
reclen
is 80; otherwise, the default is reclen=x
. For
files in OS-format or for tape files, amparms are processed as
described in Amparms - MVS details . The single exception is that
the default blksize
for tape files is 3600, rather than 6144.
File usage The amparm print
has two uses: it
specifies whether the corresponding file includes ANSI carriage
control characters, and it specifies whether the C library should
process the control characters '\r'
and '\f'
to effect
page formatting. If print=no
is specified, then '\r'
and '\f'
are simply treated as data characters, even if the
file can support page formatting. If you specify print=yes
,
then the library attempts to perform page formatting, but if the
associated file does not have the correct attributes, '\r'
and
'\f'
are treated as new lines. (A warning message is
generated when the file is opened in this case.) If neither
print=no
nor print=yes
is specified, the library chooses a
default based on the attributes of the external file. However,
print=yes
is supported only for a file accessed as a text stream.
Under CMS, any disk file may be used with page formatting. If the filetype of the file is LISTING or the file is written to the virtual printer, the file is assumed to require ANSI control characters in the first byte of each record. (If a disk file has control characters in byte 1 and does not have a filetype of LISTING, the CMS command PRINT prints the file incorrectly unless the CC option is used.)
The page
amparm, which specifies the number of lines to be
printed on each page of a print=yes
file, does not have a
default. That is, if you do not specify page
, page ejects will
occur only when a '\f'
is written to the file.
The pad
amparm specifies whether padding of records will take
place, and, if so, whether a blank or a null character ('\0'
) will be
used as the pad character. The default depends on the library access
method and the open mode, as follows:
"rel"
, the default is pad=null
.
"seq"
and the file is accessed as text, the
default is pad=blank
.
"seq"
and the file is accessed as binary, the
default is pad=no
; that is, padding is not performed.
The trunc
amparm indicates to the library whether the program
requires that output before the end of file erase following data or
leave them unchanged. CMS disk files support both trunc=yes
and trunc=no
. By default, trunc=no
is assumed; that is,
data are not erased following a modified record. Shared file system
files support only trunc=no
. All other types of files support
only trunc=yes
, except for VSAM, which supports only trunc=no
.
If a program's trunc
specification is not supported for the file
being opened, the open fails, and a diagnostic message is generated.
The details of file positioning depend heavily on the I/O package and library access method used, the stream type (text or binary), and the file organization and attributes. The following discussion is organized primarily by I/O package.
lseek
function, which
can be used to seek to an arbitrary location in the file. However,
when UNIX style I/O is used to access a file as text, the seek
address is interpreted in an implementation-specific way, as when the
fseek
function is used. This means that, for a text stream,
you should use lseek
only to seek to the beginning or end of a
file, or to a position returned by a previous call to lseek
.
The lseek
function accepts three arguments: a file number, an
offset value, and a symbolic value indicating the starting point for
positioning (called the seek type). The seek type is interpreted as
follows:
SEEK_SET
, the offset is interpreted as an
offset in bytes from the start of the file.
SEEK_CUR
, the offset is interpreted as the
offset in bytes from the current position in the file.
SEEK_END
, the offset is interpreted as the
offset in bytes from the end of file.
If the seek type is SEEK_CUR
or SEEK_END
, the offset
value may be either positive or negative. lseek
can be used
with a seek type of SEEK_SET
and an offset of 0 to position to
the start of a file, and with a seek type of SEEK_END
and an
offset of 0 to position to the end of a file.
Positioning beyond the end of a binary file with lseek
is fully
supported. Note that positioning beyond the end of a file does not in
itself change the length of the file; you must write one or more
characters to do this. When you write data to a position beyond the
end of file, any unwritten positions between the old end of file and
current position are filled with null characters ('\0'
).
The lseek
function returns the current file position, expressed
as the number of bytes from the start of the file. It is frequently
convenient to call lseek
with a seek type of SEEK_CUR
and an
offset of 0 to obtain the current file position without changing it.
Recall that, except for files suitable for "rel"
access and
OpenEdition HFS files, using UNIX style I/O is relatively inefficient.
See Choosing I/O Techniques and File Organization for more information on the advantages and
disadvantages of using UNIX style I/O.
fgetpos
and fsetpos
functions
to obtain or modify the current file position with either a text or a
binary stream. Both fsetpos
and fgetpos
accept two
arguments: a pointer to a FILE
object and a pointer to an
object of type fpos_t
. For fsetpos
, the fpos_t
object specifies the new file position, and for fgetpos
, the
current file position is stored in this object. The exact definition
of the fpos_t
type is not specified by the ISO/ANSI C standard and,
if you intend your program to be portable, you should make no
assumptions about it. However, an understanding of its implementation
by the SAS/C library can be useful for debugging or for writing
nonportable applications.
The library defines fpos_t
using the following typedef
:
typedef struct { unsigned long _recaddr; /* hardware "block" address */ long _offset; /* byte offset within block */ } fpos_t;The first element of the structure (
_recaddr
) contains the
address of the current block or record. The exact format of this
value is system- and filetype-dependent. The second element of the
structure (_offset
) contains the offset of the current
character from the start of the record or block addressed by
_recaddr
. In some cases, this offset may include space for
control characters.
A more precise definition of these fields for commonly used file types follows.
"seq"
access method, the
_recaddr
is the current record number, and the _offset
value
is the offset of the current character from the start of the record.
Record numbering starts at 1, not 0.
_recaddr
is the RBA (relative byte
address) of the current record, and the _offset
value is the
offset of the current character from the start of the record.
"seq"
access method, the
_recaddr
is the TTR of the block preceding the block containing the
current record. If the file is a PDS member, the TTR is computed
relative to the start of the member, not the start of the PDS. The
_offset
value is the offset of the current character from the
start of the block containing the current record. In computing the
offset, each record is treated as if it were terminated with a single
new-line character, even for a file accessed as a binary stream. This
technique allows the library to easily distinguish the end of a record
from the start of the next record.
"rel"
access method and OpenEdition HFS
files, the exact values in _recaddr
and _offset
depend
on the file attributes and on previous processing. You should use
fseek
and ftell
rather than fsetpos
and
fgetpos
for these files if you need to construct file positions
manually.
fsetpos
and fgetpos
are implemented to be natural and
efficient, and not to circumvent limitations or peculiarities of the
operating systems. For this reason, you should be aware of the
following:
fsetpos
and fgetpos
may fail.
These cases are outlined in Tables 3.5 and 3.6. When fsetpos
or
fgetpos
cannot be supported, a diagnostic message is generated, and
the return value from the function indicates that an error occurred.
A proper call to fsetpos
will never indicate success when the
requested operation is not supported by the file.
fgetpos
never
returns a file position of this sort, this situation can arise only if
your program manufactures its own fpos_t
values. Seeking past
the end of file is supported for files processed by the "rel"
access method. For these files, writing a character beyond the end of
file causes intervening positions to contain hexadecimal 0s.
_recaddr
value is frequently
undetected, or causes an error only when the file is next read or
written.
trunc
amparm is specified when the file is opened.
fpos_t
values. In some cases,
especially for files with spanned records, several different values
may identify the same location in the file.
fseek
and ftell
functions to obtain or modify the
current file position. Because fsetpos
and fgetpos
are
relatively new additions to the standard C language, fseek
and
ftell
are more portable. However, they are also more restricted
in their use. Full fseek
and ftell
functionality is
available only when you use the "rel"
access method, when a file
is accessed as a text stream, or when the file is in the OpenEdition
hierarchical file system. For files processed with the "rel"
access
method and for HFS files, fseek
and ftell
function
exactly like lseek
does for UNIX style files.
The fseek
function accepts three arguments: a pointer to a
FILE
object, an offset value, and a symbolic value indicating
the starting point for positioning (called the seek type). The offset
value is a long
integer, whose meaning depends on whether the
file is accessed as text or binary. For binary access, the offset
value is a number of bytes. For text access, the offset value is an
encoded file position whose interpretation is unspecified. The seek
type is one of the values SEEK_SET
, SEEK_CUR
, or
SEEK_END
, indicating positioning relative to the start of file,
the current position, or the end of file, respectively.
When you access a file as binary, the fseek
offset value is
simply interpreted as an offset from the point specified by the seek
type. For instance, fseek(f, -50L, SEEK_CUR)
requests
positioning 50 characters before the current character.
Note:
Because the fseek
offset value has type signed long
, only
files whose size is less than 2**31 bytes can be supported in a
portable fashion. However, for files accessed using the "rel"
access method, or stored in the OpenEdition HFS, the offset value is
interpreted as unsigned long
, thus allowing the use of files
whose size is less than 2**32-1.
When you access a file as text, only certain combinations of offset
and seek type are meaningful. When the seek type is SEEK_CUR
or SEEK_END
, only an offset value of 0 is meaningful,
requesting no change in positioning or positioning to the end of file,
respectively. When the seek type is SEEK_SET
, any valid file
position previously returned by ftell
is accepted as an offset.
Additionally, you can use an offset of 0 with SEEK_SET
to
reposition to the start of the file.
The ftell
function accepts one argument, a pointer to a
FILE
object, and returns a long
integer defining the
current file position. For a file accessed as binary, the returned file
position is the number of bytes from the start of the file. For a
file accessed as text, the returned file position is in an internal
format.
Note:
For a text stream, ftell
is the only safe mechanism for obtaining
a file position for later use by fseek
; that is, you cannot
construct meaningful file positions in another way.
ftell
computes the encoded file position for a text stream by
first calling fgetpos
to obtain the file position in
fpos_t
format. (Thus, if fgetpos
is not usable with a file,
neither is ftell
.) Then, initial portions of the _recaddr
and _offset
fields of the result are combined in a
manner that depends on the file organization. Because the size of an
fpos_t
value is 8 bytes and the size of a long
integer
is only 4 bytes, information is lost if either the _recaddr
value or the _offset
value is too large. The library detects
this loss of information and returns an error indication, rather than
an incorrect file position. For specific file types, the conditions
under which a file position cannot be successfully returned are listed
here:
ftell
returns
an error only when the actual file position is outside the limits.
When used with a binary stream, full fseek
functionality is
restricted to the "rel"
access method, but note that fseek
with a 0 offset value is usually supported. This means that
you can use fseek
with almost any file to rewind, position to end of file,
or switch between reading and writing. The exceptions are noted in
Tables 3.5 and 3.6.
Table 3.5 MVS Files with Restricted Positioning
File Type Restrictions
terminal positioning not allowed card reader positioning not allowed OpenEdition pipe positioning not allowed DD */DATA only fseek with a 0 offset supported printer/card punch/SYSOUT rewind and seek to the end of file accepted but ignored keyed VSAM (KSDS) only fseek with a 0 offset supported PDS member seek to the end of file not supported; switch between reading and writing only supported at the start of file unless grow=no PDSE member seek to the end-of-file not supported; seeking other than rewind only allowed if read-only or grow=no RECFM=FBS (accessed as seek to the end of file text) not supported multivolume disk or tape only rewind supported if file not opened for append; only seek to the end of file supported if opened for append unlabeled tape with only seek to the end of DISP=MOD file supported concatenated sequential only fseek with a 0 offset files supported
Table 3.6 CMS Files with Restricted Positioning
File Type Restrictions
terminal positioning not allowed reader/printer/punch rewind and seek to the end of file accepted but ignored keyed VSAM (KSDS) only fseek with a 0 offset supported MVS PDS member positioning not allowed with %MACLIB or %TXTLIB filename used
Note:
The warnings given in the previous section for use of fsetpos
are equally applicable to fseek
.
Note: The following considerations apply when you read from or write to the TSO or CMS terminal. They do not necessarily apply when you read or write from an OpenEdition terminal under the OpenEdition shell. The behavior of an OpenEdition terminal is defined by the POSIX standards. See the POSIX 1003.1 standard for further information.
'r'
,
'w'
, or 'a'
. Open for append and write-only are treated
identically. If you want to both read from and write to the terminal,
you must use two files.
"EOF"
(uppercase letters required) is normally interpreted as
the end of file. (This string may be changed by specifying the eof
amparm when the file is opened.) When a terminal file is accessed as
binary, a null input line will be treated as end of file.
"term"
access method for terminal I/O.
fflush
function to force an output buffer to be written. Programs that use
this technique are portable, because this works with almost any C
library implementation.
stdin
and stdout
).
This implementation allows many simple programs to run as intended
without solving the general problem.
Another situation that varies from one implementation to another, depending on the buffering strategy, is the effect of writing characters to several terminal files at the same time. In implementations that do not buffer terminal I/O, all the output characters are transmitted in the order that they are written. In an implementation that performs buffering, the output probably consists of complete lines of output, each line associated with a particular file. With the SAS/C library I/O functions, the buffer for one terminal output file is flushed when a character is written to another. This means that characters are transmitted in the same order as they are written and that characters written to two different files do not appear in the same output line.
scanf
or a similar function to read input from the
terminal, it can be difficult to write prompts at all points where
terminal input is required. For example, the following call reads two
integers from the standard input stream (normally the terminal):
scanf("%d %d", &i, &j)If only one integer is entered,
scanf
issues another read to
obtain the second integer without returning to the program. This
means that the program is unable to issue a prompt or message to tell
you that more input is required.
When you open a terminal input file, the library allows you to specify
a prompt that will be written by the library immediately before a read
is issued to the terminal. This allows each input request to be
automatically preceded by a prompt. You can also have more than one
terminal input file, each with a different prompt, allowing you to
easily distinguish one file from another. This feature is requested
with an amparm when you use afopen
or aopen
to open the
file.
The situation is similar for input and output to the terminal. Usually, the terminal is accessed as a text stream. In this mode, the new-line character separates lines, and a form feed issues several blank lines to simulate the effect of a form feed on a printer. Other control characters are removed from input and output. Both TSO and CMS are sensitive to the data sent to the terminal, and incorrect use of control characters can cause the user to be disconnected or logged off. Thus, the removal of control characters is a safety measure that prevents unpleasant consequences when uninitialized data are sent to the terminal.
However, some applications need the ability to send control characters to the terminal. This is supported by accessing the terminal as a binary stream. When a binary stream is used, output data are sent to the terminal without modification, and input data are only minimally edited. The new-line character still separates lines of output, because both TSO and CMS support this use of the new-line character. Note that even though the SAS/C library does not modify data transmitted to and from the terminal when binary access is used, the data can be modified by system software, including the VM control program, VTAM, and communication controller software. Also recall that incorrect data can cause disconnection or other errors, so use this technique with caution.
You may have several terminal output files open simultaneously. In this case, lines written to the various files are interspersed, as they would be if the program were running interactively. Emulation of terminal input under MVS-batch is not supported.
afopen
or aopen
to open a terminal file,
you can specify the following amparms in addition to those discussed
earlier in Opening Files :
eof=string
prompt=string
eof
amparm enables you to specify the string that is
interpreted as end-of-file if entered from the terminal. It applies
only when the terminal is accessed as a text stream; when a binary
stream is used, a null input line is always the end-of-file indicator,
and the amparm is ignored.
Use of uppercase and lowercase letters is significant. For example,
if eof=END
is specified, an input line of end
will
not be interpreted as the end of file. The default specification for
eof
is eof=EOF
; that is, the input line EOF
will be interpreted as the end of file.
prompt
amparm enables you to specify a string that is sent
to the terminal before data are read from the terminal with this
stream.Use of uppercase and lowercase letters is significant. If the
prompt string ends in a new-line ('\n'
) character under MVS, the
cursor is positioned to the line following the prompt; otherwise, the
cursor appears on the same line as the character after the prompt.
Under CMS, the presence or absence of a trailing new-line character in
the prompt is not significant, because the cursor is always positioned
to the first position of the terminal input area.
With one exception, the default value for the prompt
amparm is
"prompt="
; that is, no input prompting occurs. However, when
the library opens the standard input stream (stdin
), a prompt
consisting of the program name followed by a colon is used. See
stdin, stdout, and stderr for information on overriding this default.
*
in ddn
,
dsn
, or tso
style to access the
OpenEdition terminal. When you use this filename, the eof
and prompt
amparms are permitted and honored. These amparms
are ignored when you open the HFS file /dev/tty
. Use of these
amparms under the shell is not recommended for new programs, because
they are not portable, but they can be useful when porting existing MVS
programs.
Note:
When a program running under the shell opens the *
filename, no distinction is made between text and binary access.
The effect of control characters on the display is defined by
OpenEdition.
/u/marie/tools/wrench.c
identifies the file wrench.c
, contained in the directory tools
,
in turn contained in the directory marie
, contained in the directory
u
, which is contained in the root (/) directory. This type of pathname,
beginning with a slash connoting the root directory, is called an
absolute pathname.
A program using a hierarchical file system always has a
current directory defined, either by inheritance from a calling program,
or from using the chdir
function. A pathname without a leading slash
is called a relative pathname. Such pathnames are interpreted
relative to the current directory. For instance, if a program's
current directory is /u/marie
and it attempts to open the
pathname tools/wrench.c
, the file that is actually accessed
is /u/marie/tools/wrench.c
.
Note:
When you call the fopen
or open
function to access an HFS file,
it may be necessary to prefix the pathname with the SAS/C style prefix
hfs:
. See File Naming Conventions for information on when this is
required.
Several different kinds of files exist in the hierarchical file system. Most files are so-called regular files, which are stored on disk (in a special MVS file system data set). The hierarchical file system also contains special files of various sorts, which may not have all the properties of regular files. For instance, some special files do not support seeking, or have different behavior when read or written. Some important examples of special files include
/dev/tty
).
/dev/null
). Output to /dev/null
is
discarded; input from /dev/null
produces end-of-file.
open
, read
, and write
. For HFS
files, UNIX style I/O functions interface directly to the operating system,
bypassing most of the C library's I/O support. This ensures that access to the
Hierarchical File System through SAS/C has the same characteristics as access
when the operating system interfaces are used directly.
When an HFS file is opened using open
, the operating
system returns a small integer representing the file, called the
file descriptor. All other I/O operations, such as reading and
writing, are performed by specifying the file descriptor. File descriptors
have two important properties not applicable to more traditional MVS files:
fcntl
for
information on how several programs sharing a file can cooperate to avoid
interfering with each other.
dict1
could open a file using file descriptor 4,
and then call the program dict2
using the execvp
function without
closing file descriptor 4. When dict2
began execution, file descriptor
4 would still be open, with the same file position as at the time of the
exec
, and dict2
could immediately read or write the file without
having to open it again.
Of course, you can use standard I/O functions rather than the low-level
functions like open
, read
, and write
to access HFS files.
However, program behavior may differ, depending on which set of routines you use.
When you use fopen
to open an HFS file, it calls the OpenEdition open
interface, and then saves the resulting file descriptor in a control block
accessed via the FILE
pointer. Functions such as fread
and
fwrite
read and write data from a buffer area allocated by the
library (or by the user if the setvbuf
function is used), and actually
read from or write to the file descriptor only as necessary to empty or fill
the buffer.
For most programs, the buffering performed by standard I/O results in
a performance gain, because the program does not need to call the
operating system as often. However, for some programs, this can result in
unacceptable behavior. For example, programs that share files usually should
not use standard I/O because output data may be buffered
indefinitely; therefore, updates may not become visible to other
programs using the file for an arbitrary amount of time. Similarly,
if a program needs to receive an open file from a calling program,
it must be aware that only the file descriptor is passed. That is,
a FILE
pointer is local to the program that creates it, and it cannot
be inherited, except under special conditions.
For applications that might need to access a file using both low-level and standard I/O, the POSIX standards define two functions that cross the boundaries:
fdopen
to associate a FILE
pointer with an open
file descriptor. For example, if the program dict2
receives open file
descriptor 4 from its caller, it can use
the following statements to associate the FILE
pointer f
with
file descriptor 4. Thereafter, the program uses standard I/O functions to access the file.
FILE *f; f = fdopen(4, "r+");
fileno
to extract the file descriptor
for an HFS file from the FILE
pointer. This can be useful if
a program using standard I/O has a momentary need for a low-level
I/O feature not supported via standard I/O, such as the ftruncate
function.
When a program is called by exec
, the library automatically uses
fdopen
to associate the standard files stdin
, stdout
,
and stderr
with file descriptors 0, 1, and 2. Thus, these three
files are partial exceptions to the rule stated earlier that FILE
pointers
cannot be inherited across exec
.
posix
compiler option. If so,
then POSIX file-naming rules apply. If no compilation specifies the
posix
option, then traditional SAS/C naming conventions apply.
Using traditional SAS/C rules, a filename consists of a style prefix (one to
four characters, followed
by a colon), followed by the filename proper. The prefix determines how the
rest of the filename is to be interpreted (for example, as a DDname or an
HFS pathname). If there is no style prefix, then a default prefix is assumed.
The default prefix may be defined by the program by initializing the
_style
external variable. If _style
is not initialized,
the default is system-dependent. A filename, with or without an
explicit style prefix, may be further prefixed by the string //
.
If //
precedes a style prefix, the //
is simply ignored. If
//
is present, but there is no style prefix, then the style tso
(in MVS) or cms
(in CMS) is assumed, independent of the _style
definition. When these rules are in effect, you must do one of the following
to access a file in the HFS:
hfs:
or //hfs:
. For example, to
access the file tools/wrench.c
in the current directory, open
hfs:tools/wrench.c
or //hfs:tools/wrench.c
.
_style
external variable to "hfs"
. Then simply
use the pathname to open HFS files. However, you will have to
use a style prefix for other kinds of names, such as DDnames.
The rules above are useful for MVS-oriented programs, or for
programs that must open diverse kinds of files. However, they are often
not the most appropriate rules for portable applications. Notably,
the POSIX.1 standard requires that any pathname not beginning with
//
be interpreted as a hierarchical file system pathname. For
this reason, SAS/C implements alternate conventions to allow the
porting and/or development of applications that conform to the
POSIX.1 standard and are portable to UNIX operating systems.
These alternate rules apply whenever the main load module of a program
contains at least one compilation using the posix
compiler option.
For such programs, the file-naming conventions are as follows:
//
), it is the pathname of an HFS file, even if the name
appears to have a style prefix. For example, the filename
/u/marie/tools/wrench.c
identifies an HFS file with that pathname,
and ddn:sysin
identifies a file with that name in
the current directory.
//
),
it is interpreted exactly as it would be interpreted according to the
traditional SAS/C rules above. That is, the filename
//ddn:sysin
identifies the DDname SYSIN, and the filename
//tools.c(wrench)
identifies the MVS PDS member
userid.TOOLS.C(WRENCH)
, where userid
is the current user's id.
Note:
For a program compiled with the posix
option, the _style
external variable is ignored.
Note:
Because filenames beginning with //
are interpreted in the same
way for applications compiled with the posix
option as for those
compiled without the posix
option, this form should be used by
any functions that need to open files, and which can be used
in programs compiled with or without the posix
option. For example,
to open the HFS file /u/marie/tools/wrench.c
without knowing whether
the program was compiled with the posix
option, use the filename
//hfs:/u/marie/tools.wrench.c
. Any such functions must not be
compiled with the posix
option themselves, because then any program
using such functions would automatically follow the naming conventions for
programs compiled with the posix
option.
open
function: the PATH option corresponds
to the pathname to be opened, the PATHOPTS option corresponds to the
open
flags, and the PATHMODE option corresponds to the file creation
mode specification.
HFS files can be accessed using a ddn
-style filename, as can
any other MVS file. The following points should be noted:
open
or fopen
options must be compatible with the
DD statement. For example, if the DD statement specifies
PATHOPTS=ORDONLY, but the fopen
call specifies a mode of
'r+'
, the open will fail.
open
or fopen
, the file already will have been created.
In particular, if the DD statement specifies PATHOPTS=(OCREAT,OEXCL)
and the open
call also specifies O_CREAT+O_EXCL
, the
open
will fail, because the file will have been created when
the DD statement was processed.
<stdio.h>
is simply a file in a
particular directory. In MVS, such names are generally interpreted by
treating the first part of the name as a member name, relative to a PDS
defined by a DDname. (For example, SAS/C interprets <stdio.h>
as
ddn:syslib(stdio)
). With the availability of OpenEdition,
it may be desirable to modify these programs to use a PDS or an
HFS directory interchangeably, as convenient for the user. SAS/C
provides the following extension to its ddn
-style filename
handling in support of this. Besides all previously accepted forms, a
ddn
-style filename may now have the following form:
ddname/filenameHere,
ddname
is a valid MVS filename, and filename
is a
valid POSIX filename (not containing any slashes). When
ddn:ddname/filename
is opened, the following occurs:
ddname
is defined and allocated to an HFS directory
dirname
, the file dirname/filename
is opened.
For example, if the DDname SYSLIB references the directory
/usr/include
, then opening ddn:syslib/stdio.h
is the same as opening hfs:/usr/include/stdio.h
.
ddname
is defined and allocated to an MVS PDS, the file
ddname(member)
is opened, where the member name is the
same as filename
, discarding the first period in the name
and all succeeding characters, and truncating the remainder of the
name to eight characters. For example, if the DDname SYSLIB
references a PDS, then opening ddn:syslib/stdio.h
is the same as opening ddn:syslib(stdio)
.
ddname
is undefined, or it references some other kind of
file, the open fails.
Note:
When the ddname/filename
syntax is used and the DDname
references an HFS directory, any PATHOPTS specified on the DD
statement apply to the subfile as well. Thus, if DDname SYSLIB
specifies PATHOPTS=OWRONLY, opening ddn:syslib/stdio.h
using open mode 'r'
will fail.
fork
or exec
, as when a
program is called by the shell, a new address space is created with no
DD statements allocated other than possibly a STEPLIB. For programs
exclusively using UNIX oriented interfaces, this does not present a problem,
but it can present difficulties for porting existing MVS applications to
run under the shell. For this reason, the SAS/C library permits you to
substitute environment variables for DDnames in programs invoked by
the exec
system call.
For a program invoked by exec
, if an attempt is made to open
a DDname (for example, using the filename //ddn:anyfile
), if no
corresponding DD statement exists, the library checks for an
environment variable named ddn_ANYFILE
. Notice that the prefix
ddn
is always in lowercase letters, while the DDname proper is always
in uppercase letters. The value of the environment variable, if it exists,
must have one of two forms:
ddn_MACLIB
is sys1.maclib(dcb)
, an fopen
of
//ddn:maclib
is treated as if the call specified
//dsn:sys1.maclib(dcb)
. However, any MVS dataset specified via a
ddn_
environment variable must already exist; that is, the library
will not create a new data set while processing an environment variable.
However, you can reference a nonexistent member of an existing PDS.
ddn_MACLIB
is /usr/include/stdio.h
, an fopen
of //ddn:maclib
is treated as if the call specified
//hfs:/usr/include/stdio.h
. A ddn_
environment variable
can reference a nonexistent HFS file, which will then be created when the
DDname is opened (if permitted by the fopen
options).
ddn
-style filename is opened using an environment
variable, the specified DDname is allocated by the library during
processing. Thus, if the same program opens the DDname
a second time, a DD statement will be found, and the environment
variable will not be referenced again. Consequently, changing the
environment variable after it has been used to open a file will be
ineffective.
Note:
The ddn:ddname/filename
pathname format described above
can be used both with DDnames defined by an environment variable and
with actual DD statements.
open
system call, the
POSIX.1 standard requires that the call be assigned the lowest file
descriptor number that is not in use by an open file. Under
OpenEdition, the range of valid file descriptors is from 0 to a
maximum defined by the site. The default maximum is 64, but it
can be set by the site to be as low as 16 or as high as 65,536. The
maximum number of open OpenEdition files can be determined using
the sysconf
function.
The limit on the number of open file descriptors is unrelated to the
library's limit on the number of FILE
pointers that may be
opened using standard I/O. This limit is always 256, regardless
of the OpenEdition limit. File descriptors in the valid OpenEdition
range can be assigned to files other than OpenEdition files in two situations:
FILE
pointers stdin
, stdout
,
and stderr
as being file descriptors 0, 1, and 2, whether or not
these are HFS files.
open
,
OpenEdition could assign file descriptor 4 to the newly opened file, and
then the library could not distinguish a request to write to file 4 from
a request for socket 4.
The library solves this problem using shadow files. Whenever the
library needs to assign a file descriptor for a file that is not an OpenEdition
file, it first opens /dev/null
to obtain a file descriptor,
which is then assigned to the socket. The shadow file is closed only when
the socket or standard file is closed. Because OpenEdition associates the
file descriptor with /dev/null
, it will not be possible for OpenEdition
to associate the descriptor with any other file. This technique also ensures
that socket numbers are assigned in accordance with OpenEdition rules.
You should note the following points about file descriptor allocation:
open
function to open MVS files for UNIX style
I/O, very large file descriptors are assigned, thereby preventing these
files from affecting the OpenEdition file limit.
oeattach
. In such
cases, file descriptors may not be assigned in the order specified by
POSIX.1. This mode of operation is not recommended, because the sharing
of file descriptors (and other data, such as signal handlers) between the
two programs can lead to very confusing results.
stdin
, the standard input stream,
stdout
, the standard output stream, and stderr
, the
standard error stream. A number of C library functions, such as
puts
and scanf
, are defined to use stdin
or
stdout
automatically, without requiring you to explicitly
specify a FILE
pointer. Note that the standard streams
are always opened for text access.
stdin
, stdout
, and stderr
are implemented as
macros, not as true variables. For this reason, you cannot assign
them new values. If you want to reopen one of the standard streams,
you must use the freopen
or afreopen
function rather
than fopen
or afopen
.
Whether the standard streams are actually used is determined by the
program, with one exception. Library diagnostic messages are written
to stderr
, if it can be opened successfully and is suitable for
output. If stderr
is unavailable, library diagnostics are
written to the terminal under CMS or TSO, and to the job log under
MVS-batch.
Under CMS, all three standard streams are, by default, directed to the
terminal. Under MVS, the default filenames for stdin
,
stdout
, and stderr
are ddn:sysin*
,
ddn:sysprint*
, and *
, respectively. stdin
uses the
DDname SYSIN, if it is defined, and the terminal, otherwise.
Similarly, stdout
uses SYSPRINT, if it is defined, and the
terminal, otherwise. stderr
is directed to the terminal or to
the DDname SYSTERM, if running in batch.
For a program running under OpenEdition MVS, by default stdin
,
stdout
, and stderr
are defined as file descriptors 0,
1, and 2, as passed by the calling program. If one or more of these
file descriptors is not open in the calling program, any attempt to use
the corresponding standard file in the called program will fail,
unless it opens the appropriate file descriptors itself.
Under MVS, it is possible for one or more of the standard streams to
fail to open. For instance, in batch, stdin
cannot be opened
unless you define the DDname SYSIN, and stderr
cannot be opened
unless you define the DDname SYSTERM. To avoid generating an "open
failure" error message for a file that is never used, the library
delays issuing a system open for a standard stream until it is first
used. Note that opening a file under MVS requires significant
memory. For this reason, if you write to a standard file when your
program runs out of memory (for instance, when malloc
fails),
you may want to force the file to be opened earlier, as by writing an
initial new line at a time when enough memory is known to be
available.
fopen
, there is no
direct way to change the filenames associated with them. For this
reason, C implementations traditionally support
command-line redirection. This permits the user of a program to
specify on the command line (that invokes the program) the filenames to
be associated with standard input and output streams. For example, the
CMS command line "xyz <ddn:input >printer"
invokes the program XYZ,
requesting that ddn:input
be used as the filename for
stdin
, and that printer
be used as the filename for
stdout
. Redirection is described in detail in SAS/C Compiler and Library User's Guide, Fourth Edition .
Additionally, you should be aware of the following considerations:
ferror
function to test for errors using a standard stream, just as for any
other stream, to avoid wasting time trying to read or write a file
that cannot be accessed.
cms
style filenames under CMS. You can initialize the _style
external variable to define a different default style, as described in
Chapter 9 of SAS/C Compiler and Library User's Guide, Fourth Edition . The default style applies to all files used
by the program, not just to the standard files.
To change the default name for a standard file, you must initialize an
external char *
variable with the filename to be used. The
external variables are _stdinm
, _stdonm
, and
_stdenm
for stdin
, stdout
, and stderr
,
respectively. For example, the following declaration specifies that
by default, _stdinm
should read from the user's virtual reader:
char *_stdinm = "cms:reader";
The _stdinm
,_stdonm
, and _stdenm
specifications are
honored even for programs called with exec
. Thus, using these
variables, you can override the standard use of file descriptors 0,
1, and 2 for these files if you wish. If you do this, the standard
file descriptors are not closed, and can still be accessed directly
via the file descriptor number.
Similarly, you can assign an initial value to the external variables
_stdiamp
, _stdoamp
, or _stdeamp
to specify the
amparms to be used when stdin
, stdout
, or stderr
is opened. The library default amparms are shown in Table 3.7:
Table 3.7 Default Amparms for the Standard Files
File Amparms
stdin prompt= pgmname :\n stdout print=yes stderr print=yes,page=60
You may want to override these default amparms in the following situations:
stdin
is defined as the terminal, a prompt of the form
pgmname
: (where pgmname
is the program name
or ""
if the program name cannot be determined) is issued to the
terminal before each read. If your program performs its own prompting,
you may want to initialize _stdiamp
to ""
to suppress the
library prompt.
Note:
A standard prompt is not used when stdin
is defined as file
descriptor 0 (for a program called by exec
), even if file
descriptor 0 references the terminal.
stdout
and stderr
amparms include
"print=yes"
, the library issues a warning message if the
associated physical file does not support page formatting (for
example, if it is an MVS data set whose record format does not include
A). If you expect your program to be run with stdout
or
stderr
associated with this type of file, you can initialize
_stdoamp
or _stdeamp
to "print=no"
to inhibit the
diagnostic message.
stdin
, stdout
, and
stderr
, respectively. The library supports such access, provided
that certain guidelines are followed. This usage is nonportable. The
following restrictions apply:
stdin
) for input only, and file numbers 1
(stdout
) and 2 (stderr
) for output only.
lseek
on any of these files.
read
to file 0 and fgetc
to stdin
in the same program.
stdout
, rather than with stdin
. If you call a UNIX I/O
function with a standard file descriptor that is not assigned by
OpenEdition, and whose corresponding standard FILE
pointer is
associated with a different file descriptor, the library will reject the
call rather than possibly access the wrong file.
read
, write
, or lseek
call fails, the
only indication is the value returned by the function. Depending on
the error, it may be possible to continue to use the file after the
error occurs.
FILE
object is used to identify the file. This pointer is passed
to I/O routines such as fread
and fwrite
to indicate the
file to be read or written. Associated with each FILE
object
is a flag called the error flag that indicates whether the most recent
I/O request failed. When the error flag is set, it is not possible to
use the file other than to close it or to call the clearerr
function to clear the flag.
The error flag for a file is set whenever an error occurs trying to
access a file. The flag is set for all types of errors, whether they
are hardware errors (such as an unreadable tape block), errors
detected by the operating system (such as a full CMS minidisk), or
errors detected by the library (such as trying to read a write-only
file). In addition to setting the error flag, the library also writes
a diagnostic message to the stderr
stream and sets the
errno
external variable to indicate the type of error that occurred.
The function ferror
can be called to determine whether the
error flag is set for a file. Using this function is sometimes
necessary because some functions, such as fread
, do not
distinguish in their return values between error conditions and end of
file.
If you want to continue processing a file after an error occurs, you
must call the clearerr
function to clear the error flag; that
is, to cancel the effect of the previous error. Some errors (such as
running out of disk space under MVS) are so severe that it is
impossible to continue to use the file afterwards without reopening
it. In such cases, clearerr
is unable to clear the error, and
continued attempts to use the file cause new errors to be generated.
longjmp
to exit from a signal handler,
or when a signal handler performs I/O to a file in use at the time of
the signal. When the interrupt flag is set, you can call
clearerr
to clear it along with the error flag and continue to
use the file.
For terminal input under MVS and CMS (except with OpenEdition), the
system calls do not allow signals to be detected while the program is
waiting for terminal input, with one exception. The SIGINT signal,
which is an attention interrupt under MVS or an IC immediate command
under CMS, terminates the terminal read and causes any handler to be
called immediately. If your SIGINT handler needs to read from the
terminal, you should use a different FILE
pointer from the one
used by the rest of your program; otherwise, the error flag is set for
the file, as described in the previous paragraph. If you must use the
same FILE
pointer in mainline code and in your handler, you
need to call clearerr
in the handler before reading from the
terminal and call it again after exit (either by return
or by
longjmp
) from the handler.
afread
, afread0
, afreadh
, afwrite
,
afwrite0
, and afwriteh
have been defined to permit this sort
of application to be written in C. These functions, together with
afopen
, afreopen
, and afflush
are known as
augmented standard I/O.
afread
and afwrite
can only be used with binary streams.
Because they are used with binary streams, they never translate or
otherwise modify input or output data, even if the data include
control characters. afread
and afwrite
are useful only
when the "seq"
access method is used, because a file processed with
the "rel"
access method is treated as a stream of characters without
record boundaries. If you need to process files with fixed-length
records using afread
or afwrite
, you should open the
file with afopen
, and request the use of the "seq"
access
method.
afread
and afwrite
functions are very similar in
form to the standard fread
and fwrite
functions: they
accept as arguments a pointer to the input or output area, the size of
the type of object to be read or written, the maximum number of
objects, and the FILE
pointer identifying the file. But,
unlike fread
and fwrite
, whose purpose is simply to read
or write the items specified without regard to record boundaries, the
purpose of afread
and afwrite
is to read or write the
items specified as a single record. Specifically, afread
and
afwrite
read and write items as follows:
afread
is called, it reads items from the file until a
record boundary is encountered. It reads, at most, the number of
items specified, and it generates a diagnostic message if there are
any further items in the record. It is permitted for the input record
to contain fewer items than requested. In this case, afread
reads as many as are present in the record, and returns the number of
items read to its caller. This permits easy processing of files
containing variable-length records with afread
.
afwrite
is called, it writes all the items specified and
then forces a record break to occur. An error message is generated if
the items do not all fit in a single record, or if the file
characteristics will not permit writing a record of that size.
afread
and afwrite
do not support zero-length records.
On input, a zero-length record is ignored, and similarly, an attempt
to write a zero-length record is ignored. Two alternate functions,
afread0
and afwrite0
, are provided. These functions can
handle zero-length records, if the file being processed supports them.
To support zero-length records, afread0
and afwrite0
use error-reporting conventions that are not compatible with the standard
C fread
and fwrite
functions.
afread
and afwrite
do not require that the file be
positioned to a record boundary when they are called. Also, you can
freely mix calls to afread
and afwrite
with calls to
other standard I/O routines, such as fscanf
or fseek
,
if your application requires it. See the function descriptions for
afread
and afwrite
for examples of their use.
afreadh
and afwriteh
enable you to read or write a
header portion of a record before calling afread
or
afwrite
to process the remainder. This is useful for reading
or writing files processed by another language (such as COBOL or Pascal)
that supports variant records.
A variant record is a record composed of two parts, a fixed format
part and a variable format part. The fixed format part contains
information common to all records, and a field defining the length or
structure of the remainder of the record. Depending on the situation,
it may not be possible to read or write such records conveniently
using afread
and afwrite
. (Defining the records to be
processed as a C union is helpful only if all the different variants
are the same size.) afreadh
and afwriteh
support
processing such records in a straightforward way:
afreadh
is similar to afread
, except it does not require
that a record break occur after the last item read. However, all
items read must be contained in a single record, or an error message
is generated. afreadh
is most frequently used to read the
first part of a variant record.
afwriteh
is similar to afwrite
, except it does not force
a record break after the last item written. However, all the items
written must fit into a single record, or an error message is
generated. afwriteh
is most frequently used to write the first
part of a variant record.
See the function descriptions for afreadh
and afwriteh
for examples of their use.
system("tso:alloc file(sysmacs) da('sys1.maclib') shr"); direct = fopen("ddn:sysmacs", "rb");You can also access the PDS directory by opening the PDS using a
"dsn"
- or "tso"
-style name, and specifying the
amparm "org=ps"
, as in
direct = afopen("dsn:sys1.maclib", "rb", "seq", "org=ps");The directory is treated by the library as a RECFM=F, LRECL=256 data set, regardless of the attributes of the members.
You cannot use C I/O to modify a PDS directory. Also, access to a PDS
directory is supported using only ddn
-style filenames, unless
the org
amparm is used. If you specify a PDS using a
dsn
- or tso
-style filename without an org
specification, and no member name is present, the member name
TEMPNAME will be used.
nohtsig
run-time option to suppress the library's ESTAE.
When the library recovers from one of these ABENDs, the file is
automatically closed by the operating system. For this reason, the
error flag is set permanently; that is, you cannot clear the flag with
clearerr
and continue to use the file. An exception is made by
the "rel"
access method, which reopens the file if you use
clearerr
to clear the error condition. This enables you to read or
modify data you have already written, but you cannot add any more records
to the file, because this simply will cause the ABEND to reoccur.
Although other kinds of I/O errors are quite rare, these out-of-space ABENDs occur frequently, even for production programs. Therefore, you should always check output operations for success to avoid loops when trying to write to a file that can no longer be accessed.
fseek
or fsetpos
functions are used on a PDS member, the library
depends on this processing, except for a read-only file. For this
reason, the use of fseek
or fsetpos
on a PDSE member is
not supported unless the member is read-only, or unless you specify
grow=no
. One exception is that fseek(f, 0L, SEEK_SET)
can
always be used to reposition a PDSE member to the start of file.
Note:
When a PDSE member is accessed through UNIX style I/O in binary
mode, this restriction does not apply. In this case, full use of the
lseek
function for repositioning is supported.
grow
, which can be
specified when a file is opened for 'r+'
or 'r+b'
. You
specify grow=no
to inform the library that the program will only
replace existing records of a file, rather than adding any data to the end.
When you specify
grow=no
for a PDSE member, the library can open
the member for UPDAT rather than OUTIN and can then support use of either
the fseek
or fsetpos
function.
The grow
amparm is also supported for standard PDS members, and
it should be used where possible, because it performs an
update-in-place action, and avoids wasting the space in the PDS occupied by
the previous member.
org
amparm supports this. org
has more uses than just PDS allocation.
See Opening Files for more information.
When you use the afopen
function to create a new PDS, you can
specify one of three values for org
po
pds
pdse
Note:
A site may choose to ignore a program's request for a particular type
of PDS, although this is fairly unusual. For this reason, it cannot be
guaranteed that org=pds
or org=pdse
will be honored in
all cases. If your operating-system level does not support PDSEs, the
org
values pds
and pdse
will be treated like the
value po
.
You can access DIV objects using the ordinary C library I/O functions
and the "rel"
access method. Two amparms are available for use with
VSAM linear data sets. These amparms are not required, but they allow
the program to direct the internal buffering algorithm used by the
library:
bufsize= nnn
bufmax= n
bufsize
is rounded up to a multiple of
4096. The default value for bufsize
is bufsize=262144
(256K). The default value for bufmax
is bufmax=4
.
These default values can be modified by your site; see your SAS
software representative for C compiler products for more information
about the default values for bufsize
and bufmax
. This
discussion assumes the default values have not been modified.
DIV windows The library allocates one window when the object is opened. This window is mapped to the beginning of the object. When a reference is made to a location that is outside the bounds of the window, the library allocates a new window that maps the location.
New windows can be allocated, until the number specified by
bufmax
is reached. Then, if a reference is made to a location that
is not mapped by any window, the library remaps the least-used window
to the new location. The least-used window is the window that has the
fewest references made to locations that it maps.
If the limit specified by bufmax
has not been reached, but
there is insufficient storage available to allocate a new window, the
library issues a warning and begins remapping existing windows.
How the amparms are used As with other amparms, the
linear data set amparms may be specified in the amparms
argument to afopen
or aopen
. If one of the amparms is
omitted, then the library uses its default value.
If a linear data set is opened with fopen
or open
, or
neither amparm is used, then bufsize
is calculated from the
object size divided by 4, rounded to a multiple of 4096 as necessary.
If the data set has size 0 (that is, the data set is empty), the
default values are used. If there is insufficient storage available
to allocate the first window, the library issues a warning and uses
whatever storage is available.
xed
style files, extending global MACLIB/TXTLIB
processing, and using the CMS shared file system.
xed
filename style. xed
style filenames have the same format as cms
-style filenames,
for example, xed:payroll data a
. The filename must identify a
CMS disk file. That is, you cannot specify device names such as PRINTER.
Also, you cannot use the MEMBER
keyword (or its abbreviated format
equivalent).
You can use the xed
style even when XEDIT is not active. In
this case, or when the file requested is not in the XEDIT ring, the
file is read from disk.
See the system
function description and Chapter 2, "CMS
Low-Level I/O Functions," in SAS/C Library Reference, Volume 2 for information on other facilities
that may be useful for programs that use XEDIT files.
cms
-style filenames
%MACLIB (MEMBER name
) and %TXTLIB (MEMBER name
)
to access members of global MACLIBs or TXTLIBs. Global
MACLIBs and TXTLIBs are established using the CMS GLOBAL command. Here
is an example:
GLOBAL TXTLIB LC370 MYLIB1 MYLIB2
When %TXTLIB(
is opened, the libraries LC370 TXTLIB,
MYLIB1 TXTLIB, and MYLIB2 TXTLIB are searched, in that order, for the
member name
)
. Also, the library implements several
extensions to standard CMS GLOBAL processing to support larger numbers
of global libraries than allowed directly by the CMS GLOBAL command.
These extensions also support the use of OS partitioned data sets as
global libraries.
name
One extension to GLOBAL processing enables you to issue a FILEDEF
using the DDname CMSLIB and then include CMSLIB in the list of files
for the GLOBAL command. This causes the files associated with the
CMSLIB DDname to be treated as global. For example, if you issue the
following commands, the same set of libraries as in the previous
example is defined, and the effects of opening
%TXTLIB(
are the same:
name
)
FILEDEF CMSLIB DISK MYLIB1 TXTLIB A FILEDEF CMSLIB DISK MYLIB2 TXTLIB A (CONCAT GLOBAL TXTLIB LC370 CMSLIB
One advantage of using the FILEDEF approach is that the FILEDEF may be concatenated, enabling you to bypass the limit of eight global libraries imposed by early versions of CMS. Another is that you can put OS partitioned data sets into the global list (in a non-XA system), as described in the following section. Note that when CMSLIB is concatenated, the global search order is the same as if CMSLIB were replaced in the global list by the files that compose it, in the order in which they were concatenated.
The special processing of the CMSLIB DDname is a feature of the SAS/C library; the DDname CMSLIB has no special significance to CMS.
Using an OS PDS as a global MACLIB/TXTLIB If your site permits CMS access to OS disks, the CMSLIB FILEDEF for use in a global list may reference an OS partitioned data set. The FILEDEF must have the following form:
FILEDEF CMSLIB DISKfilename
MACLIBfm
DSNOS-data-set-name
TXTLIB
The filemode (fm) cannot be an asterisk (*) and must refer to an OS disk. The PDS referenced must have fixed-length blocked records with an LRECL of 80. The PDS must reside on a 3330, 3350, or 3380 disk device.
Note: You cannot use an OS PDS as a global MACLIB/TXTLIB in a XA-mode virtual machine.
When a shared file is open for update, the file system provides update access to a copy of the file. Changes to the file do not take effect until the changes are committed. Alternately, after updating a file, the user can roll back the changes, which leaves the file unmodified. If a user opens a shared file for reading while another user is updating it, the reading user accesses a temporary copy of the data and can read only the data in the file at the time it was opened, even after the writing user commits changes.
Shared files can be accessed as if they were normal CMS disk files by using the CMS ACCESS command, which can assign a filemode letter to an SFS directory. Currently, use of unique SFS functionality, such as access to subdirectories and the ability to roll back changes, is not available with the CMS ACCESS command. These features are only available when the Shared File System is used directly.
The SAS/C Library allows access to the Shared File System directly and
via the ACCESS command. If you use the ACCESS command to assign a
file-mode letter to an SFS directory, files in the directory can be
accessed using standard CMS pathnames. Alternately, a shared file can
be processed directly by using an sf
-style filename. For
example, opening the following file accesses the file SUMMARY DATA in
the directory of userid ACCTING named YR90.JUNE:
sf:summary data accting.yr90.juneWhen a shared file is processed directly, it can be committed automatically as it is closed, or the file can be committed explicitly using the
afflush
function.
You can also process an SFS directory as if it were a file (for input
only) by using an sfd
-style filename. This enables you to
retrieve various sorts of information about the files or
subdirectories stored in the directory. The way in which information
is returned is controlled by the dirsearch
amparm.
SFS files can be processed with either the "seq"
or
"rel"
access method, if the file attributes are appropriate. Except
for trunc=yes
(which is not allowed), all amparms that can be
used with cms
-style files can be used with an sf
-style
file. SFS directories can be opened only for input, and are always
processed by the "seq"
access method.
For more general information about using the Shared File System, see the IBM publication VM/ESA CMS User's Guide and other CMS documentation.
fopen
,
is
sf:fileid dirid [filemode-number](You can omit the
sf:
prefix if the external variable
_style
has been set to define sf
as the default style.)
Here fileid represents either a standard filename and filetype, or a namedef, which is an indirect reference to a filename and filetype created by the CMS CREATE NAMEDEF command.
Similarly, a dirid represents the following:
[filepool]:[userid].[subdir1.[subdir2]...] namedef]The filepool argument identifies a file pool; userid identifies a user; subdir1, subdir2, and so on name subdirectories of the user's top directory; and namedef is an indirect reference to a directory created by the CMS CREATE NAMEDEF command. Note that every dirid that is not a namedef contains at least one period. The simplest dirid is
"."
(which represents the
current user's top directory in the default file pool).
Here are some examples of sf
filenames and their
interpretation:
sf: profile exec .
sf: updates amy.
updates
in the top
directory of user AMY.
sf: test data qadir 3
qadir
. The file has file mode 3; that is, it will be erased
after it is read.
sf: graphix data altpool:.model.test
Note:
There is no compressed (blankless) form for sf
filenames.
sf
-style file for update, you control when
changes are committed. Two methods are provided to control when
changes are committed: the afflush
function and the
commit
amparm.
The afflush
function is called to flush output buffers to disk
with high reliability. For SFS files, a call to afflush
causes
a commit to take place, so that all changes to the file up to that
point are permanently saved.
The commit
amparm is used with sf
-style files to
specify whether changes will be committed when the file is closed.
The default, commit=yes
, specifies that when the file is
closed, changes are committed. The alternative, commit=no
,
specifies that changes are not committed when the file is closed.
When you open a file with commit=no
, you must call
afflush
before closing the file if you want changes saved. On
the other hand, if you want to roll back your changes, close the file
without calling afflush
, and no changes will be saved. You can
call afflush
as often as you want, with either commit=yes
or commit=no
; when you close a commit=no
file, all changes
since the last call to afflush
are rolled back. See the
afflush
function description for an example of the use of
commit=no
.
sfd
-style
pathname for input. The pathname specifies the directory to be
read, and possibly a subset of the directory entries to be read. The
format of the information read from the file, as well as which entries
(files and subdirectories) are processed, is determined by the value
of the dirsearch
amparm when the file is opened.
The following values are accepted for dirsearch
:
file
all
allauth
subdir
dirsearch
when you open a
shared-file directory, dirsearch=allauth
is assumed.
When you open a directory with dirsearch=file
,
dirsearch=all
, or dirsearch=allauth
, the pathname
specifies both the directory that is to be read and a filename and
filetype, possibly including wild-card characters, indicating from which
directory entries are to be read.
The form of an sfd
-style filename for these dirsearch
values is
sfd: fileid dirid [filemode-number]If fileid has the form filename filetype, the filename, filetype, or both can be specified as *, indicating that the filename and/or filetype is not to be considered while reading the directory. If filemode-number is specified, only entries for files with the specified mode number are read.
Here are a few examples of sfd
-style filenames for use with
dirsearch=file
, dirsearch=all
, or dirsearch=allauth
:
sfd: * * .
sfd: * exec devel
devel
are to be read.
sfd: * * mike.backup 2
When you open a directory with dirsearch=subdir
, the pathname
specifies only the directory that is to be read. This format of
sfd:
-style filename is also used when you call remove
,
rename
, access
, cmsstat
, or sfsstat
for a
Shared File directory.
Here are a few examples of sfd
-style filenames to use with
dirsearch=subdir
:
sfd: .
sfd: master
master
are to be read.
After you open a Shared File System directory, you read it as any other file.
The data you read consist of a number of records, one for each
matching file if dirsearch=subdir
is not specified, and one for
each subdirectory if dirsearch=subdir
is specified. Mappings
for the formats of these records are provided in the header file
<cmsstat.h>
. The following are more exact specifications:
dirsearch=file
struct MAPALL
. Only the first L_file
bytes of this record
are actually read.
dirsearch=all
or dirsearch=allauth
struct MAPALL
. The
number of bytes read is L_all
.
dirsearch=subdir
struct
MAPDIR
.
The number of bytes read is L_dir
.
These structures generally contain binary data. Therefore, if
new-line characters appear in the data, you should open sfd
files for binary rather than text access to avoid possible confusion.
Also, none of the seeking functions fseek
, ftell
,
fsetpos
, or fgetpos
are supported for Shared File
directories.
Here is a simple example that opens a directory with dirsearch=file
to print out the names of the files in the directory:
#include <lcio.h> #include <cmsstat.h> struct MAPALL dir_data; main() { FILE *dir; int count = 0; /* Open top directory for input. */ dir = afopen("sfd: * * .", "rb", "", "dirsearch=file"); if (!dir) abort(); for(;;) { fread(&dir_data, L_file, 1, dir); /* Read one entry. */ if (ferror(dir)) abort(); if(feof(dir)) break; if (count == 0) /* Write title before first line. */ puts("Files in directory .:"); ++count; printf("%8.8s %8.8s\n", dir_data.file.name, dir_data.file.type); } printf("\n%d files found.\n", count); fclose(dir); exit(0); }
For example, suppose you have a file containing a record for each employee in a company. If the data are stored in a normal MVS or CMS file, to update a single record you must read the entire file, until the correct record is found. Alternatively, the data can be stored in a VSAM file, using employee name or employee number as a key. With this organization, a program can immediately read and update any record, given the key value, without having to read the rest of the file.
VSAM files are described in more detail in the IBM publication MVS/DFP Using Data Sets. Consult this publication for a more complete description of VSAM files and services.
KSDS files can have alternate indices, which are auxiliary VSAM files that provide access to records by a key field other than the primary key. Access to records by an alternate index is accomplished by a path, which is an artificial data set name assigned to the combination of the base KSDS and the alternate index. An alternate index can be defined for a KSDS using a nonunique key field. For example, an employee file cannot have last name as its primary key because more than one employee may have the same last name. But a path to the employee file can use last name as its key, allowing quick access, for instance, to the records for all employees named Brown.
Like KSDS files, ESDS files can have alternate indices that provide keyed access to the records of the ESDS. For instance, you can choose to make an employee file an ESDS file, with the records arranged by the order in which they were added to the file. You can still access records in this file using last names by building an alternate index with last name as the key over the ESDS. The same rules apply when you use a path to access an ESDS as when you access the ESDS directly; that is, you cannot change the length of a record or delete a record. Except for these restrictions, a path over an ESDS is treated as a KSDS because records accessed through the path are always arranged in the order of the alternate keys.
<stdio.h>
. Because of the special
characteristics of VSAM files, there are restrictions for some types
of VSAM files:
"rel"
access method.
This means that you can use the fseek
and ftell
functions,
which provides compatibility with file behavior on UNIX
operating systems.
"rel"
access method. This means that the fseek
and
ftell
functions can be used, which provides compatibility with
file behavior on UNIX operating systems. See Advanced MVS I/O Facilities
for more information on accessing LDS files.
fopen
or afopen
function, as shown in the following
statements:
ftext = fopen("ddn:ESDS", "r+"); /* Open ESDS for text access. */ fbin = fopen("ddn:ESDS", "r+b"); /* Open ESDS for binary access. */ fkey = fopen("ddn:ESDS", "r+k"); /* Open ESDS for keyed access. */
Only a subset of the standard I/O functions (shown in the following list) are available for files opened for keyed access; that is, this list shows the functions that make sense for such files.
afflush
clearerr
clrerr
fattr
fclose
feof
ferror
ffixed
fnm
fterm
setbuf
setvbuf
The following keyed-access functions are supported only for VSAM files. These functions are described in more detail later in this section:
kdelete
kgetpos
kinsert
kreplace
kretrv
ksearch
kseek
ktell
Keyed access is not supported for VSAM LDS files because these files are not divided into records and have no keys.
Many VSAM files have fixed-length records, where all records have the same format. These files are easy to process in C, because the record can be represented simply as a structure, as shown in this simple example:
struct { char name[20]; char address[50]; short age; } employee; kretrv(&employee, NULL, 0, f);This example reads records of a single type from a VSAM file. More complicated files may have records with different lengths or types; C unions can be helpful in processing such files:
struct personal { char name[20]; char rectype; /* = P for personal */ char address[50]; short age; } ; struct job { char name[20]; char rectype; /* = J for job */ long salary; short year_hired; } union { struct personal p_rec; struct job j_rec; } employee; kretrv(&employee, NULL, 0, f);
The call to the kretrv
function can read a record of either
type; then the rectype
field can be tested to determine which
type of record was read. Here is an example showing the replacement
of a record with several types:
if(employee.p_rec.rectype == 'P') recsize = sizeof(struct personal); else recsize = sizeof(struct job); kreplace(&employee, recsize, 0, f);
If the length were specified as sizeof(employee)
and the
record were a job record, more data would be written than defined in the
record, and file space is wasted.
Any characters can occur in a record. Neither new-line characters ('\n') nor null characters ('\0') have any significance.
For a KSDS file, a record key is always a fixed-length field of the
record. Any characters can appear in a key, including the new-line
character ('\n') and the null character ('\0'). Also, the key is not
restricted to being a character type; for some files, the key might be
a long
, a double
, or even a structure type.
When you have character keys, you should be sure to specify all
characters of the key. For instance, consider the following call to
the ksearch
function, intended to retrieve the record whose
key is Brown in the employee file described previously:
ksearch("Brown", 0, K_exact, f);This search will probably fail, because the key length for this file is 20 characters. The
ksearch
function looks for a record
whose key is the characters "Brown"
, followed by a null
character, followed by 14 random characters (whatever comes after the
string "Brown"
in memory), and probably will not find one.
Usually, strings in VSAM files are padded with blanks, so the following example shows the correct usage:
char key[20]; memcpyp(key, "Brown", 20, 5, ' '); /* Copy key and blank pad. */ --> ksearch(key, 0, K_exact, f);
ESDS and RRDS files do not have physically recorded keys. However,
the RBA (for an ESDS) and the record number (for an RRDS) serve as
logical keys for these files. The structures representing these
records in a C program must include an unsigned int
or
unsigned long
field at the start of the record to hold the key value.
This key is not actually recorded in the file. In this example, record
46 is inserted into an RRDS:
struct { unsigned long recno; char name[20]; char address[60]; } rrds_rec; rrds_rec.recno = 46; kinsert(&rrds_rec, sizeof(rrds_rec), NULL, rrds);The key (46) is specified in the first 4 bytes of the record. Note that the key is not actually stored in the file. The size of the C record is 84 characters, but the length of the record in the VSAM file is 80 characters because the key is not physically recorded.
kdelete
and
kreplace
, which affect the current record, are not allowed at
this point. After successful use of the kinsert
, kreplace
,
kdelete
, ksearch
, or kseek
, the file is also in
this state.
kretrv
, the retrieved record becomes
current. This means that the record can be updated or deleted and
that its address can be obtained with the ktell
or
kgetpos
functions. The current record can either be held for
update or not held. The record is not held if the file is opened for
input only or if K_noupdate
was specified as an argument to the
kretrv
call. Otherwise, the record is held. Replacement or
deletion of a record is allowed only if it is held for update.
Additionally, some other VSAM processing is different, depending on
whether the current record is held. For more information, see
VSAM pitfalls .
clearerr
function to continue use of the file. In
many cases after an error, the file position is undefined, and you
have to use ksearch
or kseek
to reposition the file
before continuing.
Unlike some other kinds of files, your program can open the same VSAM file more than once. The same file can be opened any number of times, either using the same filename, or using different names. A file can also be opened via several paths. The open modes do not need to be the same in this case. For example, one stream can access the file for input only, and another can access to append. However, each opening of the file must specify keyed access; that is, standard I/O and keyed I/O to the same file cannot be mixed.
When several streams access the same VSAM file, only one of them can
hold a particular record for update. If one stream attempts to
retrieve a record held by another stream and K_noupdate
is not
specified, retrieval will fail. Because of the way that VSAM holds
records for update, it is also possible for two streams accessing the
same file to interfere with each other's processing of different
records. See VSAM pitfalls for more information.
ksearch
function description for further details.
kinsert
and is not
generally predictable before the record is inserted.
ksearch
function description for further details.
Note: Sharing of VSAM files between users through SHAREOPTIONS(3) or the SHAREOPTIONS(4) Access Method Services (AMS) option is not supported by the SAS/C library. If you ignore this restriction, lost records, duplicate records, or file damage may occur.
When the same file is accessed through several paths, a problem can occur
when VSAM attempts to avoid reading a record from disk because a copy
exists in memory. If a request is made to read a record and the
record is not to be updated, VSAM may return an obsolete copy of the
record from memory to the program, rather than reading a current copy
from disk. If this is a problem for your application, you can always
retrieve records for update by not specifying K_noupdate
,
regardless of whether you intend to update them. This ensures that you
get the most recent version of a record at the cost of additional disk
I/O. But note that you cannot retrieve a record for update if you
open the file with open mode 'rk'
. Alternately, you can use the
afflush
function to flush all buffers in memory. After using
afflush
, retrievals access the most recent data from disk,
because there is no copy in memory.
Many programs cannot be affected by this problem. For example, if your
program processes records in key order, it probably does not ever attempt
to retrieve a record after it has been updated. For such a program, there
is no need to avoid the use of K_noupdate
on retrieval.
Another potential problem has to do with the way that VSAM stores records. Records in VSAM files are organized into control intervals of a fixed size. Each disk access consists of the reading or writing of an entire control interval. When VSAM is said to be holding a record, the control interval is actually what is held. This means that an attempt to read a record for update using one stream may fail, because another record in the same control interval is held by another stream. In general, when this may occur cannot be predicted, although records whose keys are close to each other are more prone to this condition.
This condition can be recognized by the setting of the value
EINUSE
for the errno
variable. Resolving the condition is
more difficult. It is possible to release a hold on a record without
updating the record by the call kseek(fp, SEEK_CUR)
. This
call does not change the file position, which means that kretrv
can be used to retrieve the next record, as if kseek
had never
been called. Also, sometimes you may be able to organize your program
so that it normally retrieves records using K_noupdate
and, if
the program decides that the record should be modified, retrieves the
record a second time for update immediately before replacing or
deleting it.
order
amparm can also have an effect on
performance.
bufnd
amparm specifies the number of I/O buffers VSAM is to
use for the data records. This option is meaningful only for VSAM
files and is equivalent to coding a BUFND value on an ACB assembler
macro used to open the VSAM file. A data buffer is the size of a
control interval in the data component of a VSAM cluster. For keyed
access and order=random
, the bufnd
default is 2. For
standard I/O VSAM access or keyed access with order=seq
, the
bufnd
default is 4. Generally, with sequential access, the
optimum value for the data buffers is six tracks, or the size of the
control area, whichever is less. For skip-sequential processing,
specifying two tracks for the data buffers is a good starting point.
Specification of a bufnd
value larger than the default
generally yields performance improvements for applications that
primarily do sequential input processing of the VSAM file or initial
loading (sequential writes after first open) for a VSAM file opened
with keyed access. In other situations, specifying a larger
bufnd
value may yield no improvement, or may actually degrade
performance by tying up large amounts of virtual storage and causing
excessive paging.
bufni
amparm specifies the number of I/O buffers VSAM
is to use for index records. This option is meaningful only for VSAM
KSDS files and is equivalent to coding a BUFNI
value on an
ACB assembler macro used to open the VSAM file. An index buffer is
the size of a control interval in the index component of a keyed VSAM
cluster. For keyed access (random or skip sequential), bufni
defaults to 4, and for text or binary access (mainly sequential), it
defaults to 1. For keyed access other than initial load, the optimum
bufni
specification is the number of high-level (nonsequence
set) index buffers + 1. You can determine this number by subtracting
the number of data control areas from the total number of index
control intervals within the dataset. You can use an upperbound bufni
specification of 32, which accommodates most VSAM files
with reasonable index control interval and data control area sizes
(cylinder allocated data component) up to the four-gigabyte maximum data
component size allowed. Large bufni
specifications incur
little or no performance penalty, unless they are excessive.
bufsp
amparm specifies the maximum number of bytes of
storage to be used by VSAM for all I/O buffers. This
option is meaningful only for VSAM files and is equivalent to
coding a BUFSP
value on an ACB assembler macro used to open the
file. A data or index buffer is the size of a control interval in the
data or index component. For a valid bufsp
specification
(minimum of one index and two data buffers), VSAM allocates data and index
buffers as follows:
order=seq
amparm, initial keyed access load, or text or
binary access, one or two index buffers are allocated, and the remaining
bytes are allocated to data buffers.
order=random
, two data buffers are
allocated, and the remaining bytes are used for index buffers.
A valid bufsp
specification generally overrides any bufnd
or bufni
specification. However, the VSAM rules for
doing this are fairly complex, and you should consult the appropriate
IBM VSAM Macro Reference manual for your system for more information
on the ACB macro BUFSP option.
The SAS/C VSAM example program, KSDS
, demonstrates how to load,
update, search, retrieve, and delete records from a KSDS VSAM file.
Two VSAM files are used:
#include <stdio.h> #include <lcio.h> #include <fcntl.h> #define BUFSIZE 80 #define VBUFSIZE 50 #define KEYSIZE 19 void loadit(void); /* Load a VSAM file. */ void update(void); /* Update a VSAM file. */ void printfil(void); /* Print a VSAM file. */ void add_rep(void); /* Add or update specific records. */ void del_rec(void); /* Delete specific records. */ FILE *vfptr1, /* ptr to the VSAM file */ *vfptr2, /* another ptr to the VSAM file */ *fptr; /* ptr to the DATA file */ char buffer[BUFSIZE+1]; /* buffer for reading input file data */ char vbuffer[VBUFSIZE+1]; /* VSAM record buffer */ char key[KEYSIZE+1]; /* key field for VSAM record */ main() { unsigned long offset; /* If VSAM file has been loaded, update. Otherwise LOAD. */ puts("Has the VSAM file been loaded?"); quiet(1); /* Attempt to open the file r+k. If that works, then it */ /* is loaded. The open could fail for reasons other than */ /* that the file has not yet been loaded. In this case, */ /* loadit will also fail, and a library diagnostic will */ /* be printed. */ vfptr1 = afopen("ddn:ITEM", "r+k", "", "keylen=19, keyoff=0"); quiet(0); if (!vfptr1){ puts("File has not been loaded. Load it."); loadit(); } else{ puts("File has been loaded. Update it."); update(); } /* Show the current state of the VSAM file. */ printfil(); /* Est. 2nd ptr to VSAM file. */ /*Search and print specific records. */ if ((vfptr2 = afopen("ddn:ITEM", "r+k", "", "keylen=19, keyoff=0")) == NULL){ puts("Could not open VSAM file a 2nd time"); exit(99); } /* Search for some specific records by key. */ puts("nnDo some searching"); memcpy(key, "CHEMICAL FUEL ", KEYSIZE); key[KEYSIZE]='0'; /* Terminate the key. */ printf("Search for %sn", key); ksearch(key, 0, K_noupdate | K_exact, vfptr1); memcpy(key, "HOUSEHOLD PAN ", KEYSIZE); key[KEYSIZE]='0'; /* Terminate the key. */ printf("Now Search for %sn", key); ksearch(key, 0, K_noupdate | K_exact, vfptr2); /* Retrieve the records found. */ puts("nnOK, now retrieve the records that we found"); kretrv(vbuffer, NULL, K_noupdate, vfptr1); vbuffer[VBUFSIZE]='0'; puts(vbuffer); kretrv(vbuffer, NULL, K_noupdate, vfptr2); vbuffer[VBUFSIZE]='0'; puts(vbuffer); fclose(vfptr2); /* Find the first and last records in the file and their RBA. */ kseek(vfptr1, SEEK_SET); kretrv(vbuffer, NULL, K_noupdate, vfptr1); vbuffer[VBUFSIZE]='0'; printf("nThe first record in the file is:n%sn", vbuffer); offset = ktell(vfptr1); printf("Its RBA is: %lun", offset); kseek(vfptr1, SEEK_END); kretrv(vbuffer, NULL, K_backwards | K_noupdate, vfptr1); vbuffer[VBUFSIZE]='0'; printf("nThe last record in the file is:n%sn", vbuffer); offset = ktell(vfptr1); printf("Its RBA is: %lun", offset); } /* This is the loadit function, which does the initial */ /* loading of the VSAM file. */ void loadit() { puts("Loading the VSAM file"); if ((fptr = fopen("ddn:DATA", "rb")) == NULL){ puts("Input file could not be opened"); return; } /* We must attempt to open the file again. Since we are here, */ /* we know that the first attempt failed, probably because */ /* the file was empty. */ if ((vfptr1 = afopen("ddn:ITEM", "a+k", "", "keylen=19, keyoff=0")) == NULL){ puts("VSAM file could not be opened"); return; } while (afread(buffer, 1, BUFSIZE, fptr)){ kinsert(buffer, VBUFSIZE, NULL, vfptr1); } } /* The following function updates the VSAM file by calling functions */ to add, replace, and delete records. */ void update() { puts("Updating the VSAM file"); printfil(); add_rep(); del_rec(); } /* The add_rep function updates the VSAM file by adding or */ /* replacing records specified in DDN:UPDATE. */ void add_rep() { puts("nUpdating specified VSAM records"); if ((fptr = fopen("ddn:UPDATE", "rb")) == NULL){ puts("Update file could not be opened"); return; } puts("n"); /* Search VSAM file for records whose keys match those in */ /* UPDATE file. If a match is found, update record. */ /* Otherwise, add record. */ kseek(vfptr1, SEEK_SET); while (afread(buffer, 1, BUFSIZE, fptr)){ memcpy(key, buffer, KEYSIZE); if ((ksearch(key, 0, K_exact, vfptr1)) > 0){ kretrv(vbuffer, NULL, 0, vfptr1); vbuffer[VBUFSIZE]='0'; printf("Replace the record:n%sn", vbuffer); memcpy(vbuffer, buffer, VBUFSIZE); vbuffer[VBUFSIZE]='0'; printf("With:n%sn", vbuffer); kreplace(vbuffer, VBUFSIZE, vfptr1); } else{ memcpy(vbuffer, buffer, VBUFSIZE); vbuffer[VBUFSIZE]='0'; printf("Can't find this record, so we'll add it:n%sn",vbuffer); kinsert(vbuffer, VBUFSIZE, NULL, vfptr1); } } fclose(fptr); } /* The del_rec function deletes VSAM records */ /* with specified keys. */ | void del_rec() { puts("nDeleting specified VSAM records"); if ((fptr = fopen("ddn:DELETE", "rb")) == NULL){ puts("Delete file could not be opened"); return; } /* Search VSAM file for records whose keys match those in */ /* DELETE file. If a match is found, delete record. */ /* Otherwise, issue a message that no match was found. */ | kseek(vfptr1, SEEK_SET); while (afread(buffer, 1, BUFSIZE, fptr)){ memcpy(key, buffer, KEYSIZE); key[KEYSIZE]='0'; if ((ksearch(key, 0, K_exact, vfptr1)) > 0){ kretrv(vbuffer, NULL, 0, vfptr1); vbuffer[VBUFSIZE]='0'; printf("Delete the record:n%sn", vbuffer); kdelete(NULL, vfptr1); } else printf("Couldn't find a record with the key: %sn", key); } fclose(fptr); } /* The function printfil prints the contents of the VSAM file. */ | void printfil() { int i=0; puts("nnHere is the current state of the VSAM file"); puts(" ITEM QTY SZ BIN DESC COMMENTS "); kseek(vfptr1, SEEK_SET); while ((kretrv(buffer, NULL, K_noupdate, vfptr1)!=-1) && !feof(vfptr1)){ buffer(|VBUFSIZE|) = '0'; printf("%d %sn", i, buffer); i++; } }The JCL file KSDSGO creates a KSDS VSAM file, loads it using the above program (
KSDS
), and then updates it using KSDS
.
Note: The DEFINEIT step will fail the first time if there is no VSAM file to delete. You must either comment out the DELETE step the first time or create a dummy VSAM file that can be deleted before this job is run:
//*------------------------------------------------------------------ //* DEFINE THE VSAM KSDS //*------------------------------------------------------------------ //DEFINEIT EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=A //SYSIN DD * DELETE (yourid.ksds.vsamfile) PURGE CLUSTER DEFINE CLUSTER (NAME(yourid.ksds.vsamfile) INDEXED VOLUMES(YOURVOL) - TRACKS(2 2) KEYS(19 0) RECORDSIZE(50 100) - FREESPACE(0 0) CISZ(512) ) - DATA (NAME(yourid.ksds.vsamfile.DATA)) - INDEX (NAME(yourid.ksds.vsamfile.INDEX)) LISTCAT ENTRIES(yourid.ksds.vsamfile) ALL /* //*------------------------------------------------------------------ //* LOAD THE VSAM KSDS USING SAS/C //*------------------------------------------------------------------ //LOADIT EXEC PGM=KSDS //STEPLIB DD DSN=your.load.dataset,DISP=SHR // DD DSN=sasc.transient.library,DISP=SHR //SYSPRINT DD SYSOUT=A //SYSTERM DD SYSOUT=A //SYSUDUMP DD SYSOUT=A //ITEM DD DSN=yourid.ksds.vsamfile,DISP=SHR //DATA DD * AUTO STARTER 99 02 92 WARRANTY MODERATE CHEMICAL ACID 05 04 00 PH10 MODERATE CHEMICAL EAAAAA 55 75 50 ALCOHOL CHEAP CHEMICAL FUEL 45 77 80 DIESEL EXPENSIVE CHEMICAL GAS 10 30 50 LEADED CHEAP HOUSEHOLD PAN 03 10 33 METAL CHEAP /* //* //*------------------------------------------------------------------ //* OBTAIN AN IDCAMS LISTCAT //*------------------------------------------------------------------ //IDCAMS3 EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=A //SYSIN DD * LISTCAT ENTRIES(yourid.ksds.vsamfile) ALL /* //* //*------------------------------------------------------------------ //* ADD/UPDATE/DELETE RECORDS TO THE VSAM KSDS //*------------------------------------------------------------------ //UPDATE EXEC PGM=KSDS //STEPLIB DD DSN=your.load.dataset,DISP=SHR // DD DSN=sasc.transient.library,DISP=SHR //SYSPRINT DD SYSOUT=A //SYSTERM DD SYSOUT=A //SYSUDUMP DD SYSOUT=A //ITEM DD DSN=yourid.ksds.vsamfile,DISP=SHR //UPDATE DD * LIST OF RECORDS TO BE ADDED OR UPDATED CHEMICAL FUEL 45 77 80 GASOLINE CHEAP CHEMICAL FUELS 55 67 81 PROPANE CHEAP /* //DELETE DD * LIST OF KEYS OF RECORDS TO BE DELETED AUTO STARTER BOGUS ID /* //The JCL file called KSDSCL compiles and links
KSDS
.
//*------------------------------------------------------------------ //* COMPILE AND LINK THE PROGRAM //*------------------------------------------------------------------ //CL EXEC LC370CL //C.SYSLIN DD DSN=your.obj.dataset(KSDS),DISP=OLD //C.SYSIN DD DSN=your.source.dataset(KSDS),DISP=SHR //LKED.SYSLIN DD DSN=your.obj.dataset(KSDS),DISP=OLD //LKED.SYSLMOD DD DSN=your.load.dataset(KSDS),DISP=SHR //
fflush
does not
seem to guarantee this. What can I do?
A. It is true that using fflush
on a file does not
guarantee that output data are immediately written to disk. For a
file accessed as a binary stream, fflush
passes the current
output buffer to the system I/O routines, but there is no guarantee
that the data are immediately transmitted. (For instance, under MVS
the data are not written until a complete block of data has been
accumulated.) This situation is not limited to MVS and CMS. For
instance, fflush
under most versions of UNIX simply transfers
the data to a system data buffer, and there is no guarantee that the
data are immediately written to disk.
Even after output data are physically written to disk, they may be inaccessible after a system failure. This is due to the details of the way that disk space is managed under MVS and CMS. For instance, under CMS, the master file directory for a minidisk maps the blocks of data associated with each file. If a program adds new data blocks to a file, but the system fails before the master file directory is updated, the new blocks are inaccessible. CMS only updates the master file directory when a command terminates, or when the last open file on the disk is closed by CMS. A similar problem occurs under MVS with the end-of-file pointer in the data set label, which is updated only when the file is closed.
The recommended solution to this problem is the nonportable SAS/C
function afflush
. This function is similar to fflush
but guarantees that all data has been written to disk and that
the master file directory or VTOC has been updated to contain
current information. For programs using UNIX style I/O, the function
fsync
can be used in the same way.
A.A simple COBOL file copy and a simple C file copy are not comparable. COBOL I/O can be implemented much more efficiently on the 370 than C standard I/O because the COBOL I/O model is a record I/O model, corresponding closely to the I/O model implemented by the operating system. COBOL clauses such as "RECORD CONTAINS 80 CHARACTERS" and "BLOCK CONTAINS 40 RECORDS" allow the compiler to generate code that invokes the operating system's access methods directly.
C standard I/O, on the other hand, is stream-oriented. The C library
cannot call the access method directly because of the need to support
text file translation and complicated interfaces like ungetc
,
fflush
, and fseek
. Even if the program does not use
these capabilities, the library must still support them. In addition,
because of the requirement that compiled code be system independent,
and because the meanings of attributes like reclen
and
blksize
differ from MVS to CMS, C I/O cannot be optimized based
on knowledge of these attributes, as COBOL can.
The SAS/C OS and CMS low-level I/O functions enable you to access files at the same low level used by COBOL. When you use low-level I/O in C, you will find performance similar to that of COBOL. If you do not want to use low-level I/O, then refer to the next question in this section.
Note: The discussion here applies when you compare C I/O to other languages such as PL/I. However, the difference is not as great because these languages also compare unfavorably to COBOL, and for the same reason: their I/O models are not as close to the 370 model as COBOL's, although they are closer than the C model.
A. Here are some recommendations for improving the performance of I/O. Each recommendation should be evaluated individually because many are not relevant to every application:
fgets
or fputs
to
process data one line at a time and it is not required to be portable,
investigate whether it could be changed to use afread
or
afwrite
instead.
fgetc
and fputc
functions. The C standard requires that
these functions generate an actual function call, which introduces a
substantial overhead for each character read or written. If you must
do I/O one character at a time, use getc
and putc
, which
generate inline code and cause a subroutine call only when necessary
to read or write a new buffer. For debugged programs that use
getc
and putc
, you can #define
the symbol
_FASTIO
where appropriate. This increases the speed of
getc
and putc
by removing checks for invalid FILE
pointers.
fread
and fwrite
or afread
and
afwrite
. Reading less than one record at a time increases the
number of subroutine calls required and, therefore, decreases performance.
Reading more than one record at a time is not harmful, but it is not
particularly beneficial, because data are buffered within the library
one record at a time.
printf
. printf
is one of the
most expensive routines at run time, because of the need to interpret
the format string. In many cases, you can use a faster routine to do
the same thing. For instance, use puts( str
)
instead of
printf("%s\n", str)
.
A. Process the file using binary I/O. When you process a
record format A file with text I/O, the library manages the carriage
control for you, so it can correctly handle C control characters like
'\f'
and '\r'
. But when you use binary I/O, the
library leaves the data alone, so you can process the file as you see
fit.
A. The library functions afreadh
and afread
are well-suited to reading SMF records. Simple SMF records consist of
a header portion containing data items common to all records,
including a record type, followed by data whose format is record-type
dependent. Complex SMF records may contain subrecords that occur a
varying number of times. For instance, a type 30 record contains an
I/O subrecord (or section) for each DD statement opened by a job. To
process a simple SMF record in C, use afreadh
to read the
common record header, and then use afread
to read the
remainder. The length specified for the call to afread
is the
largest length possible for the record type. (afread
returns
the amount of data actually read.)
To process a complex SMF record in C, use afreadh
to read each
section of the record, using information from previous sections to
allow you to map the record. For instance, if the record header
indicates you are reading a type 30 record, then you would call
afreadh
again to read the common header for a type 30 record.
This header may indicate you have three sections of type A and two of
type B. You can then call afreadh
three times to read the A
sections, and two more times to read the B sections.
Note:
Using afread
to read any of the nonheader information is not
necessary.
A. You hardly need to do anything special at all. The main source of I/O incompatibility between MVS and CMS is filename syntax. By default, filenames are interpreted as DDnames under MVS, but as CMS disk filenames under CMS. Furthermore, CMS and MVS naming conventions are different. Here are three possible strategies for solving this particular problem (there may be more):
tso
or cms
style filenames under both systems, and
only use names that are acceptable under both systems. For example,
use tso:config.data
, not tso:config.user.data
, which is
unacceptable under CMS. Note that this may limit your program to
being used from TSO under MVS.
sysname
and envname
functions to determine at
run time whether you are running under MVS or CMS and choose
filenames accordingly. This is the most flexible solution because
you can choose the filenames most appropriate for each system
independently.
creat
function, followed by
close
, to create a file without putting any data in it. But
when I open it read-only later, I get a message that the file doesn't
exist. What is wrong?
A. You attempted to create an empty file; that is, one containing no characters. CMS does not permit such files to exist. Additionally, for reasons explained in detail in Technical Background , under MVS, empty files with sequential organization are treated by the library as not existing. The ISO/ANSI C Standard permits this interpretation because of the existence of systems like CMS.
You can avoid this restriction in two ways:
'\0'
) and ignore this character when you read the file later.
A. You can use the quiet
function to suppress all
library diagnostics or to suppress diagnostics at particular points in
execution. If you use quiet
, you may occasionally run into
errors whose cause cannot be immediately determined. When this
happens, you can use the =warning
run-time option to override
quiet
and obtain a library diagnostic without having to
recompile the program.
kretrv
or kinsert
fails. How can I find this information?
A. When the SAS/C library invokes an operating system routine, such
as a VSAM macro, and the macro fails, information about the failure
is saved in a system macro information structure. You can access
the name of the macro that most recently failed via the library
macro __sysmi_macname
and its return code via __sysmi_rc
. For more
information on this facility, see System Macro Information .
fopen
call
fails if another user has the PDS allocated, even if it is allocated as SHR.
How can I write to the PDS if it shared with another user?
A. If more than one user writes to the same PDS at the same time, the results are unpredictable. Generally, both members will be damaged. For this reason, when a PDS member (or any other MVS data set) is opened for output, the library allocates the data set to OLD to make sure that no one else writes to it at the same time. In some cases, this may be overprotective, but it prevents file damage from unintended simultaneous access.
In your application, if you are certain that only one user
can open the file for output at a time, you should access the file
through a DDname rather than through a data set name. You can define the
DDname using JCL or a TSO ALLOCATE command as SHR, and the library will not
alter this allocation when the DDname is opened. In TSO, you can
use the system
function to allocate a data set to a specific DDname.
Also, in any environment, you can use the osdynalloc
function to
dynamically allocate the data set.
Note: With a PDSE, it is possible to simultaneously write to distinct members. Even with a PDSE, the effects are unpredictable if the same member is opened by more than one user for output at the same time.
Copyright (c) 1998 SAS Institute Inc. Cary, NC, USA. All rights reserved.