Chapter Contents |
Previous |
Next |
I/O Functions |
Standard I/O Overview |
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 USS 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 Standard I/O Functions.
*
are not
defined in the ANSI standard. Programs that use them should include
lcio.h
rather than
stdio.h
.
+
may be
used with files opened for keyed access.
UNIX Style I/O Overview |
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 USS hierarchical file system.
The functions supported by UNIX style
I/O and their purposes
are listed in UNIX Style I/O Functions.
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.
*
are not
defined by UNIX operating systems.
+
are also
supported for sockets.
-
are supported
only for USS files.
Opening Files |
Although
there are several different functions that you can call to open a file (for
example,
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
The general
form of a SAS/C filename is [//]
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 USS I/O Considerations for a discussion
of filenames for
posix
-compiled programs.
The
style:
part of the filename is optional. If no style is
specified, the style is chosen as follows:
//
prefix, the default style is
tso
in OS/390, 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 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 OS/390, and
cms
under
CMS. This means that by default, filenames are interpreted as DDnames under
OS/390 and as fileids or device names under CMS.
As an aid to migration of programs between OS/390 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 Filename specification under OS/390 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.
The
library supports four primary styles of filenames under OS/390:
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 USS 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
USS 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(member-name)
references a member of the PDS identified by the DDname. For example,
the filename
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 USS, another
ddn
-style filename is possible:
ddname/filename
Here,
ddname
is a
valid OS/390 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 USS
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 USS I/O Considerations.
dsn-style filenames 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=classtmpname
A
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 USS 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=class
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.
A
dsn
-style filename
of
&tmpname
references a new temporary data set, whose name is
&tmpname
. The name is limited to
eight characters.
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
OS/390 batch (or under the USS 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 USS 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 OS/390 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 USS
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.
The library
supports five primary styles of filename under CMS:
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:
filename [filetype [filemode]] [(MEMber member-name)]]
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:
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:
filename [.filetype [.filemode]] [(member-name)]
This form of filename is interpreted in
exactly the same way as the corresponding standard name. For example,
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.
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 (member member-name) | %MACLIB (member-name) |
TXTLIB (member member-name) | %TXTLIB (member-name) |
Also, an empty filename (
""
)
may be used to open a dummy file.
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 OS/390 PDSs, and to the CMS terminal. (All forms have approximately
the same meaning as under OS/390.) For more information, see Filename specification under OS/390.
* *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(member-name)
references a member of the MACLIB, TXTLIB, or OS/390 PDS identified
by the DDname. For example, the filename
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
OS/390,
the CMS version of the library accepts
tso
-style
filenames where possible, by transforming them into equivalent
cms
-style filenames. See Filename specification under OS/390 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.
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:
Note:
UNIX I/O does not support keyed
streams.
Standard I/O and UNIX Style I/O Open Modes 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.
When you use
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 USS hierarchical file system files.
"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.
When you
use
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
amparm=value
, separated by commas (for example,
"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 OS/390 file will
be created when the filename is specified in
dsn
or
tso
style. All amparms are
accepted under both OS/390 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.
recfm=f/v/u
reclen=nnn|x
blksize=nnn
keylen=nnn
keyoff=nnn
org=value
overjcl=no | yes
print=yes|no
page=nnn
pad=no|null|blank
trunc=yes|no
grow=yes|no
order=seq|random
commit=yes|no
dirsearch=value
share=ispf|alloc|rls
eof=string
prompt=string
bufnd=nnn
bufni=nnn
bufsp=nnn
bufsize=nnn
bufmax=n
See Terminal I/O for a discussion of the
eof
and
prompt
amparms. See
VSAM-related amparms for a discussion of the VSAM Performance
amparms.
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.
To
resolve conflicts between the file characteristics, recfm
, reclen
, and blksize
, when they
are specified in the JCL and the program, you can use the amparm overjcl
to indicate whether the file characteristics specified
in the JCL or the program have precedence. overjcl
is effective only for sequential files opened with an open mode of w
, wb
, w+
,
or w+b
. For non-sequential files, such as partitioned
data sets, or for input files, the JCL always has precedence. Values for overjcl contains the values for overjcl
and
their descriptions.
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 OS/390,
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.
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 OS/390, 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 OS/390 and CMS,
despite the different definitions of LRECL in the two systems.
Under OS/390, 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 OS/390 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 USS 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 OS/390 or CMS, a large
blksize
specification
improves performance at the cost of additional memory for buffers.
The
blksize
amparm
under OS/390 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:
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 OS/390.
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 OS/390
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.
dirsearch
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.
For each of these amparms, processing is as follows:
recfm
|
If you specify
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
|
reclen
|
If you specify
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 OS/390, 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
VSAM linear data sets are always considered to have
|
blksize
|
If you specify
blksize=nnn
, a warning is generated only
if the actual blksize is greater than that specified. |
recfm
specifications
of
f
,
v
,
and
u
become OS/390 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
, OS/390 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 OS/390 BLKSIZE of
nnn
. If the requested
BLKSIZE is not compatible with the chosen RECFM and LRECL, the BLKSIZE is
rounded, if possible.
"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 OS/390 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.
For files with RECFM A, space for the control character
is included in the LRECL, but not in any
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 USS 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 OS/390, 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 USS HFS, only
trunc=no
is supported. For all other OS/390 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
.
share=ispf
amparm allows a program to write to an ISPF member without allocating
the entire dataset as "OLD". Other programs can continue to read
and write to other members while the program updates the designated member.
int cardfd; cardfd = aopen("dsn:sas.test.c(hello)", O_RDWR, "share=ispf");
Note:
Opening a file with the
share=ispf
amparm allows a PDS to be shared by several programs or
users but must be used carefully.
Using
share=ispf
allows a PDS to be allocated as SHR and used by cooperating programs, that
is, by the ISPF editor and utilities, by other SAS/C programs which open specifying
share=ispf
, and by any other applications which
observe the ISPF protocols.
Using
share=ispf
does not prevent access by applications that do not observe the ISPF protocols.
Such access may cause file damage or loss of data.
While a SAS/C program has a PDS member open with
share=ispf
, an attempt by an ISPF user to save
another member of the same PDS will wait until the SAS/C program closes the
member. Similarly, when one SAS/C program has a PDS member open using
share=ispf
, any other SAS/C program which opens
the same PDS with
share=ispf
will wait
until the first program closes its member. For this reason, programs which
use
share=ispf
should be designed to keep
such files open for as small an interval of time as possible.
share=alloc
amparm is used to open a new or existing file by DSN as shared. Here
is an example:
int cardfd; cardfd = aopen("dsn:sas.test", O_CREAT | O_RDWR | O_APPEND, "recfm=f,reclen=80,share=alloc");
share=alloc
amparms should be used
only when there is no risk of multiple simultaneous access, when the program
itself synchronizes access to the file ( for example, using the OS/390 ENQ
macro, or where the risk of occassional loss of data or file damage is considered
acceptable.
shr=rls
shr=rlsread
The
share=rls
or
share=rlsread
amparm specifies that VSAM record
level sharing protocols are to be used for processing the dataset. The RLS
protocols are available for OS/390 only with DF/SMS Version 1, Release 3 (or
higher) installed or OS/390 Release 2, which includes it. In addition, using
the RLS feature requires supporting hardware (SYSPLEX Coupling Facility (CF))
and proper site installation configuration of DF/SMS.
This option is meaningful only for VSAM files and is
equivalent to coding
MACRF=(RLS)
for
share=rls
or
MACRF=(RLS)
,
RLSREAD=CRI
for
share=rlsread
on an ACB assembler macro used to open the VSAM file.
RLS implies the use of cross-system record level locking as opposed to CI
locking, uses CF for cross-system buffer consistency with a coordinated system
wide local buffer cache. The amparm
share=rlsread
also specifies that consistent read integrity (record locking during
all reads) be used for read requests, even if the dataset is opened for read
only (
mode=r
) or
K_noupdate
flag is specified with
kretrv
. Specifying
share=rlsread
overrides
any RLS JCL specification. VSAM RLS supports only cluster or path level access
(that is, no individual data, index, or alternate index component access)
and does not support linear datasets or datasets which are defined with an
imbedded index or a keyrange. Recoverable datasets, that is, datasets defined
with the IDCAMS LOG(UNDO) or LOG(ALL) attribute, can only be opened for read
(
mode=r
) because of the CICS file control
and logging requirements. Nonrecoverable datasets, that is, LOG(NONE), or
the default can be opened in any mode with the LOG(NONE) attribute since no
CICS file control or logging is required for these datasets.
share=rls
or
share=rlsread
causes VSAM to ignore any bufnd/bufni/bufsp
specification. However, in
general, the
VSAM RLS feature is transparent from a C library VSAM file function usage
standpoint since the protocols are implemented at the operating system level
and not in the library except for specifying the ACB options. However, a couple
of pitfalls are worth mentioning. File opens with VSAM RLS will fail if there
are nonRLS users of the dataset, and conversely nonRLS opens will fail if
there are RLS users of the dataset. While OS/390 recovery is usually satisfactory,
it is possible for system crashes and/or abends to leave the dataset locked
out from nonRLS access, and locked records unavailable to RLS users, until
the IDCAMS utility is called to fix the problem.
File creation amparms These amparms are used under OS/390 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 OS/390, but in these cases they are ignored.
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
The meanings of these amparms and their defaults are discussed in the following list. Default values are site-specific and may have been changed at the time the SAS/C library was installed. Consult your SAS Software Representative for C compiler products to determine the defaults at your site.
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 OS/390 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.
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.
recfm
|
If
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
|
For files with fixed length records,
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,
|
blksize
|
The
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,
|
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
|
specifies the maximum (and minimum,
for
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
|
specifies the buffer size used by the library when performing I/O operations on the file. |
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 - OS/390 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.
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.
File Positioning |
As described in Technical Background, the 370 operating systems provide a relatively inhospitable environment for the standard C file positioning functions. For this reason, you should read this section carefully if your application makes heavy or sophisticated use of file positioning. Some understanding of OS/390 or CMS I/O internals is helpful.
When UNIX
style I/O is used to access a file as binary, file
positioning is fully supported with the
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 USS 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.
Standard I/O supports the
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 USS 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 OS/390 Files with Restricted Positioning and CMS Files with Restricted Positioning.
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.
In many cases, when you process a file with standard I/O, you
can use the
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
USS 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 USS 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:
Even for files that exceed one of these limits,
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 OS/390 Files with Restricted Positioning and
CMS Files with Restricted Positioning.
Note:
The warnings given in the previous section for
use of
fsetpos
are equally applicable to
fseek
.
Terminal I/O |
'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.
When
you use
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.
When you use
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
|
specifies an end-of-file string. |
prompt=string
|
specifies a terminal input prompt. |
The following amparms are ignored if the file to be opened is not the terminal:
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 OS/390, 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.
As
an aid to porting existing programs to the USS shell, the SAS/C library allows
the filename
*
in
ddn
,
dsn
, or
tso
style to access the USS 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 OS/390
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 USS.
Using the USS Hierarchical File System |
The USS Hierarchical File System (HFS) is an
implementation of a UNIX file system under OS/390. In this file system, a
directory is a special kind of file that contains names and other information
about a group of files. The root directory is at the top of
the hierarchy; thus, the root directory is not contained in any other directory.
Files within the file system are identified by a pathname, which consists
of the series of directories (beginning with the root directory) that lead
to a file. Directory names are separated by slashes (/), and the filename
itself comes last. For example, the pathname
/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.
/dev/tty
).
/dev/null
). Output to
/dev/null
is discarded; input from
/dev/null
produces
end-of-file.
I/O to the hierarchical
file system is implemented by USS OS/390 via a set of services that correspond
to traditional UNIX unbuffered I/O calls, such as
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
OS/390 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 USS 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.
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
.
USS I/O Considerations |
SAS/C implements
two different file-naming conventions: one for use by traditional SAS/C programs,
and one for POSIX-oriented programs. The choice of naming convention depends
on whether any compilation in the main program load module specifies the
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
OS/390) 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 OS/390-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 OS/390 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.
Enhancements to OS/390 JCL and dynamic allocation facilities
for USS OS/390 allow DD statements to be allocated to HFS files or directories.
Parameters on the DD statement correspond roughly to arguments to the
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 OS/390 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.
Until
the availability of USS, it was often convenient to replace the use of directories
in UNIX applications with PDS's when porting them to OS/390. Consider porting
a UNIX C compiler to the mainframe. In UNIX, a system header file like
<stdio.h>
is simply a file in a particular
directory. In OS/390, 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 USS, 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/filename
Here,
ddname
is a
valid OS/390 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 OS/390 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.
When a new process is created by
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 OS/390 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 OS/390 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).
When a
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.
Whenever a file is opened
using the
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
USS, 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 USS 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 USS limit. File descriptors in the valid USS
range can be assigned to files other than USS 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.
In both of these cases, confusion can occur. For example,
if file descriptor 4 is assigned to a socket and you call
open
, USS 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 USS 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 USS
associates the file descriptor with
/dev/null
, it will not be possible for USS to associate the descriptor with
any other file. This technique also ensures that socket numbers are assigned
in accordance with USS rules.
You should note the following points about file descriptor allocation:
open
function to open OS/390 files for UNIX style I/O, very large file
descriptors are assigned, thereby preventing these files from affecting the
USS 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, stdout, and stderr |
The C
language definition
specifies that when program execution begins, three standard streams should
be open and available for program use. These are
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 OS/390-batch.
Under CMS, all three standard streams are, by default,
directed to the terminal. Under OS/390, 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 USS OS/390, 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 OS/390, 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 OS/390 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.
Because the standard streams are initialized by the library before
execution rather than by an explicit call to
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 the
SAS/C Compiler and Library User's Guide. 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 the
SAS/C Compiler and Library User's Guide.
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 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 OS/390 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.
In UNIX
operating systems and other similar systems, it is possible
to access the standard streams using low-level I/O, specifying file numbers
0, 1, and 2 for
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 USS, 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.
I/O Error and Interrupt Handling |
UNIX style I/O includes no specific error-handling
functions or features. If a
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.
As
stated earlier, after a file has been opened, a pointer to a
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 OS/390) 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.
In
a program that handles asynchronous signals, it is possible for a library
I/O routine to be interrupted by a signal. When a library I/O routine is
interrupted, an interrupt flag is set for the file until the signal handler
returns. Any attempt to use the file while the interrupt flag is set is treated
as an error (and therefore sets the error flag) to avoid damage to the file
or to library file control blocks. The situations in which the interrupt
flag is most likely to be set are after using
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 OS/390 and CMS (except with
USS), 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 OS/390 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.
Augmented Standard I/O |
Some 370 I/O applications are beyond the scope of standard I/O
because the record concept is absent from the C language. Consider, for example,
a program to make an exact copy of any input file, including duplicating the
input file's record structure. Such a program could not be written using
binary file access because all information about the record structure of the
input file would be lost. It also could not be written using text access,
because if there were any new-line characters in the input file, they would
be interpreted by the program as record breaks, and the output file would
contain more records than the input file. The functions
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.
The
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.
Advanced OS/390 I/O Facilities |
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.
When
an I/O operation requires additional space to be allocated to a file but space
is unavailable, the program is normally terminated by the operating system
with a B37, D37, or E37 ABEND. The SAS/C library intercepts these ABENDs
and treats them as error conditions. It sets the error flag for the affected
file and returns an error code from the failing I/O function. The ABEND is
intercepted using a DCB ABEND exit, not a STAE or ESTAE, and functions correctly
even if you use the
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
PDSEs are compatible in most ways with standard PDSs, they do not support
either BSAM INOUT or OUTIN processing, which enable a member to be read and
written at the same time. When the
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.
The SAS/C Library
defines the amparm
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.
When a new partitioned
data set is created, the decision to create it as a regular PDS or as a PDSE
is normally determined by your site, possibly based on data set name or other
data set characteristics. In some cases, you may want to force a particular
choice. The
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
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
|
specifies the size, in bytes, of a DIV window. |
bufmax=n
|
specifies the number of DIV windows. |
The value specified for
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.
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.
Advanced CMS I/O Facilities |
This section discusses several advanced I/O tasks under CMS,
such as use of
xed
style files, extending
global MACLIB/TXTLIB processing, and using the CMS shared file system.
The
CMS version of the library supports access to files being processed by XEDIT
with the
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.
As described previously, you can
use the
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(name)
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.
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(name)
are the same:
FILEDEF CMSLIB DISK MYLIB1 TXTLIB A FILEDEF CMSLIB DISK MYLIB2 TXTLIB A (CONCAT GLOBAL TXTLIB LC370 CMSLIB
FILEDEF CMSLIB DISK filename MACLIB fm DSN OS-data-set-name TXTLIB
Note:
You cannot use an OS PDS as
a global MACLIB/TXTLIB in a XA-mode virtual machine.
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.june
When 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.
The
format of the name of a shared file, as specified to
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.)
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.
When you open an
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
.
To process a CMS Shared File System directory, you open an
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
:
If you specify no value for
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] |
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); }
Using VSAM Files |
You can access all
kinds of VSAM files using the standard C I/O
functions defined by
<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 OS/390 I/O Facilities for more information on accessing LDS files.
Because
standard C I/O assumes that files are simply sequences of characters stored
at unchanging offsets in the file, standard C is not suited to exploiting
VSAM capabilities. For this reason, the SAS/C library provides a keyed-access
mode for VSAM files designed to take advantage of their unique properties.
Keyed access is an alternative to text or binary access, specified by the
open mode argument to the
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. */
struct { char name[20]; char address[50]; short age; } employee; kretrv(&employee, NULL, 0, f);
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.
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.
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.
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.
The following are considerations unique to processing a KSDS:
ksearch
function description for further details.
The following are considerations unique to processing an ESDS:
kinsert
and is not generally predictable before
the record is inserted.
The following considerations are unique to processing an RRDS:
ksearch
function description for
further details.
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.
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.
For some VSAM files, processing performance
can be improved by allocating storage for additional I/O buffers. SAS/C allows
you to specify buffer allocation for VSAM files using the following amparms.
(Note that the
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:
ddn:ITEM | the VSAM file being used |
ddn:DATA | where records for initially loading the VSAM file are stored |
ddn:UPDATE | contains the records for loading and updating |
ddn:DELETE | contains the keys for the records being deleted |
#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("\n\nDo some searching"); memcpy(key, "CHEMICAL FUEL ", KEYSIZE); key[KEYSIZE]='\0'; /* Terminate the key. */ printf("Search for %s\n", key); ksearch(key, 0, K_noupdate | K_exact, vfptr1); memcpy(key, "HOUSEHOLD PAN ", KEYSIZE); key[KEYSIZE]='\0'; /* Terminate the key. */ printf("Now Search for %s\n", key); ksearch(key, 0, K_noupdate | K_exact, vfptr2); /* Retrieve the records found. */ puts("\n\nOK, 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%s\n", vbuffer); offset = ktell(vfptr1); printf("Its RBA is: %lu\n", 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%s\n", vbuffer); offset = ktell(vfptr1); printf("Its RBA is: %lu\n", 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%s\n", vbuffer); memcpy(vbuffer, buffer, VBUFSIZE); vbuffer[VBUFSIZE]='\0'; printf("With:\n%s\n", 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%s\n",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%s\n", vbuffer); kdelete(NULL, vfptr1); } else printf("Couldn't find a record with the key: %s\n", key); } fclose(fptr); } /* The function printfil prints the contents of the VSAM file. */ | void printfil() { int i=0; puts("\n\nHere 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 %s\n", 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
.
//*------------------------------------------------------------------ //* 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 /* //
SAS/C I/O Frequently Asked Questions |
The following are frequently asked questions about SAS/C
I/O:
Q.
My program runs for days at
a time. I want to be sure that all data I write to my files are actually
stored on disk in case the system fails while the program is running.
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 OS/390 the data are not written until a
complete block of data has been accumulated.) This situation is not limited
to OS/390 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.
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.
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 OS/390 to CMS, C I/O cannot be optimized based on knowledge
of these attributes, as COBOL can.
Q.
What can I do to improve the
performance of I/O?
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.
Q.
How can I best process SMF
records using C I/O?
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.
Q.
What can I do to make my I/O portable between OS/390 and
CMS?
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 OS/390.
sysname
and
envname
functions to determine at run
time whether you are running under OS/390 or CMS and choose filenames accordingly.
This is the most flexible solution because you can choose the filenames most
appropriate for each system independently.
Q.
I call the
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
OS/390, 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.
Q.
I'm converting an assembler
VSAM application to SAS/C, and I need to know the return code set by VSAM
when a function like
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.
Q.
When I open a PDS member for output, the
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?
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.
Chapter Contents |
Previous |
Next |
Top of Page |
Copyright © 2001 by SAS Institute Inc., Cary, NC, USA. All rights reserved.