[alt.sources] Standard I/O reimplementation, part 1 of 3

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