sfio(3)
NAME
sfio - safe/fast string/file input/output
SYNOPSIS
LIBRARIES
#include <sfio.h>
libsfio.a -lsfio
libstdio.a -lstdio
libsfio-mt.a -lsfio-mt
libstdio-mt.a -lstdio-mt
DATA TYPES
Void_t;
Sfoff_t;
Sflong_t;
Sfulong_t;
Sfdouble_t;
Sfio_t;
Sfdisc_t;
ssize_t (*Sfread_f)(Sfio_t*, Void_t*, size_t, Sfdisc_t*);
ssize_t (*Sfwrite_f)(Sfio_t*, const Void_t*, size_t, Sfdisc_t*);
Sfoff_t (*Sfseek_f)(Sfio_t*, Sfoff_t, int, Sfdisc_t*);
int (*Sfexcept_f)(Sfio_t*, int, Void_t*, Sfdisc_t*);
Sffmt_t;
int (*Sffmtext_f)(Sfio_t*, Void_t*, Sffmt_t*);
int (*Sffmtevent_f)(Sfio_t*, int, Void_t*, Sffmt_t*);
SFIO_VERSION
BIT FLAGS
SF_STRING
SF_READ
SF_WRITE
SF_APPENDWR (SF_APPEND)
SF_LINE
SF_SHARE
SF_PUBLIC
SF_MALLOC
SF_STATIC
SF_IOCHECK
SF_WHOLE
SF_MTSAFE
SF_IOINTR
OPENING/CLOSING STREAMS
Sfio_t* sfnew(Sfio_t* f, Void_t* buf, size_t size, int fd, int flags);
Sfio_t* sfopen(Sfio_t* f, const char* string, const char* mode);
Sfio_t* sfpopen(Sfio_t* f, const char* cmd, const char* mode);
Sfio_t* sftmp(size_t size);
int sfclose(Sfio_t* f);
THREAD SAFETY
int sfmutex(Sfio_t* f, int type);
SFMTX_LOCK
SFMTX_TRYLOCK
SFMTX_UNLOCK
SFMTX_CLRLOCK
INPUT/OUTPUT OPERATIONS
int sfgetc(Sfio_t* f);
int sfputc(Sfio_t* f, int c);
int sfnputc(Sfio_t* f, int c, int n);
int sfungetc(Sfio_t* f, int c);
Sfulong_t sfgetm(Sfio_t* f, Sfulong_t max);
int sfputm(Sfio_t* f, Sfulong_t v, Sfulong_t max);
Sfulong_t sfgetu(Sfio_t* f);
int sfputu(Sfio_t* f, Sfulong_t v);
Sflong_t sfgetl(Sfio_t* f);
int sfputl(Sfio_t* f, Sflong_t v);
Sfdouble_t sfgetd(Sfio_t* f);
int sfputd(Sfio_t* f, Sfdouble_t v);
char* sfgetr(Sfio_t* f, int rsc, int type);
ssize_t sfputr(Sfio_t* f, const char* s, int rsc);
Sfoff_t sfmove(Sfio_t* fr, Sfio_t* fw, Sfoff_t n, int rsc);
ssize_t sfread(Sfio_t* f, Void_t* buf, size_t n);
ssize_t sfwrite(Sfio_t* f, const Void_t* buf, size_t n);
Sfoff_t sfseek(Sfio_t* f, Sfoff_t offset, int type);
Void_t* sfreserve(Sfio_t* f, ssize_t n, int type);
DATA FORMATTING
int sfscanf(Sfio_t* f, const char* format, ...);
int sfsscanf(const char* s, const char* format, ...);
int sfvsscanf(const char* s, const char* format, va_list args);
int sfvscanf(Sfio_t* f, const char* format, va_list args);
int sfprintf(Sfio_t* f, const char* format, ...);
char* sfprints(const char* format, ...);
char* sfvprints(const char* format, va_list args);
ssize_t sfaprints(char** sp, const char* format, ...);
ssize_t sfvaprints(char** sp, const char* format, va_list args);
int sfsprintf(char* s, int n, const char* format, ...);
int sfvsprintf(char* s, int n, const char* format, va_list args);
int sfvprintf(Sfio_t* f, const char* format, va_list args);
Sffmt_t;
SFFMT_LEFT
SFFMT_SIGN
SFFMT_BLANK
SFFMT_ZERO
SFFMT_THOUSAND
SFFMT_LONG
SFFMT_LLONG
SFFMT_SHORT
SFFMT_LDOUBLE
SFFMT_IFLAG
SFFMT_ALTER
SFFMT_SKIP
SFFMT_ARGPOS
SFFMT_VALUE
int (*Sffmtext_f)(Sfio_t* f, Void_t* v, Sffmt_t* fe);
int (*Sffmtevent_f)(Sfio_t* f, int type, Void_t* v, Sffmt_t* fe);
void va_copy(va_list to, va_list fr);
long sffmtversion(Sffmt_t* fe, type);
BUFFERING, SYNCHRONIZATION
Void_t* sfsetbuf(Sfio_t* f, Void_t* buf, size_t size);
int sfsync(Sfio_t* f);
int sfpoll(Sfio_t** flist, int n, int timeout);
Sfio_t* sfpool(Sfio_t* f, Sfio_t* poolf, int mode);
int sfpurge(Sfio_t* f);
DISCIPLINE, EVENT HANDLING
Sfdisc_t* sfdisc(Sfio_t* f, Sfdisc_t* disc);
int sfraise(Sfio_t* f, int type, Void_t* data);
ssize_t sfrd(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc);
ssize_t sfwr(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc);
Sfoff_t sfsk(Sfio_t* f, Sfoff_t offset, int type, Sfdisc_t* disc);
SF_NEW
SF_READ
SF_WRITE
SF_SEEK
SF_CLOSING (SF_CLOSE)
SF_DPUSH
SF_DPOP
SF_DPOLL
SF_DBUFFER
SF_SYNC
SF_PURGE
SF_FINAL
SF_READY
SF_LOCKED
SF_ATEXIT
SF_EVENT
STREAM CONTROL
int sfresize(Sfio_t* f, Sfoff_t size);
int sfset(Sfio_t* f, int flags, int i);
int sfsetfd(Sfio_t* f, int fd);
Sfio_t* sfstack(Sfio_t* base, Sfio_t* top);
Sfio_t* sfswap(Sfio_t* f1, Sfio_t* f2);
STREAM INFORMATION
Sfoff_t sfsize(Sfio_t* f);
Sfoff_t sftell(Sfio_t* f);
ssize_t sfvalue(Sfio_t* f);
int sffileno(Sfio_t* f);
int sfstacked(Sfio_t* f);
int sfeof(Sfio_t* f);
int sferror(Sfio_t* f);
int sfclrerr(Sfio_t* f);
int sfclrlock(Sfio_t* f);
int sfnotify(void (*notify)(Sfio_t* f, int type, int fd));
MISCELLANEOUS FUNCTIONS
ssize_t sfmaxr(ssize_t maxr, int s);
ssize_t sfslen();
int sfulen(Sfulong_t v);
int sfllen(Sflong_t v);
int sfdlen(Sfdouble_t v);
ssize_t sfpkrd(int fd, Void_t* buf, size_t n,
int rsc, long tm, int action);
FULL STRUCTURE SFIO_T
#include <sfio_t.h>
#define SFNEW(buf,size,file,flags,disc)
EXAMPLE DISCIPLINES
#include <sfdisc.h>
int sfdcdio(Sfio_t* f, size_t bufsize);
int sfdcdos(Sfio_t* f);
int sfdcfilter(Sfio_t* f, const char* cmd);
int sfdcseekable(Sfio_t* f);
int sfdcslow(Sfio_t* f);
int sfdcsubstream(Sfio_t* f, Sfio_t* parent,
Sfoff_t offset, Sfoff_t extent);
int sfdctee(Sfio_t* f, Sfio_t* tee);
int sfdcunion(Sfio_t* f, Sfio_t** array, int n);
int sfdclzw(Sfio_t* f);
int sfdcgzip(Sfio_t* f, int flags);
STDIO-COMPATIBILITY
#include <stdio.h>
cc ... -lstdio -lsfio
cc ... -lstdio-mt -lsfio-mt
DESCRIPTION
Sfio provides I/O functions to manage buffered streams. Each Sfio
stream is a file stream, representing a file (see open(2)), or a string
stream, representing a memory segment. Beyond the usual I/O operations
on streams, Sfio provides I/O disciplines for extended data processing,
stream stacks for recursive stream processing, and stream pools for
automatic data synchronization. Applications can extend the
sfprintf()/sfscanf() functions to define their own conversion patterns
as well as redefine existing ones.
A discipline defines analogues of the system calls read(2), write(2)
and lseek(2). Such system calls or their discipline replacements are
used to process stream data. Henceforth, ``system call'' will refer to
either a system call or its discipline replacement.
A system call is said to cause an exception if its return value is non-
positive. Unless overridden by exception handlers (see sfdisc()), an
interrupted system call (errno == EINTR on UNIX systems) will be auto-
matically reinvoked to continue the ongoing operation.
The buffer of a stream is typically a memory segment allocated via mal-
loc(3) or supplied by the application. File streams may also use mem-
ory mapping (mmap(2)) if that is more efficient. When memory mapping
is used, the underlying file should not be truncated while the stream
is active. Memory mapping can be turned off using sfsetbuf().
There are three standard streams: sfstdin for input (file descriptor 0
on UNIX systems), sfstdout for normal output (file descriptor 1), and
sfstderr for error output (file descriptor 2).
LIBRARIES
This version of Sfio can be built and used for both uni-threaded and
multi-threaded environments. In the former case, streams are not pro-
tected from simultaneous accesses by different threads. In the latter
case, a stream is typically locked with a mutex during access so that
another thread trying to access the same stream will block until the
mutex is released.
A program that does not use multiple threads can link with libsfio.a
while a program that uses multiple threads should link with libsfio-
mt.a. The libraries libstdio.a and libstdio-mt.a provide corresponding
Stdio functions to link with code already compiled using the native
header stdio.h instead of the one provided by Sfio.
DATA TYPES
Void_t*
This defines a type suitable to exchange data of unknown types between
application and Sfio. Void_t is a macro defined as void for ANSI-C and
C++ and char for other compilation environments.
Sfoff_t
This defines an integral type suitable to address the largest possible
file extent.
Sfulong_t, Sflong_t, Sfdouble_t
These are respectively the largest unsigned integer, signed integer,
and floating point value types on the local platform.
Sfio_t
This defines the type of a stream handle.
Sfdisc_t
ssize_t (*Sfread_f)(Sfio_t*, Void_t*, size_t, Sfdisc_t*)
ssize_t (*Sfwrite_f)(Sfio_t*, const Void_t*, size_t, Sfdisc_t*)
Sfoff_t (*Sfseek_f)(Sfio_t*, Sfoff_t, int, Sfdisc_t*)
int (*Sfexcept_f)(Sfio_t*, int, Void_t*, Sfdisc_t*)
Sfdisc_t defines a stream discipline structure. Sfread_f, Sfwrite_f
and Sfseek_f are the types of discipline functions to replace the sys-
tem calls: read(2), write(2) and lseek(2). Sfexcept_f is the type of
an event-handling function. See sfdisc() for more details.
Sffmt_t
int (*Sffmtext_f)(Sfio_t*, Void_t*, Sffmt_t*)
int (*Sffmtevent_f)(Sfio_t*, int, Void_t*, Sffmt_t*)
Sffmt_t defines a formatting environment that can be used to extend
scanning and printing in the sfprint()/sfscanf() functions. Sffmtext_f
and Sffmtevent_f define the types of extension functions definable in
Sffmt_t. See Sffmt_t below for more details.
SFIO_VERSION
This is a macro value of type long int that defines the current version
number of Sfio. For example, the Sfio2000's version number is 20000515L
(which also indicates its latest version date: 05/15/2000).
BIT FLAGS
A number of bit flags control stream operations. They are set either
at stream initialization or by calling sfset(). Following are the
flags:
SF_STRING:
The stream is memory-based.
SF_READ, SF_WRITE, SF_APPENDWR (SF_APPEND):
Flags SF_READ and SF_WRITE indicate readability and writability.
Flag SF_APPENDWR asserts that the stream is a file opened in
append mode (see open(2) and fcntl(2)) so that data is always
output at the end of file. On systems without direct support
for append mode, Sfio uses lseek(2) or its discipline replace-
ment to approximate this behavior.
SF_LINE:
The stream is line-oriented. For a SF_WRITE stream, this means
that buffered data is flushed whenever a new-line character, \n,
is output. For a SF_READ stream, SF_LINE is only significant
during calls to functions in the sfscanf() family. SF_LINE is
set on initialization of any stream representing a terminal
device.
SF_SHARE, SF_PUBLIC:
Flag SF_SHARE means that the underlying file descriptor is
shared by independent entities (for example, multiple pro-
cesses).
For a seekable file stream, SF_SHARE means that the logical
stream and the physical file positions will be made the same
before a system call to perform physical I/O. There are differ-
ent possibilities. If SF_PUBLIC is not set, the physical file
position is made equal to the logical stream position. If
SF_PUBLIC is set, there are two cases. If the physical file
position has changed from its last known position, the logical
stream position is made equal to the new physical file position.
Finally, if the physical file location remains the same as its
last known position, the physical file position is made the same
as the logical stream position.
For an unseekable stream (e.g., pipes or terminal devices), if
possible, SF_SHARE means that the block and record I/O opera-
tions (sfread(), sfwrite(), sfmove(), sfgetr(), sfputr(), sfre-
serve(), sfscanf() and sfvprintf()) will ensure: (1) after each
writing operation, the stream is synchronized and (2) each read-
ing operation only reads the requested amount. Note, however,
that (2) is not always possible without proper OS facilities
such as recv(2) or streamio(4).
A standard stream that is seekable will be initialized with
SF_SHARE|SF_PUBLIC.
SF_MALLOC:
The stream buffer was obtained via malloc(3) and can be reallo-
cated or freed.
SF_STATIC:
The stream structure should not be freed when closed
(sfclose()). This flag is used by an applications that allocate
their own stream structures. Such applications must use the
header file sfio_t.h instead of sfio.h.
SF_IOCHECK:
If the stream has a discipline exception handler, exceptions
will be raised in sfsync(), sfpurge() or before a system call
read(2) or write(2) (see sfdisc()).
SF_WHOLE:
This flag guarantees that data written in any single sfwrite()
or sfputr() call will always be output as a whole to the output
device. This is useful in certain applications (e.g., network-
ing) where a complex object must be output without being split
in different system calls. Note that the respective stream
still buffers data as much as the buffer can accomodate.
SF_MTSAFE:
This flag indicates that the respective stream may be accessed
by more than one threads. A mutex lock will be used to ensure
that only one thread at a time can access the stream. Note that
this flag can only be set at stream opening time (see sfopen(),
sfpopen() and sfnew()). Certain fast macro functions such as
sfgetc() and sfputc() will no longer behave as macros. Thus, an
application that requires such fast macro functions should leave
SF_MTSAFE off and performs explicit locking with sfmutex().
SF_IOINTR:
This flag indicates that I/O system calls should not be resumed
after being interrupted by signals. It is useful for aborting
I/O operations on such interruptions. Note, however, than cer-
tain operating systems (e.g., BSD Unix systems) may automati-
cally resume interrupted system calls outside the scope of the
library. On such systems, SF_IOINTR will be ineffective.
OPENING/CLOSING STREAMS
Sfio_t* sfnew(Sfio_t* f, Void_t* buf, size_t size, int fd, int flags)
This function creates or renews a stream. It returns the new stream on
success and NULL on error.
f: If f is NULL, a new stream is created. Otherwise, f is reused.
In this case, if flags does not have SF_EOF, f shall be closed
via sfclose() before being reused. During a stream renewal,
buffer, pool and discipline stack are preserved. Note that,
except for SF_STATIC streams, renewing a stream already closed
will result in undefined behavior.
buf, size:
These determine a buffering scheme. See sfsetbuf() for more
details.
fd: If SF_STRING is specified in flags, this is ignored. Otherwise,
fd is a file descriptor (e.g., from open(2)) to use for raw data
I/O. Note that Sfio supports unseekable file descriptors opened
for both read and write, e.g., sockets.
flags: This is composed from SF_EOF and bit values defined in the BIT
FLAGS section. Note, in particular, that a multi-threaded
application should set the bit SF_MTSAFE to protect the new
stream from being simultaneously accessed by multiple threads.
Sfio_t* sfopen(Sfio_t* f, const char* string, const char* mode)
If string is NULL, f is a file stream and mode does not imply a string
stream, sfopen() changes the modes of f according to mode. In this
case, sfopen() returns f on success and NULL on error. This somewhat
unusual usage of sfopen() is good for resetting certain predefined
modes in standard streams including text/binary and append that are
inherited from some parent process. Note also that SF_READ and
SF_WRITE can only be reset if the stream is not yet initialized.
sfopen() is normally used to create a new stream or renew a stream. In
this case, it returns the new stream on success and NULL on error.
Below are the meanings of the arguments:
f: This is treated as in sfnew().
string:
This is a file name or a string to perform I/O on. See above
for when this is NULL.
mode: This is composed from the set of letters {s, r, w, +, a, b, t,
x, m, u}. When conflicting options are present in the same mode
string, the last one will take effect.
s specifies opening a string stream. string can be a null-ter-
minated string or NULL. Specifying s alone is equivalent to
specifying sr. If s is not specified, string defines a file
name.
r and w specify read and write modes. Write mode creates and/or
truncates the given file to make an empty file. The + modifier
indicates that the stream is opened for both read and write.
a specifies append mode, i.e., data is always output at end of
file.
b and t specify binary and text modes.
x specifies exclusive mode, i.e., a file opened for writing
should not already exist.
m specifies that the stream needs to be protected from simulta-
neous accesses by multiple threads. This turns on the bit flag
SF_MTSAFE.
u specifies that the stream is guaranteed to be accessed by only
one thread at a time. The bit flag SF_MTSAFE is left off. The
absence of option m is the same as the presence of option u.
Sfio_t* sfpopen(Sfio_t* f, const char* cmd, const char* mode)
This function opens a stream that corresponds to the coprocess cmd.
The argument mode should be composed from r, w, and +. The argument f,
if not NULL, is a stream to be renewed (see sfnew()). sfpopen()
returns the new stream or NULL on error.
The standard input/output of cmd is connected to the application via a
pipe if the stream is opened for writing/reading. If the stream is
opened for both reading and writing, there will be two different asso-
ciated file descriptors, one for each type of I/O (note the effect on
sffileno()).
On opening a coprocess for writing (i.e., mode contains w or +), the
signal handler for SIGPIPE in the parent application will be set to
SIG_IGN if it is SIG_DFL at that time. This protects the parent appli-
cation from being accidentally killed on writing to a coprocess that
closes its reading end. Applications that need to detect such write
errors should use disciplines and exception handlers (see sfdisc()).
The command cmd is executed by an interpreter which is either /bin/sh
or an executable command defined by the environment variable SHELL. In
either case, the interpreter is invoked with 2 arguments, respectively
-c and the given command cmd. When the interpreter is /bin/sh or
/bin/ksh, sfpopen() may execute the command cmd itself if there are no
shell meta-characters in cmd.
Sfio_t* sftmp(size_t size)
This function creates a stream for temporary data. It returns the new
stream or NULL on error.
A stream created by sftmp() can be completely or partially memory-resi-
dent. If size is SF_UNBOUND, the stream is a pure string stream. If
size is zero, the stream is a pure file stream. Otherwise, the stream
is first created as a string stream but when its buffer grows larger
than size or on any attempt to change disciplines, a temporary file is
created. Two environment variables, TMPPATH and TMPDIR, direct where
temporary files are created. TMPPATH, if defined, specifies a colon-
separated set of directories to be used in a round-robin fashion to
create files. If TMPPATH is undefined, TMPDIR can be used to specify a
single directory to create files. If neither of TMPPATH and TMPDIR are
defined, /tmp is used.
int sfclose(Sfio_t* f)
This function closes the stream f and frees its resources. SF_STATIC
should be used if the stream space is to be preserved. If f is the
base of a stream stack (see sfstack()), all streams on the stack are
closed. If f is a sfpopen-stream, sfclose() waits until the associated
command terminates and returns its exit status. sfclose() returns -1
for failure and 0 for success.
SF_READ|SF_SHARE and SF_WRITE streams are synchronized before closing
(see sfsync()). If f has disciplines, their exception handlers will be
called twice. The first exception handler call has the type argument
as one of SF_CLOSING or SF_NEW (see sfdisc().) The latter, SF_NEW is
used when a stream is being closed via sfnew() so that it can be
renewed. The second call uses type as SF_FINAL and is done after all
closing operations have succeeded but before the stream itself is deal-
located. In either case, if the exception handler returns a negative
value, sfclose() will immediately return this value. If the exception
handler returns a positive value, sfclose() will immediately return a
zero value.
THREAD SAFETY
The libraries libsfio.a and libstdio.a (providing binary compatibility
to Stdio-based code) only support uni-threaded code. Multi-threaded
applications should link with libsfio-mt.a and libstdio-mt.a. When
this is done, certain platforms may require additional thread libraries
for linkage. For example, Linux, Irix and Solaris require -lpthread
while HPUX requires -lcma. Aside from linkage differences, the Sfio
API remains identical in all cases.
Note that unlike Stdio streams which are in thread-safe mode by
default. Sfio streams can be opened in either uni-threaded or multi-
threaded mode. A uni-threaded stream is more efficient than a multi-
threaded one. For example, functions such as sfgetc() and sfputc()
remain as macro or inline functions for a uni-threaded stream while
they will act as full function calls in a multi-threaded case. The
three standard streams sfstdin/sfstdout/sfstderr are in multi-threaded
mode by default (however, see sfopen() for how this may be changed).
Other Sfio streams are normally opened uni-threaded unless the flag
SF_MTSAFE or the option m were specified. Stdio-based code can also
make a Stdio stream uni-threaded by using the option u when opening a
file.
int sfmutex(Sfio_t* f, int type)
This function acquires or releases a mutex (mutually exclusive) lock on
the stream f. It can be used by a thread to delineate a sequence of
I/O operations executed together in some critical section. sfmutex()
is implicitly used by all Sfio operations on a stream with the flag
SF_MTSAFE. sfmutex() returns 0 on success and some non-zero value on
failure.
Each stream has a lock count which starts at 0. When the count is pos-
itive, a single thread holds the stream. Only this thread can further
lock or unlock the stream. A different thread attempting to acquire
such a locked stream will suspend until the lock count returns to 0.
Each successful locking operation increases the lock count while each
successful unlocking operation decreases it, thus, allowing nesting of
matching lock/unlock operations.
The type argument of sfmutex() takes on the below values:
SFMTX_LOCK:
Locking a stream if it is unlocked or increasing the lock count
of the stream if it is already locked by the same thread.
SFMTX_TRYLOCK:
This is the non-blocking version of SFMTX_LOCK. If the stream
is already locked by a different thread, sfmutex() will immedi-
ately return with an error status.
SFMTX_UNLOCK:
Decreasing the lock count and releasing the stream when the lock
count reaches 0. An attempt to unlock a stream without a previ-
ously successful lock may result in undefined behavior in cer-
tain implementations. The current Sfio implementation returns
an error status.
SFMTX_CLRLOCK:
Resetting the lock count to 0 and releasing the stream. As with
SFMTX_LOCK, an attempt to clear the lock count without a previ-
ously successful lock may result in undefined behavior.
INPUT/OUPUT OPERATIONS
int sfgetc(Sfio_t* f)
int sfputc(Sfio_t* f, int c)
These functions read/write a byte from/to stream f. sfgetc() returns
the byte read or -1 on error. sfputc() returns c on success and -1 on
error.
ssize_t sfnputc(Sfio_t* f, int c, size_t n)
This function attempts to write the byte c to f n times. It returns
the number of bytes actually written or -1 on failure.
int sfungetc(Sfio_t* f, int c)
This function pushes the byte c back into f. If c matches the byte
immediately before the current position in buffered data, the current
position is simply backed up (note the effect on sftell() and
sfseek()). There is no theoretical limit on the number of bytes that
can be pushed back into a stream. Pushed back bytes not part of
buffered data will be discarded on any operation that implies buffer
synchronization. sfungetc() returns c on success and -1 on failure.
Sfulong_t sfgetm(Sfio_t* f, Sfulong_t max)
int sfputm(Sfio_t* f, Sfulong_t v, Sfulong_t max)
These functions read and write Sfulong_t values encoded in a portable
format given that the values are at most max. Portability across a
write architecture and a read architecture requires that the bit order
in a byte is the same on both architectures and the written value is
storable in an Sfulong_t on the read architecture. sfgetm() returns
the value read or -1 on error. sfputm() returns the number of bytes
written or -1 on error.
Sfulong_t sfgetu(Sfio_t* f)
int sfputu(Sfio_t* f, Sfulong_t v)
These functions read and write Sfulong_t values in a compact variable-
length portable format. Portability across a write architecture and a
read architecture requires that the bit order in a byte is the same on
both architectures and the written value is storable in an Sfulong_t on
the read architecture. sfgetu() returns the value read or -1 on error.
sfputu() returns the number of bytes written or -1 on error. See also
sfulen().
Sflong_t sfgetl(Sfio_t* f)
int sfputl(Sfio_t* f, Sflong_t v)
These functions are similar to sfgetu() and sfputu() but for reading
and writing (signed) Sflong_t values. See also sfllen().
Sfdouble_t sfgetd(Sfio_t* f)
int sfputd(Sfio_t* f, Sfdouble_t v)
These functions read and write Sfdouble_t values. In this case, porta-
bility depends on the input and output architectures having the same
floating point value representation. Values are coded and decoded
using ldexp(3) and frexp(3) so they are constrained to the sizes sup-
ported by these functions. See also sfdlen().
char* sfgetr(Sfio_t* f, int rsc, int type)
This function reads a record of data ending in the record separator
rsc. After sfgetr() returns, the length of the record even if it is
incomplete can be retrieved with sfvalue(). sfgetr() returns the
record on success and NULL on error. See also sfmaxr() for limiting
the amount of data read to construct a record.
The type argument is composed of some subset of the below bit flags:
SF_STRING:
A null byte will replace the record separator to make the record
into a C string. Otherwise, the record separator is left alone.
SF_LOCKR:
Upon successfully obtaining a record r, the stream will be
locked from further access until it is released with a call
sfread(f,r,0).
SF_LASTR:
This should be used only after a failed sfgetr() to retrieve the
last incomplete record. In this case, rsc is ignored.
ssize_t sfputr(Sfio_t* f, const char* s, int rsc)
This function writes the null-terminated string s to f. If rsc is non-
negative, (unsigned char)rsc is output after the string. sfputr()
returns the number of bytes written or -1 on failure.
Sfoff_t sfmove(Sfio_t* fr, Sfio_t* fw, Sfoff_t n, int rsc)
This function moves objects from input stream fr to output stream fw.
sfmove() returns the number of objects moved or -1 on failure.
An object can be either a byte if the record separator argument rsc is
negative or a record of rsc is non-negative. In the latter case, a
record is incomplete if it does not end in rsc. Generally speaking, a
stream can have at most one incomplete record. If n is negative, all
complete objects of fr will be moved. Otherwise, n indicates the num-
ber of objects to move. If either fr or fw is NULL, it acts as if it
is a stream corresponding to /dev/null, the UNIX device that has no
read data and throws away any write data. For example, the call
sfmove(f,(Sfio_t*)0,(Sfoff_t)(-1),'\n') counts the number of complete
lines in stream f.
ssize_t sfread(Sfio_t* f, Void_t* buf, size_t n)
This function reads up to n bytes from f into buffer buf. It returns
the number of bytes actually read or -1 on error.
ssize_t sfwrite(Sfio_t* f, const Void_t* buf, size_t n)
This function writes n bytes from buf to f. If f is SF_STRING, and the
buffer is not large enough, an SF_WRITE exception shall be raised.
sfwrite() returns the number of bytes written or -1 on failure.
Sfoff_t sfseek(Sfio_t* f, Sfoff_t offset, int type)
This function sets a new I/O position for f. It returns the new posi-
tion or -1 on failure.
If the stream is a SF_STRING stream and the new address is beyond the
current buffer extent, an SF_SEEK exception will be raised (see
sfdisc()).
The new position is determined based on offset and type which is com-
posed from the bit flags:
0 or SEEK_SET:
offset is the desired position.
1 or SEEK_CUR:
offset is relative to the current position (see SF_PUBLIC
below).
2 or SEEK_END:
offset is relative to the physical end of file.
SF_SHARE:
The stream is treated as if it has the control bit SF_SHARE on.
This implies that a system call seek will be done to ensure that
the location seeking to is valid.
SF_PUBLIC:
The stream is treated as if it has the control bit SF_PUBLIC on.
If the physical file position has changed from its last known
location, the current position is taken as the new physical
position. Otherwise, the current position is the logical stream
position.
Void_t* sfreserve(Sfio_t* f, ssize_t n, int type)
This function reserves a data block from the stream f. It returns the
reserved data block on success and NULL on failure.
If f is a SF_READ stream, the data block is a segment of input data.
If f is a SF_WRITE stream, the data block is a buffer suitable for
writing output data. For consistency, if f is opened with
SF_READ|SF_WRITE, it will normally be treated as if it is a SF_READ
stream (see sfset() for forcing a particular mode) but the returned
buffer can also be written into (more below). However, it is possible
to bias to SF_WRITE when the type argument is non-negative by adding
the SF_WRITE bit type. In any case, a reserved data block is guaran-
teed to be valid only until a future access to the stream f.
When f is SF_READ, SF_SHARE and unseekable, sfreserve() will attempt to
peek at input data without consuming it. This enables separate pro-
cesses to share in reading input from unseekable file descriptors
(e.g., pipes or devices). However, this use of sfreserve() may fail on
certain platforms that do not properly support peeking on unseekable
file descriptors.
After a sfreserve() call, whether or not it succeeds, sfvalue(f) gives
the size of the available data block. Any partially reserved data
block after a failed sfreserve() call can be obtained in another sfre-
serve() call with the argument type being SF_LASTR. The second argument
n to sfreserve() will be ignored in this case.
A sfreserve() call is successful if it can obtain a data block of size
at least the absolute value of n. For a SF_READ atream, the argument n
is treated as follows:
n < 0: sfreserve() attempts to get at least |n| bytes into the buffer.
n == 0:
If the argument type is 0, sfreserve() attempts to get at least
1 byte into the buffer; otherwise, no attempt will be made to
read data into the buffer. For example, the call sfreserve(f,
0, -1) only returns the buffer status, i.e., size of existing
buffered data and pointer to such data, if any. The call sfre-
serve(f, 0, SF_LOCKR) is similar but also locks the stream.
n > 0: sfreserve() will use attempt to get at most n bytes into the
buffer. Further, if type == SF_LOCKR (see below), read attempts
end on a positive amount.
For a successful reservation, the argument type dictates treat-
ment as follows:
type == SF_LASTR:
After a sfreserve() call with type != SF_LOCKR fails, there may
be some left over data not accessible via conventional Sfio
calls. Immediately after such a failed call, another call to
sfreserve with type == SF_LASTR will return any left over data
and also advance the stream I/O position by the amount of
returned data.
type < 0:
If n > 0, the stream I/O position is advanced by n. If n < 0,
the stream I/O position is advanced by the amount of available
data. For example, a successful sfreserve(f, -1, -1) call will
return a buffer of data and simultanously advance the stream I/O
position by the amount indicated by sfvalue(f).
type == SF_LOCKR:
The stream I/O position remains unchanged. In addition, f will
be locked from further access. As appropriate to the stream
type (SF_READ, SF_WRITE or both), f can be unlocked later with
one of sfread(f,rsrv,size) or sfwrite(f,rsrv,size) where rsrv is
the reserved data block and size is the amount of data to be
consumed. For example, if f is a locked SF_READ stream, the call
sfread(f,rsrv,1) will reopen the stream and simultaneously
advance the stream I/O position by 1. Finally, a stream opened
for both reading and writing can release the lock with either
call (with associated operational semantics!) For example, the
below code reads 10 bytes of data from a stream opened with both
SF_READ and SF_WRITE, modifies the data in place, then rewrites
the new data back to the stream:
rsrv = sfreserve(f, 10, 1);
for(i = 0; i < 10; ++i)
rsrv[i] = toupper(rsrv[i]);
sfwrite(f, rsrv, 10);
DATA FORMATTING
Data printing and scanning are done via the sfprintf() and sfscanf()
family of functions. These functions are similar to their ANSI-C
fprintf() and fscanf() counterparts. However, the Sfio versions have
been extended for both portability and generality. In particular, a
notion of a formatting environment stack is introduced. Each format-
ting element on the stack defines a separate formatting pair of a for-
mat specification string, char* format (the usual second argument in
the formatting functions), and an argument list, va_list args (the
third argument in functions sfvprintf() and sfvscanf()). A formatting
environment element may also specify extension functions to obtain or
assign arguments and to provide new semantics for pattern processing.
To simplify the description below, whenever we talk about an argument
list, unless noted otherwise, it is understood that this means either
the true argument list when there is no extension function or the
action to be taken by such a function in processing arguments. The
manipulation of the formatting environment stack is done via the pat-
tern ! discussed below.
%! and Sffmt_t
The pattern %! manipulates the formatting environment stack to (1)
change the top environment to a new environment, (2) stack a new envi-
ronment on top of the current top, or (3) pop the top environment. The
bottom of the environment stack always contains a virtual environment
with the original formatting pair and without any extension functions.
The top environment of a stack, say fe, is automatically popped when-
ever its format string is completely processed. In this case, its
event-handling function (if any) is called as
(*eventf)(f,SF_FINAL,NIL(Void_t*),fe). The top environment can also be
popped by giving an argument NULL to %! or by returning a negative
value in an extension function. In these cases, the event-handling
function is called as (*eventf)(f,SF_DPOP,form,fe) where form is the
remainder of the format string. A negative return value from the event
handling function will prevent the environment from being popped.
A formatting environment is a structure of type Sffmt_t which contains
the following elements:
Sffmtext_f extf; /* extension processor */
Sffmtevent_f eventf; /* event handler */
char* form; /* format string to stack */
va_list args; /* corresponding arg list */
int fmt; /* pattern being processed */
ssize_t size; /* object size */
int flags; /* formatting control flags */
int width; /* width of field */
int precis; /* precision required */
int base; /* conversion base */
char* t_str; /* extfdata string */
int n_str; /* length of t_str */
The first four elements of Sffmt_t must be defined by the application
before the structure is passed to a formatting function. The two func-
tion fields should not be changed during processing. Other elements of
Sffmt_t are set by the respective formatting function before it calls
the extension function Sffmt_t.extf and, subsequently, can be modified
by this function to redirect formatting or scanning. For example, con-
sider a call from a sfprintf() function to process an unknown pattern
%t (which we may take to mean ``time'') based on a formatting environ-
ment fe. fe->extf may reset fe->fmt to `d' upon returing to cause
sfprintf() to process the value being formatted as an integer.
Below are the fields of Sffmt_t:
extf: extf is a function to extend scanning and formatting patterns.
Its usage is discussed below.
eventf:
This is a function to process events as discussed earlier.
form and args:
This is the formatting pair of a specification string and corre-
sponding argument list. When an environment fe is being
inserted into the stack, if fe->form is NULL, the top environ-
ment is changed to fe and its associated extension functions but
processing of the current formatting pair continues. On the
other hand, if fe->form is not NULL, the new environment is
pushed onto the stack so that pattern processing will start with
the new formatting pair as well as any associated extension
functions. During processing, whenever extf is called, form and
args will be set to the current values of the formatting pair in
use.
fmt: This is set to the pattern being processed or one of '.', 'I',
'('.
size: This is the size of the object being processed.
flags: This is a collection of bits defining the formatting flags spec-
ified for the pattern. The bits are:
SFFMT_LEFT: Flag - in sfprintf().
SFFMT_SIGN: Flag + in sfprintf().
SFFMT_BLANK: Flag space in sfprintf().
SFFMT_ZERO: Flag 0 in sfprintf().
SFFMT_THOUSAND: Flag ' in sfprintf().
SFFMT_LONG: Flag l in sfprintf() and sfscanf().
SFFMT_LLONG: Flag ll in sfprintf() and sfscanf().
SFFMT_SHORT: Flag h in sfprintf() and sfscanf().
SFFMT_LDOUBLE: Flag L in sfprintf() and sfscanf().
SFFMT_IFLAG: flag I in sfprintf() and sfscanf().
SFFMT_ALTER: Flag # in sfprintf() and sfscanf().
SFFMT_SKIP: Flag * in sfscanf().
SFFMT_ARGPOS: This indicates argument processing for pos$.
SFFMT_VALUE: This is set by fe->extf to indicate that it is
returning a value to be formatted or the address of an object to
be assigned.
width: This is the field width.
precis:
This is the precision.
base: This is the conversion base.
t_str and n_str:
This is the type string and its size.
int (*Sffmtext_f)(Sfio_t* f, Void_t* v, Sffmt_t* fe)
This is the type of the extension function fe->extf to process patterns
and arguments. Arguments are always processed in order and fe->extf is
called exactly once per argument. Note that, when pos$ (below) is not
used anywhere in a format string, each argument is used exactly once
per a corresponding pattern. In that case, fe->extf is called as soon
as the pattern is recognized and before any scanning or formatting. On
the other hand, when pos$ is used in a format string, an argument may
be used multiple times. In this case, all arguments shall be processed
in order by calling fe->extf exactly once per argument before any pat-
tern processing. This case is signified by the flag SFFMT_ARGPOS in
fe->flags.
In addition to the predefined formatting patterns and other applica-
tion-defined patterns, fe->extf may be called with fe->fmt being one of
`(' (left parenthesis), `.' (dot), and `I'.
The left parenthesis requests a string to be used as the extfdata
string discussed below. In this case, upon returning, fe->extf should
set the fe->size field to be the length of the string or a negative
value to indicate a null-terminated string.
The `I' requests an integer to define the object size.
The dot requests an integer for width, precision, base, or a separator.
In this case, the fe->size field will indicate how many dots have
appeared in the pattern specification. Note that, if the actual conver-
sion pattern is 'c' or 's', the value *form will be one of these char-
acters.
f: This is the input/output stream in the calling formatting func-
tion. During a call to fe->extf, the stream shall be unlocked
so that fe->extf can read from or write to it as appropriate.
v: For both sfscanf() and sfprintf() functions, v points to a loca-
tion suitable for storing any scalars or pointers. On return,
fe->extf treats v as discussed below.
fe: This is the current formatting environment.
The return value rv of fe->extf directs further processing. There are
two cases. When pos$ is present, a negative return value means to
ignore fe in further argument processing while a non-negative return
value is treated as the case rv == 0 below. When pos$ is not present,
fe->extf is called per argument immediately before pattern processing
and its return values are treated as below:
rv < 0:
The environment stack is immediately popped.
rv == 0:
The extension function has not consumed (in a scanning case) or
output (in a printing case) data out of or into the given stream
f. The fields fmt, flags, size, width, precis and base of fe
shall direct further processing.
For sfprintf() functions, if fe->flags has the bit SFFMT_VALUE,
fe->extf should have set *v to the value to be processed; other-
wise, a value should be obtained from the argument list. Like-
wise, for sfscanf() functions, SFFMT_VALUE means that *v should
have a suitable address; otherwise, an address to assign value
should be obtained from the argument list.
When pos$ is present, if fe->extf changes fe->fmt, this pattern
shall be used regardless of the pattern defined in the format
string. On the other hand, if fe->fmt is unchanged by fe->extf,
the pattern in the format string is used. In any case, the
effective pattern should be one of the standardly defined pat-
tern. Otherwise, it shall be treated as unmatched.
rv > 0:
The extension function has accessed the stream f to the extent
of rv bytes. Processing of the current pattern ceases except
that, for scanning functions, if fe->flags does not contain the
bit SFFMT_SKIP, the assignment count shall increase by 1.
void va_copy(va_list to, va_list fr)
This macro function portably copies the argument list fr to the argu-
ment list to. It should be used to set the field Sffmt_t.args.
long sffmtversion(Sffmt_t* fe, int type)
This macro function initializes the formatting environment fe with a
version number if type is non-zero. Otherwise, it returns the current
value of the version number of fe. This is useful for applications to
find out when the format of the structure Sffmt_t changes. Note that
the version number corresponds to the Sfio version number which is
defined in the macro value SFIO_VERSION.
int sfprintf(Sfio_t* f, const char* format, ...);
char* sfprints(const char* format, ...);
char* sfvprints(const char* format, va_list args);
ssize_t sfaprints(char** sp, const char* format, ...);
ssize_t sfvaprints(char** sp, const char* format, va_list args);
int sfsprintf(char* s, int n, const char* format, ...)
int sfvsprintf(char* s, int n, const char* format, va_list args);
int sfvprintf(Sfio_t* f, const char* format, va_list args);
These functions format output data. sfprintf() and sfvprintf() write
to output stream f. sfsprintf() and sfvsprintf() write to buffer s
which is of size n. sfprints() and sfvprints() construct data in some
Sfio-defined buffer. sfaprints() and sfvaprints() are similar to
sfprints() and sfvprints() but they return a string constructed via
malloc() in *sp and expect this string to be freed by the caller when
no longer needed. sfvprintf() is the underlying primitive for the
other functions. Except for sfprints() and sfvprints() which return a
null-terminated string or NULL, other functions return the number of
output bytes or -1 on failure.
The length of string constructed by sfprints(), sfsprintf(), or
sfvsprintf() can be retrieved by sfslen().
The standard patterns are: n, s, c, %, h, i, d, p, u, o, x, X, g, G, e,
E, f and !. Except for ! which shall be described below, see the ANSI-
C specification of fprintf(3) for details on the other patterns. Let z
be some pattern type. A formatting pattern is defined as below:
%[pos$][flag][width][.precision[.base]][(extfdata)]z
pos$: A pattern can specify which argument in the argument list to
use. This is done via pos$ where pos is the argument position.
Arguments are numbered so that the first argument after format
is at position 1. If pos is not specified, the argument follow-
ing the most recently used one will be used. The pattern %!
(see below) cannot be used subsequent to a usage of pos$. Doing
so may cause unexpected behaviors.
flag: The flag characters are h, hh, l, ll, L, I, j, t, z, -, +,
space, 0, ' and #.
Flag I defines the size or type of the object being formatted.
There are two cases: (1) I by itself and (2) I followed by
either a decimal number or `*'.
In the first case, for integer and floating point patterns, the
object type is taken to be the largest appropriate type (i.e.,
one of Sflong_t, Sfulong_t or Sfdouble_t). For conversion spec-
ifiers s and c, the flag is ignored.
In the second case, a given decimal value would define a size
while `*' would cause the size to be obtained from the argument
list. Then, if the conversion specifier is s, this size defines
the length of the string or strings being formatted (see the
discussion of base below). For integer and floating point pat-
terns, the size is used to select a type from one of the below
lists as indicated by the conversion specifier:
Sflong_t, long, int, short
Sfulong_t, unsigned long, unsigned int, unsigned short
Sfdouble_t, double, float
The selection algorithm always matches types from left to right
in any given list. Although selection is generally based on
sizes in bytes, for compatibility with Microsoft-C, the size 64
is matched with an appropriate type with the same number of
bits, if any. If the given size does not match any of the
listed types, it shall match one of int, unsigned int, and dou-
ble as defined by the formatting pattern.
Below are a few examples of using the I flag. The first example
prints an Sflong_t integer. This example is actually not porta-
ble and only works on platforms where sizeof(Sflong_t) is 8.
The second example shows how to that portably. The third exam-
ple specifies printing a string of length 16. This length shall
be used regardless of whether or not the given string is shorter
or longer than 16. The last example shows the use of the pat-
tern %n to assign the amount of data already output into a short
integer n_output.
sfprintf(sfstdout,"%I8d", Sflong_obj);
sfprintf(sfstdout,"%I*d", sizeof(Sflong_obj), Sflong_obj);
sfprintf(sfstdout,"%I*s", 16, s);
sfprintf(sfstdout,"%d%I*n", 1001, sizeof(short), &n_output);
Flags h, l, and L are the ANSI-C conventions to select the types
of input objects. For example, %hd indicates a short int while
%ld indicates a long int.
Flag hh addresses the byte value types, i.e., char and unsigned
char.
Flags z, t and j address respectively the types size_t,
ptrdiff_t and Sflong_t.
Flags ll and L address respectively the largest integer and
floating value types, i.e., Sfulong_t, Sflong_t, and Sfdouble_t.
Flag - left-justifies data within the field (otherwise, right-
justification).
Flag + means that a signed conversion will always begin with a
plus or minus sign.
Flag space is ignored if + is specified; otherwise, it means
that if the first character of a signed conversion is not a sign
or if the result is empty, a space will be prepended.
Flag 0 means padding with zeros on the left.
Flag ' outputs thousands-separator used by the current locale.
setlocale(3) should have been used to set the desired locale.
Flag # indicates an alternative format processing. For %o, the
first digit is always a zero. For %x and %X, a non-zero result
will have a prefix 0x or 0X. For %e, %E, %f, %g, and %G, the
result always contains a decimal point. For %g and %G, trailing
zeros will not be removed. For %d, %i and %u, the form is
base#number where base is the conversion base and number is rep-
resented by digits for this base. For example, a base 2 conver-
sion with %#..2d for 10 is 2#1010 instead of 1010 as printed
with %..2d. Finally, for %c, bytes will be printed in the C
format. For example, when the ASCII character set is used, the
byte value 10 will be printed as \n while 255 is printed as
\377.
width: This defines the width of the printing field. A value to be
printed will be justified and padded if necessary to fill out
the field width.
precis:
After a first dot appears, an integral value defines a preci-
sion. For floating point value patterns, precision is the num-
ber of precision digits. For %c, precision defines the number
of times to repeat the character being formatted. For %s, pre-
cision defines the maximum number of characters to output.
base: This is defined after exactly two dots have appeared.
For %i, %d, and %u, base should be an integer value in the
inclusive range [2,64] and defines a conversion base. If base
is not in this range, it is defined to be 10. The digits to
represent numbers are:
01234567890
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ @_
For %s and %c, base defines a separator. Then, for %s, the
input argument is taken to be a NULL-terminated array of strings
while, for %c, this is a null-terminated array of characters.
The strings or characters will be formatted one of a time based
on the usual width and precision rules. After each formatted
string or character, except for the last one, the separator base
is output if it is a non-zero.
There are further restrictions on the syntax of %s and %c when a
separator is defined. Below are the legitimate sequences for %s
and %c after the second dot:
s c
*s *c
zs zc
In the first case, no separator is defined so base is set to
zero. In the second case, base is obtained from the argument
list. In the third case, the character z must be non-alphanu-
meric and base will be set to this character.
The below example shows both the call and the result of printing
a NULL-terminated array of three strings apple, orange, and
grape:
sfprintf(sfstdout,"|%8..:s|",list);
| apple: orange: grape|
(extfdata):
This defines a string extfdata to be passed to the extension
function Sffmt_t.extf. Parentheses shall be balanced. If extf-
data is *, the string is obtained from the argument list.
int sfscanf(Sfio_t* f, const char* format, ...)
int sfsscanf(const char* s, const char* format, ...)
int sfvsscanf(const char* s, const char* format, va_list args)
int sfvscanf(Sfio_t* f, const char* format, va_list args)
These functions scan data items. sfscanf() scans from the input stream
f while sfsscanf() and sfvsscanf() scan from the null-terminated string
s. sfvscanf() is the underlying primitive that performs the actual
scanning. Item types are determined from patterns in string format.
These functions return the number of items successfully scanned or -1
on error.
A white space character (blank, tab, or new-line) in format normally
matches a maximal sequence of input white space characters. However,
if the input stream is in SF_LINE mode (see sfset()), a new-line char-
acter only matches white spaces up to an input new-line character.
This is useful to avoid blocking when scanning typed inputs.
The standard scan patterns are: i, d, u, o, x, X, p, n, f, e, E, g, G,
c, %, s, [] and !. Except for ! which shall be described below, see
the ANSI-C specification of fscanf(3) for details on other patterns.
Let z be some pattern type. A formatting pattern is specified as below:
%[*][pos$][width][.width.base][(extfdata)][flag]z
pos$: A pattern can specify which argument in the argument list to
use. This is done via pos$ where pos is the argument position.
Arguments are numbered so that the first argument after format
is at position 1. If pos is not specified, the argument follow-
ing the most recently used one will be used. The pattern %!
(see below) cannot be used subsequent to a usage of pos$.
*: This discards the corresponding scanned item.
width and base:
width defines the maximum number of bytes to scan and base
defines the base of an integral value being scanned. The `.'
(dot) notation also allows specifying a `*' (star) to obtain the
value from the argument list. The below example specifies scan-
ning 4 bytes to obtain the value of an integer in base 10. At
the end of scanning, the variable v should have the value 1234.
sfsscanf("12345678","%.*.*d", 4, 10, &v);
(extfdata):
This defines a string extfdata to be passed to the extension
function Sffmt_t.extf. Parentheses shall be balanced. If extf-
data is *, the string is obtained from the argument list.
flag: This is #, I, or some sequence of h, l, and L.
Flag # is significant for pattern %i and %[. For %i, it means
that the # symbol does not have its usual meaning in an input
sequence base#value. For example, the scanning result of %#i on
input 2#1001 is 2 and the next sfgetc() call will return #. For
%[, if the next character in the input stream does not match the
given scan set of characters, # causes a match to a null string
instead of a failure.
Flag I defines the size or type of the object being formatted.
There are two cases: (1) I by itself and (2) I followed by
either a decimal number or `*'.
In the first case, for integer and floating point patterns, the
object type is taken to be the largest appropriate type (i.e.,
one of Sflong_t, Sfulong_t or Sfdouble_t). For string patterns
such as %s, the flag is ignored.
In the second case, a given decimal value would define a size
while `*' would cause the size to be obtained from the argument
list. For string patterns such as %s or %[, this size defines
the length of the buffer to store scanned data. Specifying a
buffer size only limits the amount of data copied into the
buffer. Scanned data beyond the buffer limit will be discarded.
For integer and floating point patterns, the size is used to
select a type from one of the below lists as indicated by the
conversion specifier:
Sflong_t, long, int, short
Sfulong_t, unsigned long, unsigned int, unsigned short
Sfdouble_t, double, float
The selection algorithm always matches types from left to right
in any given list. Although selection is generally based on
sizes in bytes, for compatibility with Microsoft-C, the size 64
is matched with an appropriate type with the same number of
bits, if any. If the given size does not match any of the
listed types, it shall match one of int, unsigned int, and dou-
ble as indicated by the formatting pattern.
Below are examples of using the I flag. The first example scans
a 64-bit integer. The second scans some floating point value
whose size is explicitly computed and given. The last example
scans a string into a buffer with the given size 128. Note that
if the scanned string is longer than 127, only the first 127
bytes shall be copied into the buffer. The rest of the scanned
data shall be discarded.
sfscanf(sfstdin,"%I64d", &int64_obj);
sfscanf(sfstdin,"%I*f", sizeof(float_obj), &float_obj);
sfscanf(sfstdin,"%I*s", 128, buffer);
Flags h, l, and L are the ANSI-C conventions for indicating the
type of a scanned element. For example, %hd means scanning a
short int. The flags ll and L mean respectively scanning an
integer or a floating point value with largest size (i.e,
Sflong_t or Sfdouble_t).
The %i, %d and %u patterns scan numbers in bases from 2 to 64. %i
scans integral values in self-describing formats. Except for octal,
decimal and hexadecimal numbers with the usual formats, numbers in gen-
eral bases are assumed to be of the form: base#value where base is a
number in base 10 and value is a number in the given base. For exam-
ple, 2#1001 is the binary representation of the decimal value 9. If
base is 36 or less, the digits for value can be any combination of
[0-9], [a-z], [A-Z] where upper and lower case digits are not distin-
guishable. If base is larger than 36, the set of digits is:
0123456789
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ @_
BUFFERING, SYNCHRONIZATION
Void_t* sfsetbuf(Sfio_t* f, Void_t* buf, size_t size)
This function changed the buffering scheme for the stream f. The
stream will be synchronized before any buffer modification. If a new
buffer is successfully set and the old buffer has not been freed,
sfsetbuf() returns the old buffer. Otherwise, it returns NULL. After a
sfsetbuf() call, sfvalue() returns the size of the returned buffer.
Sfio attempts to read data in blocks likely to be serviced fast by the
file system. This means block sizes being multiples of a suitable
alignment value (e.g., 512, 1024 or 8192). By default, the alignment
value is computed via some internal mechanism depending on the local
platform but it can also be explicitly set via the call sfsetbuf(f,
(Void_t*)f, size).
In invocations of sfsetbuf() other than the above case, the size argu-
ment is treated as follows:
size == SF_UNBOUND:
Sfio will pick a suitable buffer size. If buf is NULL, Sfio
will also pick a suitable buffering scheme (such as memory map-
ping.) If buf is not NULL, its actual value is ignored but the
buffer will be allocated via malloc(3). This can be used to
avoid memory mapping.
size > 0:
This is the suggested size to use for buffering or memory map-
ping. If buf is NULL, Sfio will pick a suitable buffering
scheme as discussed above. If buf is not NULL, then buf and
size determine a buffer of the given size.
size == 0:
If buf is NULL, the stream will be unbuffered. If buf is not
NULL, sfsetbuf() simply returns the stream buffer. In this
case, no attempt will be made to synchronize the stream.
int sfsync(Sfio_t* f)
This function synchronizes the logical and physical views of stream f.
It returns a negative value for failure and 0 for success.
For a SF_WRITE stream, synchronization means to write out any buffered
data. For a seekable SF_READ file stream, the physical file position
is aligned with the logical stream position and, if SF_SHARE is on,
buffered data is discarded. If f is NULL, all streams are synchro-
nized. If f is the base of a stream stack (see sfstack()), all stacked
streams are synchronized. Note that a stacked stream can only be syn-
chronized this way. If f is in a pool (see sfpool()) but not being the
head, the pool head is synchronized.
If f has flag SF_IOCHECK, the SF_SYNC event is raised before and after
synchronization. See sfdisc() for details.
int sfpoll(Sfio_t** flist, int n, int timeout)
This function polls a set of streams to see if I/O operations can be
performed on them without blocking. This is useful for multiplexing
I/O over a set of streams. If a stream has a discipline, the exception
function may be called before and after the stream is polled (see
sfdisc() for details). After a successful sfpoll() call, for each
ready stream f, sfvalue(f) returns a bit combination of SF_READ and
SF_WRITE to tell which I/O mode is available. If SF_READ is available,
an attempt to read a byte will not block. If SF_WRITE is available, an
attempt to flush will not block. sfpoll() returns the number of ready
streams or -1 on failure.
flist and n:
flist is an array of n streams to be polled. Upon return, ready
streams are moved to the front of flist in the same relative
order.
timeout:
This defines an elapse time in milliseconds to wait to see if
any stream is ready for I/O. If timeout is negative, sfpoll()
will block until some stream become ready. Note that SF_STRING
and normal file streams never block and are always ready for
I/O. If a stream with discipline is being polled and its readi-
ness is as yet undetermined (e.g., empty buffer,) the discipline
exception function will be called with SF_DPOLL before querying
the operating system.
Sfio_t* sfpool(Sfio_t* f, Sfio_t* poolf, int mode)
This function manipulates pools of streams. In a pool, only one stream
is at the head and can have buffered data. All other streams in the
pool will be synchronized. A stream becomes head when it is used for
some I/O operation. sfpool() returns NULL on failure.
f and poolf:
If f is NULL, sfpool() simply returns the head of the pool con-
taining poolf. If f is not NULL and poolf is NULL, f is deleted
from its pool. In this case, if no other stream from the same
pool can become head, sfpool() will return NULL; otherwise, it
returns some stream from the remainder of the pool. If both f
and poolf are not NULL, f is moved from its current pool (if
any) into the same pool with poolf. In this case, poolf is
returned.
mode: If poolf is already in a pool, mode is ignored. Otherwise, mode
should be 0 or SF_SHARE. A SF_SHARE pool contains streams with
SF_WRITE mode. In addition, on change to a new head stream,
buffered write data of the current head is transferred to the
new head.
int sfpurge(Sfio_t* f)
This function discards all buffered data unless f is a SF_STRING
stream. Note that if f is a SF_READ stream based on an unseekable
device, purged data will not be recoverable. If f is a sfpopen-stream
opened for both read and write, data of both the read and write pipe
ends will be purged (see sfset() to selectively turn off read or write
mode if one set of data is to be preserved.) After purging, if f has
flag SF_IOCHECK, the event SF_PURGE is raised. sfpurge() returns -1
for failure and 0 for success.
DISCIPLINE, EVENT-HANDLING
A file stream uses the system calls read(2), write(2) and lseek(2) to
read, write and position in the underlying file. Disciplines enable
application-defined I/O methods including exception handling and data
pre/post-processing.
Sfdisc_t* sfdisc(Sfio_t* f, Sfdisc_t* disc)
Each stream has a discipline stack whose bottom is a virtual discipline
representing the actual system calls. sfdisc() manipulates the disci-
pline stack of stream f. f will be synchronized before any discipline
stack manipulation. After a successful discipline stack manipulation,
the stream I/O position (see sfseek() and sftell()) and extent (see
sfsize()) are updated to reflect that defined by the top discipline.
If disc is SF_POPDISC or (Sfdisc_t*)0, the top element of the stack, if
any, is popped and its address is returned. Otherwise, disc is pushed
onto the discipline stack. In this case, if successful, sfdisc()
returns the discipline that was pushed down. sfdisc() returns NULL on
failure.
Note that a discipline can be used only on one stream at a time. An
application should take care to allocate different discipline struc-
tures for use with different streams. A discipline structure is of the
type Sfdisc_t which contains the following public fields:
Sfread_f readf;
Sfwrite_f writef;
Sfseek_f seekf;
Sfexcept_f exceptf;
The first three fields of Sfdisc_t specify alternative I/O functions.
If any of them is NULL, it is inherited from a discipline pushed ear-
lier on the stack. Note that a file stream always has read(2),
write(2), lseek(2) and NIL(Sfexcept_f) as the logical bottom disci-
pline. Arguments to I/O discipline functions have the same meaning as
that of the functions sfrd(), sfwr() and sfsk() described below.
The exception function, (*exceptf)() announces exceptional events dur-
ing I/O operations. It is called as (*exceptf)(Sfio_t* f, int type,
Void_t* value, Sfdisc_t* disc). Unless noted otherwise, the return
value of (*exceptf)() is used as follows:
<0: The on-going operation shall terminate.
>0: If the event was raised due to an I/O error, the error has been
repaired and the on-going operation shall continue normally.
For some events, e.g., SF_DPOLL, the return value may also have
additional meanings.
=0: The on-going operation performs default actions with respect to
the raised event. For example, on a reading error or reaching
end of file, the top stream of a stack will be popped and closed
and the on-going operation continue with the new top stream.
The argument type of (*exceptf)() identifies the particular exceptional
event:
SF_LOCKED:
The stream cannot be accessed. Note that this lock state is not
related to the mutex lock that protects a stream from multiple
accesses by different threads (see section THREAD SAFETY).
Rather, the stream was frozen by certain operations such as
sfreserve() or sfstack(). Thus, a stream can be in this state
even if the application is uni-threaded.
SF_READ, SF_WRITE:
These events are raised around reading and writing operations.
If SF_IOCHECK is on, SF_READ and SF_WRITE are raised immediately
before read(2) and write(2) calls. In this case,
*((ssize_t*)value) is the amount of data to be processed. The
return value of (*exceptf)(), if negative, indicates that the
stream is not ready for I/O and the calling operation will abort
with failure. If it is positive, the stream is ready for I/O
but the amount should be restricted to the amount specified by
this value. If the return value is zero, the I/O operation is
carried out normally.
SF_READ and SF_WRITE are also raised on operation failures. In
such a case, *((ssize_t*)value) is the return value from the
failed operation.
SF_SEEK:
This event is raised when a seek operation fails.
SF_NEW, SF_CLOSING (SF_CLOSE), SF_FINAL:
These events are raised during a stream closing. SF_NEW is
raised for a stream about to be closed to be renewed (see
sfnew()). SF_CLOSING is raised for a stream about to be closed.
SF_FINAL is raised after a stream has been closed and before its
space is to be destroyed (see sfclose()). For these events, a
non-zero return value from (*exceptf)() causes sfclose() to
return immediately with the same value.
SF_DPUSH, SF_DPOP, SF_DBUFFER:
Events SF_DPUSH and SF_DPOP are raised when a discipline is
about to be pushed or popped. (Sfdisc_t*)value is the to-be top
discipline, if any.
A stream buffer is always synchronized before pushing or popping
a discipline. If this synchronization fails, SF_DBUFFER will be
raised with *((size_t*)value) being the amount of buffered data.
If the return value of exceptf is positive, the push or pop
operation will continue normally; otherwise, sfdisc() returns
failure.
SF_DPOLL:
This event is raised by sfpoll() to see if the stream is ready
for I/O. *((int*)value) indicates a time-out interval to wait.
A negative return value from the exception function means block-
ing. A zero return value means that sfpoll() should query the
underlying file descriptor. A positive return value means non-
blocking. In addition, this value will be a bit combination of
SF_READ and SF_WRITE to indicate what I/O modes are ready.
SF_READY:
This event is raised by sfpoll() for each ready stream. The
third argument to the event handler is an integer composed with
the two bits SF_READ and SF_WRITE to indicate which I/O modes
are ready.
SF_SYNC, SF_PURGE:
If SF_IOCHECK is set, these events are raised respectively for a
sfsync() or sfpurge() call. In each case, the respective event
is raised once before the appropriate operation (synchronization
or purging) with ((int)value) being 1 and once after with
((int)value) being 0. Note that sfsync() is called for each
SF_WRITE or SF_SHARE|SF_READ stream on closing.
SF_ATEXIT:
This event is raised for each open stream before the process
exits.
int sfraise(Sfio_t* f, int type, Void_t* data)
If f is non-NULL, sfraise() calls all exception handlers of f with the
event type and associated data. If an exception handler returns a non-
zero value, sfraise() immediate returns the same value. Application-
defined events should start from the value SF_EVENT so as to avoid con-
fusion with system-defined events, sfraise() returns 0 on success and
-1 on failure.
If f is NULL, sfraise() iterates over all streams and raise events as
described above. In this case, sfraise() returns 0 on success and a
negative value on failure. The absolute value of the return value tells
how many streams failed on raising the given event.
ssize_t sfrd(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
ssize_t sfwr(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
Sfoff_t sfsk(Sfio_t* f, Sfoff_t offset, int type, Sfdisc_t* disc)
These functions provides safe methods for a discipline I/O function to
invoke earlier discipline I/O functions and to properly handle excep-
tions. They should not be used in any other context. sfrd() and
sfwr() return the number of bytes read or written. sfsk() returns the
new seek position. On error, all three functions return a negative
value which should be -1 or the value returned by the exception han-
dler.
STREAM CONTROL
int sfresize(Sfio_t* f, Sfoff_t size)
This function resizes the stream fP so that its extent is size. If the
stream corresponds to a file, the file size is set to size via the sys-
tem call ftruncate(). When a stream is made larger, the new data space
is filled with zero's. sfresize() returns 0 on success and a negative
value on failure.
int sfset(Sfio_t* f, int flags, int set)
This function sets control flags for the stream f. It returns the pre-
vious set of flags or 0 on error.
Settable flags are: SF_READ, SF_WRITE, SF_IOCHECK, SF_LINE, SF_SHARE,
SF_PUBLIC, SF_MALLOC and SF_STATIC. Note that SF_READ and SF_WRITE can
be turned on or off only if the stream was opened as SF_READ|SF_WRITE.
Turning off one of them means that the stream is to be treated exclu-
sively in the other mode. It is not possible to turn off both. If
legal, an attempt to turn on either SF_READ or SF_WRITE will cause the
stream to be in the given I/O mode.
set == 0:
If flags is zero, the current set of flags is simply returned.
Note that when a stream is first opened, not all of its flags
are initialized yet (more below). If flags is non-zero, an
attempt is made to turn off the specified flags.
set != 0:
If flags is zero, the stream is initialized if not yet done so.
Then the current set of flags is returned. If flags is non-
zero, an attempt is made to turn on the specified flags.
int sfsetfd(Sfio_t* f, int fd)
This function changes the file descriptor of f. Before a change is
realized, (*notify)(f,SF_SETFD,newfd) (see sfnotify()) is called.
sfsetfd() returns -1 on failure and the new file descriptor on success.
fd >= 0:
If the current file descriptor is non-negative, it will be
changed using dup(3) to a value larger or equal to fd. Upon a
successful change, the previous file descriptor will be closed.
If the current file descriptor is negative, it will be set to fd
and the stream will be reinitialized.
fd < 0:
The stream is synchronized (see sfsync()) and its file descrip-
tor will be set to this value. Then, except for sfclose(), the
stream will be inaccessible until a future sfsetfd() call resets
the file descriptor to a non-negative value. Thus,
sfsetfd(f,-1) can be used to avoid closing the file descriptor
of f when f is closed.
Sfio_t* sfstack(Sfio_t* base, Sfio_t* top)
This function stacks or unstacks stream. Every stream stack is identi-
fied by a base stream via which all I/O operations are performed. How-
ever, an I/O operation always takes effect on the top stream. If the
top stream reaches the end of file or has an unrecoverable error condi-
tion, it is automatically popped and closed (see also sfdisc() for
alternative handling of these conditions).
base: This is the base stream of the stack. If it is NULL, sfstack()
does nothing and returns top.
top: If this is SF_POPSTACK or (Sfio_t*)0, the stack is popped and
sfstack() returns the popped stream. Otherwise, top is pushed
on top of the stack identified by base and sfstack() returns the
base stream.
Sfio_t* sfswap(Sfio_t* f1, Sfio_t* f2)
This function swaps contents of f1 and f2. This fails if either stream
is in a stream stack but not being a base stream. If f2 is NULL, a new
stream is constructed as a duplicate of f1. sfswap() returns f2 or f1
duplicate on success and NULL on failure.
STREAM INFORMATION
Sfoff_t sfsize(Sfio_t* f)
This function returns the size of stream f (see sfnew()). If f is not
seekable or if its size is not determinable, sfsize() returns -1.
Sfoff_t sftell(Sfio_t* f)
This function returns the current I/O position in stream f. Note that
if f is SF_APPEND and a writing operation was just performed, the cur-
rent I/O position is at the physical end of file. If f is unseekable,
sftell returns the number of bytes read from or written to f. See also
sfungetc().
ssize_t sfvalue(Sfio_t* f)
This function returns the string or buffer length for sfreserve(),
sfsetbuf(), and sfgetr().
int sffileno(Sfio_t* f)
This function returns the file descriptor of stream f.
int sfstacked(Sfio_t* f)
This function returns a non-zero value if stream f has been stacked.
int sfeof(Sfio_t* f)
int sferror(Sfio_t* f)
int sfclrerr(Sfio_t* f)
sfeof() tells whether or not the stream has an end-of-file condition.
sferror() tells whether or not the stream has an error condition.
sfclrerr() clears both end-of-file and error conditions. The end-of-
file and error conditions are also cleared on an I/O operation.
int sfclrlock(Sfio_t* f)
This function restores the stream back to a normal state. This means
clearing locks and possibly throwing away unprocessed data. As such,
this operation is unsafe and should be used with care. For example, it
may be used before a long jump (longjmp(3)) out of some discipline I/O
function to restore the internal stream states. sfclrlock() returns
the current set of flags.
int sfnotify((void(*)notify)(Sfio_t*, int, int) )
This sets a function (*notify)() to be called as (*notify)(f,type,file)
on various stream events. Arguments f and file are stream and related
file descriptor. Argument type indicates the reason for the call:
SF_NEW:
f is being opened and file is the underlying file descriptor.
SF_CLOSING (SF_CLOSE):
f and file are being closed.
SF_SETFD:
The file descriptor of f is being changed to file (see
sfsetfd().)
SF_READ:
An attempt to change f to read mode failed.
SF_WRITE:
An attempt to change f to write mode failed.
MISCELLANEOUS FUNCTIONS
ssize_t sfmaxr(ssize_t maxr, int set)
Certain records may require too much memory for storage, thus, causing
undesirable side effects. Therefore, the library normally bounds the
amount of memory used by sfgetr(). A different memory bound can be set
via sfmaxr(). While a positive maxr hints to sfgetr() to use only about
that much memory to construct a record, a non-positive bound allows
sfgetr() to use as much memory as necessary. sfmaxr() sets the value
only if set is non-zero. It returns the value before setting or the
current value if not setting.
ssize_t sfslen()
This function returns the length of a string just constructed by
sfsprintf() or sfprints(). See also sfvalue().
int sfulen(Sfulong_t v)
int sfllen(Sflong_t v)
int sfdlen(Sfdouble_t v)
These functions return respectively the number of bytes required to
code the Sfulong_t, Sflong_t or Sfdouble_t value v by sfputu(),
sfputl() or sfputd().
ssize_t sfpkrd(int fd, char* buf, size_t n, int rsc, long tm, int action)
This function acts directly on the file descriptor fd. It does a com-
bination of peeking on incoming data and a time-out read. Upon suc-
cess, it returns the number of bytes received. A return value of 0
means that the end-of-file condition has been detected. A negative
value represents an error.
buf, n:
These define a buffer and its size to read data into.
rsc: If >=0, this defines a record separator. See action for detail.
tm: If >=0, this defines a time interval in milliseconds to wait for
incoming data.
action:
When rsc >= 0, the absolute value of action, r, determines the
number of records to be read. If action > 0, sfpkrd() will peek
on incoming data but will not read past it. Therefore, a future
sfpkrd() or read(2) will see the same data again. If action ==
0, sfpkrd() will not peek. If action < 0, there are two cases:
if rsc < 0, sfpkrd() reads n bytes; otherwise, exactly r records
will be read. Note that, in the last case, reading records from
an unseekable device may be slow if the underlying platform does
not allow peeking on such a device.
FULL STRUCTURE SFIO_T
#include <sfio_t.h>
Most applications based on Sfio only need to include the header file
sfio.h which defines an abbreviated Sfio_t structure without certain
fields private to Sfio. However, there are times (e.g., debugging)
when an application may require more details about the full Sfio_t
structure. In such cases, the header file sfio_t.h can be used in
place of sfio.h. Note that an application doing this will become sen-
sitive to changes in the internal architecture of Sfio.
#define SFNEW(buf,size,file,flags,disc)
This macro function is defined in sfio_t.h for use in static initial-
ization of an Sfio_t structure. It requires five arguments:
buf, size:
These define a buffer and its size.
file: This defines the underlying file descriptor if any.
flags: This is composed from bit flags described above.
disc: This defines a discipline if any.
EXAMPLE DISCIPLINES
The below functions create disciplines and insert them into the given
streams f. These functions return 0 on success and -1 on failure.
int sfdcdio(Sfio_t* f, size_t bufsize)
This creates a discipline that uses the direct IO feature available on
file systems such as SGI's XFS to speed up IO. The argument bufsize
suggests a buffer size to use for data transfer.
int sfdcdos(Sfio_t* f)
This creates a discipline to read DOS text files. It basically trans-
forms pairs of \r\n to \n.
int sfdcfilter(Sfio_t* f, const char* cmd)
This creates a discipline that sends data from f to the given command
cmd to process, then reads back the processed data.
int sfdcseekable(Sfio_t* f)
This creates a discipline that makes an unseekable reading stream seek-
able.
int sfdcslow(Sfio_t* f)
This creates a discipline that makes all Sfio operations return immedi-
ately on interrupts. This is useful for dealing with slow devices.
int sfdcsubstream(Sfio_t* f, Sfio_t* parent, Sfoff_t offset, Sfoff_t
extent)
This creates a discipline that makes f acts as if it corresponds
exactly to the subsection of parent starting at offset with size
extent.
int sfdctee(Sfio_t* f, Sfio_t* tee)
This creates a discipline that copies to the stream tee any data writ-
ten to f.
int sfdcunion(Sfio_t* f, Sfio_t** array, int n)
This creates a discipline that makes f act as if it is the concatena-
tion of the n streams given in array.
int sfdclzw(Sfio_t* f)
This creates a discipline that would decompress data in f. The stream
f should have data from a source compressed by the Unix compress pro-
gram.
int sfdcgzip(Sfio_t* f, int opt)
This creates a discipline for reading/writing data compressed by zlib.
The argument opt defines the optimization level.
STDIO-COMPATIBILITY
Sfio provides compatibility functions for all various popular Stdio
implementations at source and binary level. The source Stdio-compati-
bility interface provides the header file stdio.h that defines a set of
macros or inlined functions to map Stdio calls to Sfio ones. This map-
ping may benignly extend or change the meaning of certain original
Stdio operations. For example, the Sfio's version of popen() allows a
coprocess to be opened for both reading and writing unlike the original
call which only allows a coprocess to be opened for a single mode.
Similarly, the Sfio's fopen() call can be used to create string streams
in addition to file streams.
The standard streams stdin, stdout and stderr are mapped via #define to
sfstdin, sfstdout and sfstderr. The latter are typically declared of
the type Sfio_t*. Certain older Stdio applications require these to be
declared as addresses of structures so that static initializations of
the sort ``FILE* f = stdin;'' would work. Such applications should use
the compile time flag SF_FILE_STRUCT to achieve the desired effect.
The binary Stdio-compatibility libraries, libstdio.a and libstdio-mt.a,
provide complete implementations of Stdio functions suitable for link-
ing applications already compiled with native header stdio.h. These
functions are also slightly altered or extended as discussed above.
Below are the supported Stdio functions:
FILE* fopen(const char* file, const char* mode);
FILE* freopen(const char* file, const char* mode, FILE* stream);
FILE* fdopen(int filedesc, const char* mode);
FILE* popen(const char* command, const char* mode);
FILE* tmpfile();
int fclose(FILE* stream);
int pclose(FILE* stream);
void flockfile(FILE* stream)
int ftrylockfile(FILE* stream)
void funlockfile(FILE* stream)
void setbuf(FILE* stream, char* buf);
int setvbuf(FILE* stream, char* buf, int mode, size_t size);
void setbuffer(FILE* stream, char* buf, size_t size);
int setlinebuf(FILE* stream);
int fflush(FILE* stream);
int fpurge(FILE* stream);
int fseek(FILE* stream, long offset, int whence);
void rewind(FILE* stream);
int fgetpos(FILE* stream, fpos_t* pos);
int fsetpos(FILE* stream, fpos_t* pos);
long ftell(FILE* stream);
int getc(FILE* stream);
int fgetc(FILE* stream);
int getchar(void);
int ungetc(int c, FILE* stream);
int getw(FILE* stream);
char* gets(char* s);
char* fgets(char* s, int n, FILE* stream);
size_t fread(Void_t* ptr, size_t size, size_t nelt, FILE* stream);
int putc(int c, FILE* stream);
int fputc(int c, FILE* stream);
int putchar(int c);
int putw(int w, FILE* stream);
int puts(const char* s, FILE* stream);
int fputs(const char* s, FILE* stream);
size_t fwrite(const Void_t* ptr, size_t size, size_t nelt, FILE* stream);
int fscanf(FILE* stream, const char* format, ...);
int vfscanf(FILE* stream, const char* format, va_list args);
int _doscan(FILE* stream, const char* format, va_list args);
int scanf(const char* format, ...);
int vscanf(const char* format, va_list args);
int sscanf(const char* s, const char* format, ...);
int vsscanf(const char* s, const char* format, va_list args);
int fprintf(FILE* stream, const char* format, ...);
int vfprintf(FILE* stream, const char* format, va_list args);
int _doprnt(FILE* stream, const char* format, va_list args);
int printf(const char* format, ...);
int vprintf(const char* format, va_list args);
int sprintf(const char* s, const char* format, ...);
int snprintf(const char* s, int n, const char* format, ...);
int vsprintf(const char* s, const char* format, va_list args);
int vsnprintf(const char* s, int n, const char* format, va_list args);
int feof(FILE* stream);
int ferror(FILE* stream);
int clearerr(FILE* stream);
RECENT CHANGES
A few exception types have been added. In particular, exception han-
dlers shall be raised with SF_LOCKED on accessing a stream frozen
either by an ongoing operation or a previous operation (e.g.,
sfgetr()). Before a process exits, the event SF_ATEXIT is raised for
each open stream.
A number of disciplines were added for various processing functions.
Of interests are disciplines to use the direct I/O feature on IRIX6.2,
read DOS text files, and decompress files compressed by Unix compress.
Various new stream and function flags have been added. For example, the
third argument of sfgetr() is now a set of bit flags and not just a
three-value object. However, the old semantics of this argument of
sfgetr() is still supported.
The sfopen() call has been extended so that sfopen(f,NULL,mode) can be
used to changed the mode of a file stream before any I/O operations.
This is most useful for changing the modes of the standard streams.
The buffering strategy has been significantly enhanced for streams that
perform many seek operations. Also, the handling of stream and file
positions have been better clarified so that applications that share
file descriptors across streams and/or processes can be sure that the
file states will be consistent.
The strategy for mapping between Sfio and Stdio streams in the binary
compatibility package has been significantly enhanced for efficiency.
For most platforms, the mapping is now constant time per look-up.
The SF_BUFCONST flag was deleted. This is largely unused anyway.
The library can be built for thread-safety. This is based largely on
Posix pthread mutexes except for on UWIN where native Windows APIs are
used.
The functions sfgetm() and sfputm() were added to encode unsigned inte-
ger values with known ranges.
The flag SF_APPEND is identical to SF_APPENDWR. However it conflicts
with a different token of the same name defined in the system header
stat.h of BSDI Unix systems. On such systems, we shall not define
SF_APPEND and this symbol may be removed in a future release.
Similarly, the exception SF_CLOSE is identical to SF_CLOSING. However
it conflicts with a different token of the same name defined in the
system header socket.h of AIX Unix systems. On such systems, we shall
not define SF_CLOSE and this symbol may be removed in a future release.
The printing and scanning functions were extended to handle multibyte
characters and to conform to the C99 standard.
The function sfpoll() was rehauled to make it useful for writing
servers that must commnunicate with multiple streams without blocking.
The formatting pattern %c for sf*printf was extended to allow the flag
# to print unprintable character values using the C convention. For
example, %#c prints the octal value 012 as \n.
AUTHORS
Kiem-Phong Vo, kpv@research.att.com,
David G. Korn, dgk@research.att.com, and
Glenn S. Fowler, gsf@research.att.com.
01 February 2005 SFIO(3)
Man(1) output converted with
man2html