| SFIO(3) | C LIBRARY FUNCTIONS | SFIO(3) |
|---|
#include <sfio.h> libsfio.a -lsfio libstdio.a -lstdio libsfio-mt.a -lsfio-mt libstdio-mt.a -lstdio-mt
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
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
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);
int sfmutex(Sfio_t* f, int type); SFMTX_LOCK SFMTX_TRYLOCK SFMTX_UNLOCK SFMTX_CLRLOCK
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);
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);
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);
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
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);
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));
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);
#include <sfio_t.h> #define SFNEW(buf,size,file,flags,disc)
#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);
#include <stdio.h> cc ... -lstdio -lsfio cc ... -lstdio-mt -lsfio-mt
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 automatically reinvoked to continue the ongoing operation.
The buffer of a stream is typically a memory segment allocated via malloc(3) or supplied by the application. File streams may also use memory 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).
This version of Sfio can be built and used for both uni-threaded and multi-threaded environments. In the former case, streams are not protected 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.
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.
rsrv = sfreserve(f, 10, 1);
for(i = 0; i < 10; ++i)
rsrv[i] = toupper(rsrv[i]);
sfwrite(f, rsrv, 10);
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 formatting element on the stack defines a separate formatting pair of a format 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 pattern ! discussed below.
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 function 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, consider a call from a sfprintf() function to process an
unknown pattern %t (which we may take to mean ``time'') based on a
formatting environment 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:
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:
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
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 double
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 portable and
only works on platforms where sizeof(Sflong_t) is 8.
The second example shows how to that portably.
The third example 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 pattern %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 represented by digits for this base.
For example, a base 2 conversion 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.
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-alphanumeric 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|
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 character 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
sfsscanf("12345678","%.*.*d", 4, 10, &v);
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 double
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 general 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 example, 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 distinguishable. If base is larger than 36, the set of digits is:
0123456789
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ @_
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.
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 earlier on the stack. Note that a file stream always has read(2), write(2), lseek(2) and NIL(Sfexcept_f) as the logical bottom discipline. 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 during 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:
The argument type of (*exceptf)() identifies the particular exceptional event:
The below functions create disciplines and insert them into the given streams f. These functions return 0 on success and -1 on failure.
Sfio provides compatibility functions for all various popular Stdio implementations at source and binary level. The source Stdio-compatibility interface provides the header file stdio.h that defines a set of macros or inlined functions to map Stdio calls to Sfio ones. This mapping 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 linking 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);
A few exception types have been added. In particular, exception handlers 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 integer 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.
| 01 February 2005 | November 07, 2006 |