scs@avarice.pika.mit.edu (Steve Summit) (02/11/90)
This posting contains an essentially complete, "nearly" public domain reimplementation of the "standard I/O" package. ("`Nearly' public domain" means that there are the usual few restrictions; see the copyright notices and COPYING file for details.) A paper is included describing this package, the new features it contains, and its implementation. The abstract of that paper serves as a useful introduction: This paper describes a new implementation of the traditional C/UNIX stdio package. Although retaining the efficiency and (to the extent possible) the compactness of the original, this implementation contains several significant improvements, including user-definable underlying I/O functions, improved error handling, new routines for "string" I/O, and efficient unbuffered I/O. This package is intended to be compatible with the proposed ANSI C standard, although it contains new functions not mentioned in that standard. I am posting this to alt.sources because, although it is mostly "finished," I have not performed the exhaustive testing and evaluation of it that I would like to. The mainstream source group moderators are welcome to pick it up and repost it, if that seems appropriate. (A later, "released" version will definitely be posted on a mainstream source newsgroup.) Mail from the world at large into my home machine (adam) is sporadic at best; if you can't reach me, post articles to alt.sources.d and/or comp.sources.d . (On the other hand, I don't keep up with usenet much of late, so do send mail if it's important and you can.) Besides the descriptive paper and the COPYING file, the README file may be of interest to those delving into the code. (It contains my notes about work in progress, open design decisions, future directions, etc.) I must admit that I haven't worked on or even looked at this package for some time; even its bundling for posting happened last September, although downed machines and absent-mindedness delayed it until now. All this means is that I might be as surprised at what this posting contains as you; I can't remember exactly what shape I thought it was in. I do notice that it contains a very experimental and incomplete function called askf which I hadn't thought I'd post at first; you may well want to remove the -DASKF from CFLAGS in the Makefile. The code as it stands was developed and tested on a (!) pdp11 running a V7 derivative. I don't remember if I have tested it on a Vax or not. It should run under 4BSD without difficulty; AT&T Unix might require a bit of work. Eventually, I'll get it running under MS-DOS (and maybe VMS); these possibilities have been anticipated and an attempt made to keep the code maximally portable, although significant changes (particularly with respect to non-byte-offset lseek cookies, and significant "binary" file distinctions) will certainly be necessary. I might also point out that any claims about X3J11 conformance are essentially hollow promises at this point; I still haven't read an official copy or done any careful work to ensure ANSIness. Steve Summit scs@adam.mit.edu scs@hstbme.mit.edu (temporary) ------8<--------8<--------8<----stdio1.shar----8<--------8<------ overwritecheck=yes verbose=yes while true; do case $1 in -f) overwritecheck=no shift;; -q) verbose=no shift;; -v) verbose=yes shift;; -*) echo "shar: unknown option $1" 1>&2 shift;; *) break;; esac done if test $overwritecheck = no -o ! -f paper.ms; then case $verbose in yes) echo "extracting paper.ms";; esac sed 's/^X//' > paper.ms <<\EOF X.ie n \{\ X.ds `` "" X.ds '' ""\} X.el \{\ X.ds `` \(lq X.ds '' \(rq\} X.de Rt X.if n \{\ X.na X.nh \} X.. X.de SE \" sentence X.. X.RP X.ds LH STDIO Reimplementation X.ds CH X.ds RH Page % X.ds CF \\*(DA X.TL XA Reimplementation of the Standard I/O Package X.AU XSteve Summit X.AB X.PP X.Rt XThis paper describes a new implementation of the traditional XC/\c X.UX Xstdio package. XAlthough retaining the efficiency and X(to the extent possible) Xthe compactness of the original, Xthis implementation contains several significant improvements, Xincluding Xuser-definable underlying I/O functions, Ximproved error handling, Xnew routines for \*(``string\*('' I/O, Xand Xefficient unbuffered I/O. XThis package is intended to be compatible with the proposed X.SM XANSI X.LG XC standard, although it contains new functions not mentioned in Xthat standard. X.sp .5i X.LP XCopyright 1989 by Steve Summit. X.br XAll Rights Reserved. X.br XNoncommercial redistribution permitted; Xcommercial, for-profit use will require permission of the author. X.AE X.SH XIntroduction X.PP X.Rt XThe \*(``Standard I/O\*('' (stdio) package traditionally associated with Xthe C language (as part of its run-time library) has proven to be Xan effective and valuable subsystem. XThis paper describes a new implementation of the stdio package. XThis implementation has been undertaken for several reasons: X.IP 1. 6 2 XTo provide a testbed for extensions and additions to the the Xtraditional stdio feature set, Xnotably \*(``user-defined\*('' I/O processing; X.IP 2. XTo provide X.SM XANSI X.LG XC functionality on systems which are not yet standard-conforming; X.IP 3. XTo provide a package, in source form, (relatively) free from Xlicense and copyright restrictions; and X.IP 4. XBecause it was there. X.LP XThe following sections describe the principal improvements Xpresent in this package, Xas well as a few implementation, installation, and maintenance issues. X.SH XUser-Definable I/O Functions X.PP XIt is frequently desirable to have stdio-like high-level behavior X(printf, etc.) which results in something other than calls to the low-level X.I read Xand X.I write Xfunctions. XAn alternative frequently suggested, Xand implemented in this package, Xis to allow functions other than the standard ones to be Xassigned, on a per-stream basis. XFor example, a windowing system might have a low-level call, X.I wwrite , Xfor writing text into a window. XIf X.I wwrite Xis installed as the underlying write function for a stream, Xthe full flexibility of fprintf X(and fputs and fputc, if desired) Xbecomes available for window output. XNo parallel reimplementation X(\*(``wprintf\*('' or the like) Xis required. X.PP XThe definable low-level functions are a read function, a write Xfunction, a seek function, and a close function. XThese functions, whatever their implementation, are assumed to Xtake the same arguments, and return the same values, as the X.UX Xsystem calls X.I read , X.I write , X.I lseek , Xand X.I close . XHowever, it is possible for the underlying \*(``handle\*('' to be a Xpointer (\fCchar\ *\fP, or X.SM XANSI X.LG X\fCvoid\ *\fP) Xrather than an integer descriptor. X.PP XWhen the characters being read or written are not mapped to an XI/O-like character stream at all (for instance when a stdio Xstream is \*(``writing\*('' to a dynamically allocated in-memory buffer) Xit may be desirable to gain more control over stdio's buffering Xprocess. XFor this reason, the internal stdio buffering functions X.I _filbuf Xand X.I _flsbuf Xare also redefinable. X.SH XError Handling X.PP XC programs are notoriously poor at handling I/O errors. XOn input, an error is not immediately distinguishable from EOF, Xand few programs bother to check (using X.I feof Xor X.I ferror ). XOn output, Xalthough an error code is potentially returned by each call to Xprintf, it is the very rare program that checks every return Xvalue, and it is arguably inappropriate to do so. X(The source and object code bloating resulting from exhaustive Xprintf return value checking would be intolerable for many programs.) X.SE XYet the underlying stdio implementation has complete error Xinformation available, since it does (as it must) check for Xerrors resulting from any low-level I/O function. X(These checks are not inefficient in time or space, since they Xare made in only a few centralized routines, and on a per-bufferful Xrather than per-character basis.) X.PP XThis implementation of stdio can have an error handling function Xassociated with each stream. XA stream's error handler is called if any low-level I/O error Xoccurs. XThe default error handler prints an error message (to stderr) Xincluding the file name (if known), Xthe kind of error X(read, write, etc.) Xand the perror text. XIn the case of write errors, the default error handler aborts the Xprogram. XFor read errors, the normal EOF is returned. X.PP XAborting a program due to a write error is certainly a harsh Xpenalty. XThe decision to do so was made based on the following Xobservations: X.IP 1. 6 2 XVery, very few programs check for write errors. X.IP 2. XThe most common write error (in my experience) is \*(``file system Xfull\*('' (\s-2ENOSPC\s0). XRunaway programs continuing to write to a full filesystem (often X/tmp) are extremely unpleasant and can bring a system to its knees. X.PP XTo be sure, there are programs X(notably text editors, databases, and revision control systems) Xfor which write errors should most certainly X.I not Xcause an abort. XSuch programs, if linked against this stdio package, can use one Xof several mechanisms to replace the default error handler with a Xmore appropriate one. XThese programs are fairly easy to identify, as they have Xtypically been recognized as requiring more-careful-than-usual Xwrite return value checking. X(It is unfortunate that those few programs which are likely to Xbe penalized by the behavior of the default error handler are the Xsame ones that have been responsible enough to check for write errors Xalready.) X.PP XIf the automatic abort due to a write error is felt to be Xcompletely inappropriate, it can be disabled (at library compile Xtime) by #defining \s-2WRITEERRNOTFATAL\s0. X.SH XUnbuffered I/O Efficiency X.PP XAn unbuffered stream does not (by definition) have an associated Xbuffer, from which contiguous characters can be passed to X.I write . XTraditionally, an unbuffered stream performed low-level X.I read s Xand X.I write s Xone character at a time, Xresulting in a potentially devastating performance degradation due to Xsystem call overhead. XHowever, in many cases (particularly for output streams) the Xcalling program's stdio calls do refer to contiguous chunks of characters, Xmaking the character-at-a-time low-level performance particularly Xunnecessary. X.PP XThis package can perform unbuffered I/O of longer strings of Xcharacters when the characters are detectably contiguous in the Xcalling program, obviating the need for a stdio buffer. XThis optimization is performed in the following cases: X.IP \(bu 6 2 Xfread X.IP \(bu Xfwrite X.IP \(bu Xfputs X.IP \(bu Xputs X.IP \(bu Xfprintf and printf, Xfor constant text (between %'s) in the format string, Xfor strings printed with %s, Xand for formatted numbers printed with %[doxuefg]. X.PP XThis option does of course increase the code size slightly. XThe optimization is conditional on the preprocessor macro \s-2FASTNBF\s0. X.PP XThe X.SM XFASTNBF X.LG Ximplementation does X.I not Xsimply assign a temporary buffer during calls to printf and fprintf, Xas is done by some other versions. XRather, special cases in the lowest-level output routines check Xfor the _IONBF flag in situations when multiple adjacent Xcharacters are likely to be available. XThis technique is less desirable from a code cleanliness standpoint X(special cases are always ugly), but it is vastly preferable from Xa performance standpoint: Xtemporary buffer assignment within fprintf is nonreentrant and unsafe. X.PP XThe existence of the X.SM XFASTNBF X.LG Xoption should remove any temptation Xto make stderr buffered. X(A few programs, Xnotably tar with the v option, Xand to a lesser extent RCS, Xprint significant quantities of text to stderr, Xwhich is noticeably slow on loaded systems or over network connections, Xand which occasionally lead to suggestions to buffer stderr, Xwhich would be a horrible idea.) X.SH XNew \*(``String I/O\*('' Functions X.PP XStdio has always contained the \*(``string I/O\*('' functions X.I sscanf Xand X.I sprintf , Xwhich read/write not to a file but an in-memory string. XThese functions are convenient and surprisingly easy to Ximplement, but they suffer from annoying and unnecessary Xlimitations. XIn particular, it is in general impossible to guarantee that X.I sprintf Xwill not overflow its output string, overwriting other Xmemory with potentially dire effects. X.PP XThis package adds the following new \*(``string I/O\*('' functions: X.IP snprintf 10 Xlike X.I sprintf , Xbut allows a maximum output string length to be Xspecified. X.IP saprintf Xlike X.I sprintf , Xbut returns a pointer to dynamically-allocated Xmemory (obtained with X.I malloc ) Xlarge enough to contain the formatted string. X.IP strnopen XReturns a general-purpose stream, \*(``opened\*('' on a string, Xin either \*(``r\*('', \*(``w\*('' or \*(``a\*('' mode X(the modes have a similar interpretation as for X.I fopen ). XThe string length can be specified, to avoid overwriting on Xoutput, Xor to limit the portion of the string read on input X(i.e. stopping before to the default '\e0'). X.IP X.I strnopen Xallows multiple, arbitrary I/O calls to be performed on a single Xstring X(\fIsprintf\fP essentially allows just one X.I printf ). X.IP stropen Xlike X.I strnopen , Xbut without the explicit string length argument, Xand therefore potentially unsafe for output. X.IP straopen Xlike X.I stropen , Xbut builds dynamically-allocated output buffer \*(``on the fly\*('' (like X.I saprintf ). X.SH XInterface With Other Libraries X.PP XOccasionally, the fact that stdio traditionally makes direct Xcalls to other library routines X(such as X.I malloc ) Xis troublesome. XFor instance, a program might have its own \*(``wrapper\*('' functions Xaround X.I malloc Xand X.I free , Xthat perform consistency checking or Xstorage reclamation. X XThe only routines called Xby this implementation of stdio are: X.DS I X.ta \w'write'u+3m Xopen malloc Xread realloc Xwrite free Xlseek fstat Xclose isatty X.DE XOf these, all but X.I fstat Xand X.I isatty Xcan be redefined either at Xlibrary compilation time or at run time. X.I fstat Xand X.I isatty Xcan only be redefined at compile time. X(\fIfstat\fP and X.I isatty Xare only used for buffering decisions on X\*(``normal\*('' streams. X.I fstat Xis only used on systems, such as 4.2bsd, which have a Xst_blksize field in the stat structure.) X.PP X.I popen Xand X.I pclose Xadditionally call X.I pipe , X.I fork , X.I exec , Xand X.I wait , Xwhich are not currently redefinable. X.PP XThe fact that the X.I read , X.I write , X.I lseek , Xand X.I close Xfunctions are Xredefinable (this refers to the default functions, in addition to Xthe fact that they are also redefinable on a per-stream basis) Xcan be exploited to X.IP Xbuild an application on top of a user-mode distributed file Xsystem, which uses special X.I open , X.I read , Xand X.I write Xcalls X.IP Xengender true X.SM XANSI X.LG Xcompliance, by using reserved symbols X(e.g. X.I __read , X.I __write , Xetc.) X.SH XMiscellaneous Extensions X.PP XThis package contains the usual host of gratuitous creeping Xfeatures. XThe following new functions, described briefly here, are Xdocumented more fully in separate \*(``man\*('' pages. XThough nonstandard, they should be \*(``safe:\*('' Xthey are not relied upon by other parts of the library, Xso user-defined routines which happen to have these names should Xnot cause problems (other than of course that the overridden Xroutines are unavailable). X.IP fabort 10 XDiscard buffered characters, without flushing them. X.IP fdclose XClose a stream, without closing the low-level descriptor. X.IP flushall XCall X.I fflush Xon all open streams. X.IP saprintf XFormatted print to dynamically-allocated string. X.IP scanfiles XCall some function for each open stream. X.IP seterrfn XInstall an error handler for a stream, Xor set the default error handler for all streams. X.IP setfuncs XInstall the four low-level I/O functions for a stream, Xor set the default functions for all streams. X.IP snprintf XFormatted print to string, specified length not to be exceeded. X.IP stropen X\*(``open\*('' string for stream-like I/O. X.IP straopen XOpen dynamically-allocating string stream. X.IP straptr XReturn current output pointer for \fIstraopen\fPed stream. X.IP straclose X\*(``Close\*('' \fIstraopen\fPed stream and return final output pointer. X.IP strnopen X\*(``Open\*('' length-specified string for stream-like I/O. X.IP vfscanf XLike X.I fscanf , Xbut takes variable argument list pointer (va_list) Xrather than explicit variable arguments. X(Analogous to X.I vfsprintf , Xfor input) X.IP vscanf XLike X.I vfscanf , Xbut assumes stdin. X.IP vsscanf XLike X.I vfscanf , Xbut \*(``reads\*('' a string. X.IP vsaprintf XLike X.I saprintf , Xbut takes a single va_list X(encapsulating a variable number of arguments) Xrather than the variable arguments themselves. X.PP XThe internal function X.I _cleanup , Xcalled by X.I exit Xto clean up open streams, Xflushes them (\fIfflush\fP) rather than closing them (\fIfclose\fP). XThe traditional close occasionally causes problems, to wit: X.IP \(bu Xwhen a user-definable function called during the cleanup process Xattempts to print a debugging or diagnostic message, but stdout Xand stderr are already closed; or X.IP \(bu Xwhen the program calling stdio is operating under the auspices of Xan interpreter or in-process debugger, since it may run multiple Xtimes within the same process, and must keep at least the three Xstandard file descriptors open. X.PP X.I printf X(and, by extension, X.I fprintf , X.I sprintf , Xand the others) Xaccept a few new format specifiers. XThese accept the standard field width and other modifiers as well. X.IP %b 8 XBinary. X%#b prints a leading \*(``0b\*(''. X.IP %r,%R XRoman numerals. X%r uses lower-case letters; %V upper-case. X.PP XA X.SM XNULL X.LG Xpointer passed to %s prints as \*(``(null)\*(''. X.PP XI was about to implement a way for the application to register Xnew format characters for user-defined conversion, Xwhen I heard that this had already been conceived and implemented X(in 8th edition X.UX X, I believe). XI will implement this function once I learn the specifications Xfor the existing implementation so I can emulate it compatibly. X.PP XI am investigating the possibility of allowing X.I setvbuf Xand Xrelated functions to be called at any time. X(Traditionally, setting the buffer is allowed only immediately Xafter a stream is opened, before any I/O is performed.) X.SE XAlthough this extension is theoretically possible, it is proving Xto be somewhat expensive in code space, with limited payoff since Xno portable application will make use of it. X(In fact, I am not sure that nonportable applications would have Xmuch use for this functionality, either. XThe attempt was mainly undertaken on the general principle that Xarbitrary limitations should be avoided.) X.SH XLimitations X.PP XAlthough this package has been conscientiously written, Xand will be carefully evaluated, Xthe breadth of the stdio specification is sufficient that there Xmay well be areas in which this implementation is inadequate. X.PP XOne area in which inadequate implementation is likely is the Xsimultaneous read/write mode (\s-2_IORW\s0; the \*(``r+\*('', X\*(``w+\*('', and \*(``a+\*('' arguments to X.I fopen ). XThe author Xis not particularly enthralled with Xthe use of these modes, and Xconsequently is unaware of their full implications. XOn the other hand, Xa version of RCS linked against this implementation Xhas been performing flawlessly for over a year, Xso the X.SM X_IORW X.LG Ximplementation is not completely without merit. X(It was during a port of RCS to the author's V7 X.SM XPDP11 X.LG Xwithout X.SM X_IORW X.LG Xin the libc.a stdio that the code here was first added. XRCS not only uses \*(``w+\*('' but is also a critical program which Xcannot tolerate library malfunction without corrupting files, Xso it is a fairly good \*(``torture test\*('' for at least those Xaspects of the library which it does exercise.) X.PP XThe author is similarly ambivalent about the use of the X.I scanf Xfamily. XThe scanf code here presented is a straightforward but uninspired Ximplementation. XIt has been superficially evaluated, Xand although it does fix at least one bug Xwhich is present in some of the more standard implementations, Xit is likely that it contains a few bugs Xpertaining to the more obscure cases. X.SH XBuilding X.PP XThe library is built using the X.UX Xutility X.I make ; Xthe usual Makefile is enclosed. XA number of conditional compilation switches exist; some have Xalready been mentioned here. XThe following list (and the equivalent one in a comment in the XMakefile) attempts to recapitulate all of the available Xconditional compilation options. X(Since new ones are continually added, however, only the source Xcode can be considered definitive in this regard.) X.IP bsd4_2 \w'WRITEERRNOTFATAL'u+2m XThe code is being compiled under a 4.2bsd or later or derived system. XThe distinction is whether the stat structure contains a "natural Xblock size" field st_blksize. X.IP CLEANUPCLOSE XThe X_cleanup Xfunction, called from X.I exit , Xshould close each open stream, rather than simply flushing it. X(The standard stdio implementations typically close files during X.I _cleanup ; Xthe decision to merely to flush them is peculiar to this package.) X.IP FASTFRDWR XThe code for X.I fread Xand X.I fwrite Xtransfers characters between the calling program and the stdio buffer X(and directly to or from the operating system, Xbypassing the buffer, if possible) Xin large chunks. X.IP FASTNBF XSpecial cases throughout the code recognize the opportunity to Xcall the underlying write function with a string of contiguous Xcharacters, rather than mindlessly one at a time, when a stream Xis doing unbuffered (_IONBF) output. X.IP FORCECLEANUP XA dummy external reference in a central object file forces the Xmodule in this library containing the X.I _cleanup Xroutine to be loaded. XSince X.I cleanup Xis typically only called by X.I exit , Xand since X.I exit Xis loaded from the standard library (/lib/libc.a or the like), Xthe copy of X.I _cleanup Xfrom the standard library would otherwise typically be loaded. X.IP PUTCLBUF XThe line-buffered check for newline characters ('\en') is Xperformed directly by the X.I putc Xmacro, rather than being buried in X.I _flsbuf . XThe tradeoff is the classic one between execution speed and code Xsize: the macro version can bloat the object code considerably, Xwhile the non-macro version requires a function call per Xcharacter output. X.IP READWRITE XThe (quasi) simultaneous read/write mode X(_IORW, fopen "r+", "w+", and "a+") Xis enabled. X.IP SAFEREALLOC XThe X.I realloc Ximplementation being used checks its first argument and, Xif NULL, essentially performs a X.I malloc . X(SAFEREALLOC is automatically turned on if __STDC__ is defined.) X.IP SETBUFANYTIME XThe various X.I setbuf Xfunctions are permitted at any time during the life of a stream, Xnot necessarily just after opening and before doing any I/O. X(SETBUFANYTIME is not really implemented yet, and may never be.) X.IP STDINFLUSH XWhen a read is pending on stdin, stdout is flushed. X(This is a historically early form of "line buffering," and is Xsuperceded by true line buffering if it is in effect.) X.IP STICKYEOF XThe EOF condition is not only remembered but also checked on Xsubsequent calls without necessarily bothering to try another read. XThe primary consequence is that when a program receives EOF from Xa terminal (normally triggered by control-D under X.UX X), but wishes to continue, it must explicitly call X.I clearerr . X.IP X"Sticky" EOF breaks lots of programs. XIt was introduced in 4.2bsd, and is (conditionally) included here Xfor compatibility. X.IP THREEARGOPEN XThe system's X.I open Xtakes an O_CREAT flag and an optional third argument, Xthereby superceding the X.I creat Xcall. X(The THREEARGOPEN distinction isn't really finished yet.) X.IP WRITEERRNOTFATAL XThe default error handling function should X.I not Xabort the program on write errors. X.LP XA few source files have additional conditional switches which are Xenabled or disbled by editing the particular source file, rather Xthan setting them through the global CFLAGS macro in the Makefile. XThe file doprnt.c X(the common code for the X.I printf Xfamily) Xhas several: X.IP BINARY XThe %b extension is enabled. X.IP FLOATING XThe floating-point formats (%e, %f, and %g) are enabled. X.IP NOUNSLONG XThe compiler does not support the \fCunsigned long\fP type, Xso it must be simulated. X.IP NULLPTR XA NULL (0) pointer passed to the %s format is printed as "(null)" X(or whatever string the NULLPTR macro is #defined to). X.IP ROMAN XThe Roman numeral formats (%v and %V) are enabled. X.SH XImplementation X.PP XThis package has been written from scratch; it contains no Xproprietary code. XSome care has been taken to make it compatible with the X\*(``standard\*('' implementations, on more than just a public Xinterface level. X(By \*(``standard\*('' I refer to the V7 stdio, from which BSD Xstdio and\(emI believe\(emSystemIII/V stdio are descended.) X.SE XIn particular, the _iobuf structure defined in stdio.h contains Xfields with the same names, and in many cases with the same offsets. XA few internal routines, notably X.I _filbuf , X.I _flsbuf , X.I _doprnt , Xand X.I _doscan , Xretain the same names and calling sequences. XThis consistency should make it easy for those familiar with the X\*(``standard\*('' implementations to understand this version, Xand also admits the possibility for object file compatibility, Xand the possibility that applications which made nonportable Xassumptions about stdio internals will continue to work. XThese possibilities are discussed further in the next section. X.PP XThe new features implemented by this package primarily involve Xnew fields in the _iobuf structure; these new fields are Xdescribed here. X.PP XThe _readfunc, _writefunc, _seekfunc, and _closefunc are pointers Xto functions returning int, int, long int, and int, respectively. XThe functions take the same arguments as do the corresponding X.UX Xsystem calls read, write, lseek, and close. XAny of the function pointers may contain the value NULL; Xthe corresponding function is then assumed not to exist. X(When an attempt is made to access a nonexistent function, Xthe effect is to disallow the requesting operation. XFor example, streams without read functions can essentially not, Xthat is not usefully, be fopened mode \*(``r.\*('') X.PP XBy setting all or some of the function pointers to some other Xfunction than the default, and setting an appropriate _file X(\*(``file descriptor\*('') value, it can be arranged that the \*(``I/O\*('' Xthat underlies a buffered stream involve almost anything. XExamples might include I/O to windows, encryption or decryption, Xnormal file-descriptor-based I/O with special cleanup functions Xon close, etc. X.PP XIn case the \*(``handle\*('' for the special I/O functions being used is Xa structure pointer (rather than the usual small integer descriptor) Xa pointer-sized field is available in the _iobuf struct for this Xpurpose. XThe X.SM X_IOFPTR X.LG Xbit in the _flag field indicates that the pointer Xfield (_fptr) should be passed as the first argument to I/O Xfunctions, rather than _file. X.PP XWhen the special processing which is to be performed \*(``underneath\*('' Xa user-defined stdio stream cannot conveniently be encapsulated Xin \*(``read\*('' and \*(``write\*('' functions, it is possible to gain control Xat a higher level. XA stream can also have its own _filbuf and/or _flsbuf function Xinstalled, which will gain control whenever the buffer Xunder/overflows. XThe _filbuf and _flsbuf functions (and their replacements) have Xaccess to the complete _iobuf structure, and can therefore Xinteract with the buffer in arbitrary ways. XThe primary example is the saprintf function, which dynamically Xgrows the buffer, in-memory, to keep it big enough for the string Xbeing formatted. X.PP XCustomized _filbuf and _flsbuf functions are potentially difficult to write, Xrequire access to the normally private fields of the _iobuf Xstructure (therefore requiring recompilation if not rewriting Xwhen that structure changes), are nonportable, and are Xpotentially short-lived as other internals of this package change. X(The only current use of a such a customized function is the Xspecial _flsbuf function which arranges for the dynamic growth Xof the outbut buffers for X.I saprintf , X.I vsaprintf , Xand X.I straopen .) X.PP XNot surprisingly, this library contains a number of \*(``internal\*('' Xroutines, not to be accessed by calling programs, but which Xnonetheless have names in global scope. XThe naming conventions for such routines are often problematical. X.PP XUnder the old rules, leading underscores were informally reserved Xto \*(``the implementation,\*('' so library writers typically named Xinternal routines with leading underscores and crossed their Xfingers and hoped that there were no name clashes between Xlibraries. X(This is relatively easy when there is exactly one standard C Xlibrary containing multiple facilities.) X.PP XANSI C has, in this area as in so many others, clarified and Xstrengthened the rules quite a bit. XNames with a single leading underscore have been abandoned to the Xapplication; internal library routines must now begin with two Xunderscores or with an underscore followed by an uppercase letter. X.PP XA standalone library implementation such as this one falls into a Xgrey area, however. XIt should not use names beginning with two underscores, since Xthose are now officially reserved to the implementor of the C Xlibrary delivered with the compiler. XOn the other hand, it should not use names beginning with one Xunderscore, because those are now available to the application. X.PP XPresumably, the application level is now allowed to use names Xbeginning with a single underscore so that it may usurp the X\*(``leading underscores are internal library routines\*('' convention Xfor use by its own, project-level libraries. XSince, from the point of view of the compiler, this standalone Xstdio library is more like a project library, and since single Xunderscores were used by the historical implementations with Xwhich (for now) I am attempting to maintain object-level Xbackwards compatibility (see below), this library currently Xuses single underscores (followed by lower-case letters) for Xits internal symbols. X.PP XIt is expected that the names of these internal symbols may Xchange as the proper role and implementation strategies for Xstandalone C sublibrary replacements become better defined. X.SH XObject-Level Compatibility X.PP XConsistency at the object file level means that, under certain Xcircumstances, object files and libraries which were compiled Xagainst the standard <stdio.h>, and intended to be linked against Xthe standard library, may be linked against this package without Xrecompiling. XAdditionally, source files that (antisocially) inspect or modify Xthe contents of an _iobuf structure may compile and function Xcorrectly with this version. X.PP XObject-level compatibility obviously cannot be guaranteed. XHere are a few guidelines outlining the likelihood for success in Xsuch an endeavor: X.IP 1. XObject files which reference only the _ptr, _cnt, and _base Xfields are almost guaranteed to work, provided they do so in X\*(``normal\*('' ways, calling _filbuf or _flsbuf as appropriate Xwhen the buffer is empty or full. X.IP 2. XObject files which reference stdout or stderr are guaranteed X.I not Xto work, since the size of a struct _iobuf is considerably larger Xin this version, and &_iob[1] therefore has a different offset. XThis means, for example, that: X.RS X.IP Xan old fprintf.o will work X.IP Xan old printf.o will not work X.IP Xan object file that calls only printf will work (provided it is Xlinked against an updated printf.o) X.IP Xan object file that calls fflush(stdout) Xor fprintf(stderr, ...) Xwill not work. X.RE X.IP 3. XSource files which reference the standard fields, and use the Xstandard values for the _flag field, are likely to work, although Xthere are certainly source files out there which make assumptions Xso dangerous that they will only work with the exact version of Xstdio which they were written against. X.IP XIn particular, I expect that many printf lookalikes (varargs Xfunctions that call _doprnt themselves) will continue to work, Xalthough of course they would be well-advised to convert to Xvprintf or vfprintf. Xscanf lookalikes (how common are they?) that call _doscan should Xwork as well (they have, as yet, no portable vscanf to call). Xsprintf emulators, which handcraft a stack-allocated X_iobuf, may also work, but will probably crash if they overflow Xthe buffer, since an uninitialized _flsbuf function will likely Xbe called even before X.SM X_IOSTRG X.LG Xis checked. Xsscanf emulators are almost guaranteed to fail at \*(``EOF\*('' for this Xreason. EOF chmod 664 paper.ms shouldbe=28794 size=`wc -c < paper.ms` if test $size -ne $shouldbe; then echo "shar: $0: error extracting paper.ms ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file paper.ms" 1>&2; fi if test $overwritecheck = no -o ! -f COPYING; then case $verbose in yes) echo "extracting COPYING";; esac sed 's/^X//' > COPYING <<\EOF XIt's a sad commentary on the current times that I have to include Xthis file at all. I'm sorry that I have to (or that I think I Xhave to). I'd like to simply spread this code around under sort Xof a "gentleman's agreement" of reasonable behavior, but Xattitudes about copyright, liability, and the like these days Xoften seem to be anything but reasonable. X XThe copyright notices scattered through this package all say Xsomething like "Copyright by Steve Summit. Freely Xredistributable if these notices are retained. Commercial use Xwill require permission of the author." This means that you can Xdo practically anything you want with this code provided that: X X 1. you leave my name and copyright on it, and don't try to X misrepresent as your own, and X X 2. you don't charge money for the code as such. X XThe second point deserves elaboration. I don't mind if you use Xthis package as an internal tool within a commercial Xorganization. I also don't mind if you link products against this Xpackage and then sell those products (containing linked-in, Xexecutable code derived from these sources). What I don't want Xyou to do, without asking me first, is to sell the library as a Xlibrary, in source, object, or object library form, either by Xitself or as part of a larger C run-time library. I may give you Xpermission to do this, but I will first want to discuss Xmaintenance, liability, and remuneration. X XA note about liability: I accept responsibility for this code, Xbut not liability. This is high-quality code, and it should work Xwell for you. If it doesn't, I'd like to hear about it, and I'll Xprobably try to fix it. I'll even offer a no-questions-asked, Xmoney-back guarantee: if for any reason you are not satisfied Xwith the performance of this code, simply return it for a prompt Xrefund of your original purchase price. However, if you use this Xcode in such a way that its failure costs you time, money, or X(heaven help us!) personal injury, I cannot be held liable for Xthose damages. X XI'm no lawyer, and this file is probably not legally binding. X(Among other things, it uses lower-case letters as well as Xupper-case, and tends not to use a string of synonyms where one Xword will do.) If you wanted to, you could probably figure out a Xway to circumvent the copyright notice and steal this code and Xmake money off of it, or to sue me if its failure did cost you Xtime, money, or personal injury. Let me merely point out that Xneither of these actions would be very gentlemanly, and that I do Xnot have deep pockets. If you want to sue somebody, I would Xsuggest you pick the largest corporation on the news feed path Xfrom my site to your site. EOF chmod 664 COPYING shouldbe=2660 size=`wc -c < COPYING` if test $size -ne $shouldbe; then echo "shar: $0: error extracting COPYING ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file COPYING" 1>&2; fi if test $overwritecheck = no -o ! -f Makefile; then case $verbose in yes) echo "extracting Makefile";; esac sed 's/^X//' > Makefile <<\EOF XHOME = /usr/stevesu X XOBJS = cleanup.o doprnt.o doscan.o errfunc.o \ X fabort.o \ X fclose.o fdopen.o fflush.o fgetc.o \ X fdclose.o flushall.o \ X fgets.o filbuf.o flsbuf.o fopen.o fprintf.o fputc.o \ X fputs.o fread.o freopen.o fscanf.o fseek.o ftell.o fwrite.o gets.o \ X getbuf.o \ X getw.o printf.o putpad.o puts.o putw.o rewind.o scanf.o scanfiles.o \ X funcs.o funcs2.o iob.o \ X strutil.o strautil.o \ X popen.o \ X setbuf.o setvbuf.o \ X setbuffer.o setlinebuf.o \ X setfuncs.o seterrfn.o \ X stropen.o strnopen.o \ X straopen.o \ X snprintf.o saprintf.o \ X sprintf.o sscanf.o ungetc.o \ X vfprintf.o vprintf.o vsprintf.o \ X vsaprintf.o \ X vfscanf.o vscanf.o vsscanf.o \ X memcpy.o X XINC2 = $(HOME)/include X XCFLAGS = -O -I. -I$(INC2) -DFORCECLEANUP -DSTICKYEOF -DSTDINFLUSH -DREADWRITE \ X -DFASTFRDWR -DFASTNBF -DASKF -DSAFEREALLOC -Dvoid=int X Xlibstdio.a: $(OBJS) X ar r $@ $? X ranlib $@ X Xfst: fst.o libstdio.a X $(CC) -o fst fst.o libstdio.a -lc2 X Xfwrt: fwrt.o libstdio.a X $(CC) -o fwrt fwrt.o libstdio.a -lc2 X Xscantest: scantest.o doscan.o X $(CC) -o $@ scantest.o doscan.o X Xscantest.std: scantest.o X $(CC) -o $@ scantest.o X Xaskf.o: askf.c stdio.h Xdoprnt.o: doprnt.c stdio.h printf.h Xdoscan.o: doscan.c stdio.h Xerrfunc.o: errfunc.c stdio.h Xfabort.o: fabort.c stdio.h Xfclose.o: fclose.c stdio.h Xfdclose.o: fdclose.c stdio.h Xfdopen.o: fdopen.c stdio.h Xfflush.o: fflush.c stdio.h Xfgetc.o: fgetc.c stdio.h Xfgets.o: fgets.c stdio.h Xfilbuf.o: filbuf.c stdio.h Xflsbuf.o: flsbuf.c stdio.h Xfopen.o: fopen.c stdio.h funcs.h Xfprintf.o: fprintf.c stdio.h Xfputc.o: fputc.c stdio.h Xfputs.o: fputs.c stdio.h Xfread.o: fread.c stdio.h Xfreopen.o: freopen.c stdio.h funcs.h Xfscanf.o: fscanf.c stdio.h Xfseek.o: fseek.c stdio.h Xftell.o: ftell.c stdio.h Xfuncs.o: funcs.c funcs.h Xfuncs2.o: funcs2.c funcs.h Xfwrite.o: fwrite.c stdio.h Xgetbuf.o: getbuf.c stdio.h funcs.h Xgets.o: gets.c stdio.h Xgetw.o: getw.c stdio.h Xiob.o: iob.c stdio.h funcs.h Xpopen.o: popen.c stdio.h funcs.h Xprintf.o: printf.c stdio.h Xputpad.o: putpad.c stdio.h printf.h Xputs.o: puts.c stdio.h Xputw.o: putw.c stdio.h Xrewind.o: rewind.c stdio.h Xsaprintf.o: saprintf.c stdio.h Xscanf.o: scanf.c stdio.h Xscanfiles.o: scanfiles.c stdio.h Xsetbuf.o: setbuf.c stdio.h Xsetbuffer.o: setbuffer.c stdio.h Xseterrfn.o: seterrfn.c stdio.h Xsetfuncs.o: setfuncs.c stdio.h Xsetlinebuf.o: setlinebuf.c stdio.h Xsetvbuf.o: setvbuf.c stdio.h funcs.h Xsnprintf.o: snprintf.c stdio.h Xsprintf.o: sprintf.c stdio.h Xsscanf.o: sscanf.c stdio.h Xstrutil.o: strutil.c stdio.h Xstraopen.o: straopen.c stdio.h Xstrautil.o: strautil.c stdio.h funcs.h Xstrnopen.o: strnopen.c stdio.h Xstropen.o: stropen.c stdio.h Xungetc.o: ungetc.c stdio.h Xvfprintf.o: vfprintf.c stdio.h Xvfscanf.o: vfscanf.c stdio.h Xvprintf.o: vprintf.c stdio.h Xvsaprintf.o: vsaprintf.c stdio.h Xvscanf.o: vscanf.c stdio.h Xvsprintf.o: vsprintf.c stdio.h Xvsscanf.o: vsscanf.c stdio.h EOF chmod 664 Makefile shouldbe=2843 size=`wc -c < Makefile` if test $size -ne $shouldbe; then echo "shar: $0: error extracting Makefile ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file Makefile" 1>&2; fi if test $overwritecheck = no -o ! -f stdio.h; then case $verbose in yes) echo "extracting stdio.h";; esac sed 's/^X//' > stdio.h <<\EOF X#define BUFSIZ 512 X X#ifndef FILE X Xstruct _iobuf X { X#ifdef pdp11 /* really #ifdef oldunix */ X char *_ptr; X int _cnt; X#else X int _cnt; X char *_ptr; X#endif X char *_base; X int _bufsiz; X short _flag; X int _file; X char *_fptr; /* ANSI void * */ X char _tinybuf; /* used when _IONBF */ X char *_filename; X int (*_filbuf)(); X int (*_flsbuf)(); X int (*_readfunc)(); X int (*_writefunc)(); X long (*_seekfunc)(); X int (*_closefunc)(); X int (*_errfunc)(); X struct _iobuf *_next; X /* spare? */ X }; X X#define FILE struct _iobuf X X#endif X X#define EOF (-1) X X#define _IOFBF 0 X#define _IOREAD 01 X#define _IOWRT 02 X#define _IONBF 04 X#define _IOMYBUF 010 X#define _IOEOF 020 X#define _IOERR 040 X#define _IOSTRG 0100 X#define _IOLBF 0200 X#define _IORW 0400 X#define _IOFPTR 02000 /* I/O functions take _fptr instead of _file */ X#define _IOSTFN 04000 /* filename statically allocated (don't free) */ X X#ifndef NULL X#define NULL 0 X#endif X X#define SEEK_SET 0 X#define SEEK_CUR 1 X#define SEEK_END 2 X X#define _NFILE 3 /* not used; only for compatibility */ X Xextern FILE _iob[]; X X#define stdin (&_iob[0]) X#define stdout (&_iob[1]) X#define stderr (&_iob[2]) X X#define getc(fp) ((fp)->_cnt-- > 0 ? (*(fp)->_ptr++ & 0377) : \ X _filbuf(fp)) X X#ifndef PUTCLBUF X X#define putc(c, fp) ((fp)->_cnt-- > 0 ? (*(fp)->_ptr++ = (c)) : \ X _flsbuf(c, fp)) X X#else X X#define putc(c, fp) ((fp)->_cnt-- > 0 ? \ X ((*(fp)->_ptr = (c)) == '\n' && ((fp)->_flag & _IOLBF) ? \ X _flsbuf(*(fp)->_ptr, fp) : \ X *(fp)->_ptr++) \ X : _flsbuf(c, fp)) X X#endif X X#define getchar() getc(stdin) X#define putchar(c) putc(c, stdout) X X#define clearerr(fp) ((fp)->_flag &= ~(_IOEOF | _IOERR)) X#define feof(fp) ((fp)->_flag & _IOEOF) X#define ferror(fp) ((fp)->_flag & _IOERR) X X#define fileno(fp) ((fp)->_file) X#define _fileptr(fp) ((fp)->_fptr) X X#ifndef __STDC__ X Xextern FILE *fdopen(); Xextern char *fgets(); Xextern FILE *fopen(); Xextern FILE *freopen(); Xextern long int ftell(); Xextern char *gets(); X X#ifdef EXTENSIONS X Xextern char *saprintf(); Xextern FILE *stropen(); Xextern FILE *strnopen(); Xextern char *vsaprintf(); X X#endif X X#else X X#include <stdarg.h> /* for va_list */ X Xextern int fclose(FILE *); Xextern FILE *fdopen(int, char *); Xextern int fflush(FILE *); Xextern int fgetc(FILE *); Xextern char *fgets(char *, int, FILE *); Xextern FILE *fopen(char *, char *); Xextern int fprintf(FILE *, char *, ...); Xextern int fputc(char, FILE *); Xextern int fputs(char *, FILE *); Xextern int fread(char *, unsigned int, int, FILE *); Xextern FILE *freopen(char *, char *, FILE *); Xextern int fscanf(FILE *, char *, ...); Xextern int fseek(FILE *, long int, int); Xextern long int ftell(FILE *); Xextern int fwrite(char *, unsigned int, int, FILE *); Xextern char *gets(char *); X/* getw? */ Xextern int printf(char *, ...); Xextern int puts(char *); X/* putw? */ Xextern void rewind(FILE *); Xextern int scanf(char *, ...); Xextern int setbuf(FILE *, char *); Xextern int setbuffer(FILE *, char *, int); /* Berkeley */ Xextern int setlinebuf(FILE *); /* Berkeley */ Xextern int setvbuf(FILE *, char *, int, int); Xextern int sprintf(char *, char *, ...); Xextern int sscanf(char *, char *, ...); Xextern int ungetc(char, FILE *); Xextern int vfprintf(FILE *, char *, va_list); Xextern int vprintf(char *, va_list); Xextern int vsprintf(char *, char *, va_list); X X#ifdef EXTENSIONS X Xextern void fabort(FILE *); Xextern int fdclose(FILE *); Xextern int flushall(void); Xextern int putpad(FILE *, char *, int, int, int); Xextern char *saprintf(char *, ...); Xextern int scanfiles(int (*)()); Xextern int seterrfn(FILE *, int (*)()); Xextern int setfuncs(FILE *, int (*)(), int (*)(), long int (*)(), int (*)()); Xextern int snprintf(char *, int, char *, ...); Xextern FILE *stropen(char *, char *); Xextern FILE *strnopen(char *, int, char *); Xextern char *vsaprintf(char *, va_list); X X#endif X X#endif EOF chmod 644 stdio.h shouldbe=3820 size=`wc -c < stdio.h` if test $size -ne $shouldbe; then echo "shar: $0: error extracting stdio.h ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file stdio.h" 1>&2; fi if test $overwritecheck = no -o ! -f README; then case $verbose in yes) echo "extracting README";; esac sed 's/^X//' > README <<\EOF Xto do: X X getc (and maybe putc) macros probably need &0377 masking X (or make _ptr &c unsigned char *) X X write straopen (poor name?) (straopen is to saprintf as X stropen is to sprintf.) Also need char *straclose (which X returns pointer to completed string) or char *straptr (to X get at it along the way). X X check _IORW more thoroughly X X will fseek correctly undo ungetc when the in-buffer X adjustment for near seeks is used? can an ungetc'd X character ever accidentally get written back to the X file from an _IORW stream? X X line buffering probably isn't finished yet X (in particular, has implications for STDINFLUSH) X (I think there's gotta be some hair where _cnt is X always 0, too, especially #ifndef NOPUTCLBUF) X X is setvbuf finished? X X *printf return value (especially EOF on error) X (will it be acceptable for _doprnt to just call iserror() X when it's done, rather than after each character?) X (_doprnt should return -1 if ferror(), even if no X otherwise correct return value.) X X worry about _ptr == _base case in ungetc X (never happens if char has been read?) X does it have the scanf(const char *) problem? (yes, at the moment) X X do fread and fwrite have two cases or three? X they only need two, if in loop X X idea: allow user-installable malloc replacement X (prleak, makeroom, etc.) X X start writing a test suite X Xopen design questions: X X preallocated buffers (_sibuf, _sobuf) for stdin & stdout? X (remember that they'd have to be word-aligned for raw magtape, etc.) X X on-the-fly buffering decisions (especially for stdout) X based on isatty()? X (but remember to check readfunc/writefunc first) X X pre/post increment/decrement in getc/putc macros? X (could use opposite way from standard implementations to X assert independence) X X fflush on input streams? X (conditional -- #ifdef) X use fabort() X X how to mesh _flsbuf and fflush better? X (the call to _writefunc oughta appear X in one or the other, not both) X X flag for malloc'ed iob to avoid pointer compares in _freefile? X X how should the caller install error functions? X X fstat nonsense in _filbuf X X fopen2, that does things right? (more open-ended & X extensible, allocate buffer upon open rather than X first use, ...) X X worry more about struct iob compatibility? X (_file, _flags field sizes, _bufsize presence on X non-4.2 systems, etc.) X X write return value: r < 0 vs. r != n X X lseek return value checking? X X write ftell/fseek in terms of potentially irregular lseek??? X (conditionally compilable; only truly generic X implementation will probably involve seek/offset pair X encoding in ftell's return value) X ("Library writers, like members of Congress, tend not to X like following their own rules...") X X stderr: line buffered or unbuffered? X X should _freefile() free _base and _filename? X (would lessen redundancy between fclose and fdclose) X X worry about _bufsize field and/or fstat saying bufsize is 0? X X should the #define FILE struct _iobuf in stdio.h X be inside the #ifndef FILE? X X what should fflush do if _flsbuf has been redefined? X X prototypes for the function pointers in struct _iob? X (makes _fptr even more of a problem) X X Should fopen mode modifiers ('+', 'b', etc.) really be X accepted in any order? X X Note that FASTNBUF forces loading of fwrite.o which is X quite big, if FASTFRDWR is turned on. X Xdesign decisions: X X the obvious extensions: virtual I/O functions, X error handlers, saved filename X X _cleanup flushes rather than closing X X set*buf can be called after reading or writing (I think) EOF chmod 644 README shouldbe=3462 size=`wc -c < README` if test $size -ne $shouldbe; then echo "shar: $0: error extracting README ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file README" 1>&2; fi case $verbose in yes) echo "extracting Copyright";; esac sed 's/^X//' > Copyright <<\EOF XThe source and documentation contained here is XCopyright 1987, 1988, and 1989 by Steve Summit. XAll Rights Reserved. XNoncommercial redistribution is permitted as long Xas these notices are retained. XAny modifications should be marked as such. XAny commercial, for-profit use will require Xprior permission from the author. EOF chmod 664 Copyright shouldbe=319 size=`wc -c < Copyright` if test $size -ne $shouldbe; then echo "shar: $0: error extracting Copyright ($size != $shouldbe)" 1>&2 fi if test $overwritecheck = no -o ! -f files; then case $verbose in yes) echo "extracting files";; esac sed 's/^X//' > files <<\EOF Xpaper.ms XCOPYING XMakefile Xstdio.h XREADME XCopyright Xfiles Xaskf.3s Xfabort.3s Xfdclose.3s Xflushall.3s Xfseterrfunc.3s Xsaprintf.3s Xscanfiles.3s Xsnprintf.3s Xstraopen.3s Xstrnopen.3s Xstropen.3s Xvsaprintf.3s Xvscanf.3s Xaskf.c Xcleanup.c Xdoprnt.c Xdoscan.c Xerrfunc.c Xfabort.c Xfclose.c Xfdclose.c Xfdopen.c Xfflush.c Xfgetc.c Xfgets.c Xfilbuf.c Xflsbuf.c Xflushall.c Xfopen.c Xfprintf.c Xfputc.c Xfputs.c Xfread.c Xfreopen.c Xfscanf.c Xfseek.c Xftell.c Xfuncs.c Xfuncs.h Xfuncs2.c Xfwrite.c Xgetbuf.c Xgets.c Xgetw.c Xiob.c Xmemcpy.c Xpopen.c Xprintf.c Xprintf.h Xputpad.c Xputs.c Xputw.c Xrewind.c Xsaprintf.c Xscanf.c Xscanfiles.c Xsetbuf.c Xsetbuffer.c Xseterrfn.c Xsetfuncs.c Xsetlinebuf.c Xsetvbuf.c Xsnprintf.c Xsprintf.c Xsscanf.c Xstraopen.c Xstrautil.c Xstrnopen.c Xstropen.c Xstrutil.c Xungetc.c Xvfprintf.c Xvfscanf.c Xvprintf.c Xvsaprintf.c Xvscanf.c Xvsprintf.c Xvsscanf.c EOF chmod 664 files shouldbe=813 size=`wc -c < files` if test $size -ne $shouldbe; then echo "shar: $0: error extracting files ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file files" 1>&2; fi if test $overwritecheck = no -o ! -f askf.3s; then case $verbose in yes) echo "extracting askf.3s";; esac sed 's/^X//' > askf.3s <<\EOF X.TH ASKF 3S X.SH NAME Xaskf \- user input function with prompt X.SH SYNOPSIS X.nf X#include <stdio.h> X Xaskf(prompt, ..., fmt, ...) Xchar *prompt; Xchar *fmt; X.fi X.SH DESCRIPTION X.I Askf Xis a general-purpose user input function. XIt is intended to alleviate the difficulties encountered when X.I scanf Xis used for this purpose. X.I askf Xprints the X.I prompt Xstring on the terminal and awaits a response. XThe X.I prompt Xstring can contain X.IR printf -like Xformatting requests; any values to be interpolated (via %'s) appear X.I between Xthe X.I prompt Xand X.I fmt Xarguments. X.PP X.I askf Xcollects responses from the user as controlled by the X.I fmt Xargument. X.I fmt Xcan contain any of the input requests which are accepted by the Xscanf family, with extensions and restrictions as noted below. X.PP XIf the user's input is incorrect, X.I askf Xnormally prints the prompt again and waits for the user to try again. X.PP XThe X.I fmt Xstring should normally contain only input format specifiers and X(optional) separating white space. XAny literal characters appearing in the X.I fmt Xstring must be matched by the user, Xwhich would not normally be "user friendly." X X.SH BUGS X.I askf Xis a nonstandard extension; Xit should be used but warily by portable programs. X.SH "SEE ALSO" Xprintf(3s), scanf(3s) EOF chmod 644 askf.3s shouldbe=1267 size=`wc -c < askf.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting askf.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file askf.3s" 1>&2; fi if test $overwritecheck = no -o ! -f fabort.3s; then case $verbose in yes) echo "extracting fabort.3s";; esac sed 's/^X//' > fabort.3s <<\EOF X.TH FABORT 3S X.SH NAME Xfabort \- discard buffered characters without flushing them X.SH SYNOPSIS X.nf X#include <stdio.h> X Xfabort(fp) XFILE *fp; X.fi X.SH DESCRIPTION X.I Fabort Xdiscards characters which have been buffered by the stdio package Xbut whose I/O is not complete. XFor output streams, Xcharacters which have been written by the calling program X(with X.IR putc , X.IR printf , Xand the like) Xbut which have not yet been written to the underlying file Xdescriptor (or "handle") are discarded. XFor input streams, any characters which have been "read ahead" Xinto the buffer, but not yet retrieved by the calling program X(with getchar, scanf, etc.) are discarded. X.SH BUGS X.I fabort Xis a nonstandard extension; Xit should be used but warily by portable programs. XSome other stdio implementations perform the same effect as X.I fabort Xwhen X.I fflush Xis applied to an input stream. X.SH "SEE ALSO" Xfflush(3S), fclose(3S) EOF chmod 644 fabort.3s shouldbe=909 size=`wc -c < fabort.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting fabort.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file fabort.3s" 1>&2; fi if test $overwritecheck = no -o ! -f fdclose.3s; then case $verbose in yes) echo "extracting fdclose.3s";; esac sed 's/^X//' > fdclose.3s <<\EOF X.TH FDCLOSE 3S X.SH NAME Xfdclose \- close stream without closing low-level descriptor X.SH SYNOPSIS X.nf X#include <stdio.h> X Xfdclose(fp) XFILE *fp; X.fi X.SH DESCRIPTION X.I Fdclose Xcompletes I/O on, Xand deletes the data structures associated with, Xa stdio stream, Xwithout actually closing the underlying file descriptor (or other handle). XIts name reflects its complementary nature to X.I fdopen X(q.v.); Xthe sequence X.DS Xint fd = ...; XFILE *fp = fdopen(fd, ...); X... Xfdclose(fp); X.DE Xleaves the file descriptor fd afterwards available for further I/O. X.SH BUGS X.I fdclose Xis a nonstandard extension; Xit should be used but warily by portable programs. X.SH "SEE ALSO" Xfdopen(3s), fclose(3s) EOF chmod 644 fdclose.3s shouldbe=682 size=`wc -c < fdclose.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting fdclose.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file fdclose.3s" 1>&2; fi if test $overwritecheck = no -o ! -f flushall.3s; then case $verbose in yes) echo "extracting flushall.3s";; esac sed 's/^X//' > flushall.3s <<\EOF X.TH FLUSHALL 3S X.SH NAME Xflushall \- flush all open streams X.SH SYNOPSIS X.nf X#include <stdio.h> X Xflushall() X.fi X.SH DESCRIPTION X.I Flushall Xperforms the effect of X.I fflush Xfor all currently open streams. XNo streams are closed. X.I flushall Xis useful for checkpointing an application before some Xtime-consuming, risky, or terminal operation. X.SH BUGS X.I flushall Xis a nonstandard extension; Xit should be used but warily by portable programs. XThe ANSI C standard states that fflush((FILE *)NULL) will flush Xall open streams. X.SH "SEE ALSO" Xfflush(3s), scanfiles(3s) EOF chmod 644 flushall.3s shouldbe=564 size=`wc -c < flushall.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting flushall.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file flushall.3s" 1>&2; fi if test $overwritecheck = no -o ! -f fseterrfunc.3s; then case $verbose in yes) echo "extracting fseterrfunc.3s";; esac sed 's/^X//' > fseterrfunc.3s <<\EOF X.TH FSETERRFUNC 3S X.SH NAME Xfseterrfunc \- install default or per-stream error handler X.SH SYNOPSIS X.nf X#include <stdio.h> X Xfseterrfunc(fp, errfunc) XFILE *fp; Xint (*errfunc)(); X.fi X.SH DESCRIPTION X.I Fseterrfunc Xassociates the error-handling function pointed to by X.I func Xwith the stream X.IR fp . XIf X.I fp Xis NULL, the function is instead installed as the default handler Xfor all streams without explicitly-installed handlers. X.PP XWhen an I/O error occurs, the error-handling function is called as X.sp X.nf X.in +.6i X (*func)(filename, rw, fp) X char *filename; X int rw; X FILE *fp; X.in -.6i X.fi X.I fp Xis the stream pointer for the operation incurring the error. X.I filename Xis the name of the associated file, if known X(or NULL if not). X.I rw Xis a character denoting the kind of error. XThe error codes defined so far are: X.sp X.nf X 'r' read error X 'w' write error X 'c' close error X 's' (l)seek error X 'm' memory allocation error X.fi X.sp XOther error codes may be defined in the future. X.PP XThe operation of the default error handler is to print a message X(to stderr) including the file name, kind of error, and X.I perror Xtext. XIf X.I rw Xis 'w', the default handler calls exit(1). X.LP XThe default error handler can be replaced by calling X.I fseterrfunc Xwith an X.I fp Xof NULL. X.PP XWhen installing a new default error handler, the programmer Xshould beware of the possibility of infinite recursion. XFor example, the default handler, which prints to stderr, returns Ximmediately (without printing anything) if X.I fp Xis stderr and X.I rw Xis 'w'. X.SH BUGS X.I fseterrfunc Xis a nonstandard extension; Xit should be used but warily by portable programs. EOF chmod 644 fseterrfunc.3s shouldbe=1636 size=`wc -c < fseterrfunc.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting fseterrfunc.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file fseterrfunc.3s" 1>&2; fi if test $overwritecheck = no -o ! -f saprintf.3s; then case $verbose in yes) echo "extracting saprintf.3s";; esac sed 's/^X//' > saprintf.3s <<\EOF X.TH SAPRINTF 3S X.SH NAME Xsaprintf \- formatted print to dynamically-allocated string X.SH SYNOPSIS X.nf X#include <stdio.h> X Xchar *saprintf(fmt, ...) Xchar *fmt; X.fi X.SH DESCRIPTION X.I Saprintf Xperforms formatted printing, in the style of X.IR printf , Xon the X.I fmt Xstring, interpolating additional arguments as required. XThe output is written to dynamically-allocated memory X(typically obtained with X.I malloc Xand/or X.IR realloc ) Xand a pointer to that memory is returned. XThe returned pointer may be (and should be) deallocated with X.I free Xwhen no longer needed. X.PP XIt is the responsibility of the calling program to free the Xpointers returned by X.IR saprintf ; Xno garbage collection is implied. X.SH BUGS X.I saprintf Xis a nonstandard extension; Xit should be used but warily by portable programs. X.SH "SEE ALSO" Xprintf(3s), sprintf(3s), vsaprintf(3s) EOF chmod 644 saprintf.3s shouldbe=850 size=`wc -c < saprintf.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting saprintf.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file saprintf.3s" 1>&2; fi if test $overwritecheck = no -o ! -f scanfiles.3s; then case $verbose in yes) echo "extracting scanfiles.3s";; esac sed 's/^X//' > scanfiles.3s <<\EOF X.TH scanfiles 3S X.SH NAME Xscanfiles \- call function for each open stream X.SH SYNOPSIS X.nf X#include <stdio.h> X Xscanfiles(func) Xint (*func)(FILE *); X.fi X.SH DESCRIPTION X.I Scanfiles Xcalls X.I func Xfor each currently-open stream. XEach invocation X.I func Xis passed a single argument, the stream pointer in question. X.SH "RETURN VALUE" X.I Scanfiles Xreturns no useful value. X(The return values from the calls to X.I func Xare ignored.) X.SH BUGS X.I scanfiles Xis a nonstandard extension; Xit should be used but warily by portable programs. EOF chmod 644 scanfiles.3s shouldbe=529 size=`wc -c < scanfiles.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting scanfiles.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file scanfiles.3s" 1>&2; fi if test $overwritecheck = no -o ! -f snprintf.3s; then case $verbose in yes) echo "extracting snprintf.3s";; esac sed 's/^X//' > snprintf.3s <<\EOF X.TH SNPRINTF 3S X.SH NAME Xsnprintf \- sprintf with overflow detection X.SH SYNOPSIS X.nf X#include <stdio.h> X Xsnprintf(buf, len, fmt, ...) Xchar *buf; Xint len; Xchar *fmt; X.fi X.SH DESCRIPTION X.I snprintf Xis like X.I sprintf Xis that it formats a string into the destination buffer X.IR buf , Xcontrolled by the formatting argument X.I fmt Xand interpolating any additional arguments (indicated by %'s in Xthe format string) as required. XHowever, no more that X.I len Xcharacters, including the trailing \e0, will be written to X.IR buf . X(The trailing \e0 is always written, so at most \fIn\fP-1 "real" Xcharacters will be written to X.IR buf .) X.PP X.I snprintf Xallows the programmer to exclude the possibility of buffer Xoverflow, since in many cases the results of the formatting Xoperation could be arbitrarily large, and not predictable at Xcompile time. X.SH BUGS X.I snprintf Xis a common but nonstandard extension; Xit should be used but warily by portable programs. X.SH "SEE ALSO" Xsprintf(3s), saprintf(3s), strnopen(3s) EOF chmod 644 snprintf.3s shouldbe=1004 size=`wc -c < snprintf.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting snprintf.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file snprintf.3s" 1>&2; fi if test $overwritecheck = no -o ! -f straopen.3s; then case $verbose in yes) echo "extracting straopen.3s";; esac sed 's/^X//' > straopen.3s <<\EOF X.TH STRAOPEN 3S X.SH NAME Xstraopen \- open dynamically-allocating string stream X.SH SYNOPSIS X.nf X#include <stdio.h> X XFILE *straopen(); X Xchar *straptr(fp); XFILE *fp; X Xchar *straclose(fp); XFILE *fp; X.fi X.SH DESCRIPTION X.I straopen Xreturns a stream, open for writing, upon which arbitrary output Xoperations can be performed. XThe "output" destination is a Xdynamically-allocated buffer which grows as required to Xaccommodate as many characters as are written. X.PP XAs output operations are performed and the string is built up, Xthe work-in-progress may be inspected by calling X.IR straptr , Xwhich returns a pointer to the string which has been built so far. XThe string is terminated with the usual '\e0'. XThe pointer returned by X.I straptr Xshould not be saved for very long, since the next operation on Xthe stream may provoke a reallocation which could move the string Xin memory, invalidating the older pointer. X.PP XWhen all output operations have been performed and the string is Xcompletely built, X.I straclose Xmay be called. X.I Straclose Xresizes the allocated buffer to the actual size reached X(freeing any extra memory that had been preallocated) Xand returns a pointer to the final buffer. X(The string is, of course, terminated with a '\e0'.) X.PP XThe return value of X.I straclose Xis a pointer to dynamically-allocated memory. XIt may (and should) be deallocated with X.I free Xwhen it is no longer needed, or memory will be wasted. X(However, it would be a grave error to free the pointer returned by X.IR straptr .) X.PP XIt is an error to call X.I straptr Xor X.I straclose Xwith a stream pointer other than one obtained with X.IR straopen . XSuch an error may or may not be detected. X.PP XIt is permissible to close a \fIstraopen\fPed stream with X.IR fclose ; Xhowever, the sizedown may not occur and the final pointer must Xhave been acquired independently with X.IR straptr . X.SH BUGS X.I straopen Xis a nonstandard extension; Xit should be used but warily by portable programs. X.SH "SEE ALSO" Xstropen(3s), saprintf(3s) EOF chmod 644 straopen.3s shouldbe=2001 size=`wc -c < straopen.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting straopen.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file straopen.3s" 1>&2; fi if test $overwritecheck = no -o ! -f strnopen.3s; then case $verbose in yes) echo "extracting strnopen.3s";; esac sed 's/^X//' > strnopen.3s <<\EOF X.TH STRNOPEN 3S X.SH NAME Xstrnopen \- open length-specified string for stream-like I/O X.SH SYNOPSIS X.nf X#include <stdio.h> X XFILE *strnopen(string, n, mode) Xchar *string; Xint n; Xchar *mode; X.fi X.SH DESCRIPTION X.I Strnopen Xreturns a stdio stream pointer "opened" on the passed X.IR string , Xwhose length is X.IR n. XThe string is read from, written to, or appended to, depending on Xwhether the X.I mode Xargument is "r", "w", or "a". X.PP XAny stdio function that accepts a stream pointer may be used to Xperform I/O on a stream obtained with X.IR stropen. XThis allows the full flexibility of the stdio package to be used Xwhen formatting or unformatting in-memory strings, Xas well as allowing in-memory strings to be read/written by any Xother utility functions which happen to deal with stdio streams. X.PP XA stream opened for reading by X.I strnopen Xwill supply exactly X.I n Xcharacters before returning EOF. X(The scan is not terminated prematurely if a \e0 is encountered before X.I n Xcharacters have been used up. XThis behavior is somewhat incompatible with that of X.I strncat Xand X.IR strncpy .) X.PP XWhen writing, no more that X.I n Xcharacters may be written to the stream supplied. X(An attempt to write more characters will result in an error code Xbeing returned by the top-level write call, if the calling Xprogram happens to be checking.) XWhen appending (\fImode\fP "a"), X.I n Xis still interpreted as the buffer size (not to be exceeded), Xnot the length of the string to be appended to (in the absence of Xan explicit \e0). X.SH BUGS X.I strnopen Xis a nonstandard extension; Xit should be used but warily by portable programs. X.SH "SEE ALSO" Xstropen(3s), sprintf(3s) EOF chmod 644 strnopen.3s shouldbe=1651 size=`wc -c < strnopen.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting strnopen.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file strnopen.3s" 1>&2; fi if test $overwritecheck = no -o ! -f stropen.3s; then case $verbose in yes) echo "extracting stropen.3s";; esac sed 's/^X//' > stropen.3s <<\EOF X.TH STROPEN 3S X.SH NAME Xstropen \- open string for stream-like I/O X.SH SYNOPSIS X.nf X#include <stdio.h> X XFILE *stropen(string, mode) Xchar *string; Xchar *mode; X.fi X.SH DESCRIPTION X.I Stropen Xreturns a stdio stream pointer "opened" on the passed X.IR string . XThe string is read from, written to, or appended to, depending on Xwhether the X.I mode Xargument is "r", "w", or "a". X.PP XAny stdio function that accepts a stream pointer may be used to Xperform I/O on a stream obtained with X.IR stropen. XThis allows the full flexibility of the stdio package to be used Xwhen formatting or unformatting in-memory strings, Xas well as allowing in-memory strings to be read/written by any Xother utility functions which happen to deal with stdio streams. X.PP XWhen reading, the nul (\e0) terminating the string is signaled by XEOF. X.PP XWhen writing, there is no provision for an overflow check; the passed X.I string X(normally a buffer of some sort) must somehow be "big enough" to Xhold the received characters. XIf boundary checking is desired, use X.IR strnopen . X.PP X.IR Strnopen , Xin combination with other stdio I/O functions, provides a Xsuperset of the string I/O functionality provided by X.I sprintf Xand X.IR sscanf. X(\fISprintf\fP and X.I sscanf Xallow a single operation to be performed on a string; X.I stropen Xallows a multiplicity of arbitrary operations.) X.SH BUGS X.I stropen Xis a nonstandard extension; Xit should be used but warily by portable programs. X.SH "SEE ALSO" Xstrnopen(3s), sprintf(3s), sscanf(3s) EOF chmod 644 stropen.3s shouldbe=1493 size=`wc -c < stropen.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting stropen.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file stropen.3s" 1>&2; fi if test $overwritecheck = no -o ! -f vsaprintf.3s; then case $verbose in yes) echo "extracting vsaprintf.3s";; esac sed 's/^X//' > vsaprintf.3s <<\EOF X.TH VSAPRINTF 3S X.SH NAME Xvsaprintf \- "varargs" sprintf to dynamically-allocated string X.SH SYNOPSIS X.nf X#include <stdio.h> X#include <stdarg.h> X Xchar *vsaprintf(fmt, argp) Xchar *fmt; Xva_list argp; X.fi X.SH DESCRIPTION X.I vsaprintf Xis like X.I vsprintf Xis that it formats a string, Xcontrolled by the formatting argument X.I fmt Xand interpolating additional arguments Xwhich are obtained indirectly through the variable-length Xargument list pointer argp. X.I vsaprintf Xs unique in that, list saprintf, the destination for the Xformatted string is a dynamically-allocated buffer X(typically obtained with X.I malloc Xand/or X.IR realloc ) Xwhich is automatically sized to be just big enough for the actual Xstring created. X.PP XThe return value of X.I vsaprintf Xis a pointer to dynamically-allocated memory. XIt may (and should) be deallocated with X.I free Xwhen it is no longer needed, or memory will be wasted. X.PP XThe use of X.I vsaprintf Xis indicated when the size of the resultant string cannot be Xpredicted (the usual case for a v*printf routine, since the Xformat string and arguments are always passed in from elsewhere). XThe alternative, a fixed but "large" destination buffer used with X.IR vsprintf , Xsuffers because the buffer must typically either waste space by Xbeing fantastically large, or risk overflow in some rare but Ximpossible to predict or eliminate case. X.SH BUGS X.I vsaprintf Xis a nonstandard extension; Xit should be used but warily by portable programs. X.SH "SEE ALSO" Xsaprintf(3s), straopen(3s), vsprintf(3s) EOF chmod 644 vsaprintf.3s shouldbe=1514 size=`wc -c < vsaprintf.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting vsaprintf.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file vsaprintf.3s" 1>&2; fi if test $overwritecheck = no -o ! -f vscanf.3s; then case $verbose in yes) echo "extracting vscanf.3s";; esac sed 's/^X//' > vscanf.3s <<\EOF X.TH VSCANF 3S X.SH NAME Xvscanf, vfscanf, vsscanf \- "varargs" interface to scanf family X.SH SYNOPSIS X.nf X#include <stdio.h> X#include <stdarg.h> X Xvscanf(fmt, argp) Xchar *fmt; Xva_list argp; X Xvfscanf(fp, fmt, argp) XFILE *fp; Xchar *fmt; Xva_list argp; X Xvsscanf(string, fmt, argp) Xchar *string; Xchar *fmt; Xva_list argp; X.fi X.SH DESCRIPTION XThese functions are analogous to X.IR scanf , X.IR fscanf , Xand X.IR sscanf , Xexcept that they expect a single va_list pointer X(typically obtained with va_start) Xas an argument rather than an actual variable argument list. XThese routines can therefore be used as the underlying routines Xto implement new functions which "act like" scanf, on some other Xinput or with some other difference. XSuch a routine would use va_start to obtain a "pointer" to its Xown variable argument list, and then pass the pointer to one of Xthese routines to actually perform the input conversion(s). X.SH BUGS XThese routines are obvious but nonstandard extensions; Xthey should be used but warily by portable programs. X.SH "SEE ALSO" Xscanf(3s), stdarg(3) EOF chmod 644 vscanf.3s shouldbe=1059 size=`wc -c < vscanf.3s` if test $size -ne $shouldbe; then echo "shar: $0: error extracting vscanf.3s ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file vscanf.3s" 1>&2; fi if test $overwritecheck = no -o ! -f askf.c; then case $verbose in yes) echo "extracting askf.c";; esac sed 's/^X//' > askf.c <<\EOF X#include <stdio.h> X#include <stdarg.h> X Xaskf(prompt) Xchar *prompt; X{ Xva_list argp; Xchar *fmt; Xint r; X Xdo { X va_start(argp, prompt); X X /* X * Have to pass argp by reference so _doscan can pick up X * where _doprnt left off. X */ X X _do2prnt(1, prompt, &argp, stderr); X X fmt = va_arg(argp, char *); X X r = _do2scan(1, stdin, fmt, argp); X X va_end(argp); X } while(r < 0); X Xreturn r; X} EOF chmod 644 askf.c shouldbe=381 size=`wc -c < askf.c` if test $size -ne $shouldbe; then echo "shar: $0: error extracting askf.c ($size != $shouldbe)" 1>&2 fi else echo "shar: $0: will not overwrite existing file askf.c" 1>&2; fi exit