functional stdio

Chris Torek chris at mimsy.UUCP
Fri May 20 05:03:10 AEST 1988


(The subject is something of a pun.  Doug Gwyn answered the varargs-related
questions, and this is now focussed on stdio applied to functions.)

>In article <11439 at mimsy.UUCP> I mentioned my funopen():
>>	FILE *funopen(void *cookie,
		<relatively complex types, only one shown:>
		int (*readfn)(void *cookie, char *buf, int nbytes),
		writefn, seekfn, closefn)

In article <13621 at comp.vuw.ac.nz> andrew at comp.vuw.ac.nz (Andrew Vignaux)
writes:
>How {,un}standard is it?  How can I get it?

Well, let me see.  It runs on gyre, and mimsy, and brillig, and tove;
that makes four machines, out of what, perhaps several tens of thousands?
As you can see, it is immensely popular :-) .  Oh yes, and rhodes: must
not forget rhodes.cs.umd.edu.  Make that five machines.

As for obtaining it: that is somewhat difficult.  funopen() is
based upon the existing 4.3BSD stdio.  It is not much code in and
of itself, and I might be able to make up context diffs, if not
for some other work I did as well.  I am afraid there is rather a
lot of difference now.  With any luck some version of this will appear
in 4.4BSD; in the meantime, the intrepid but impatient stdio hacker
can add funopen() and its variants with just a little work.  The
key is to add the following five members to `struct _iobuf':

	char	(*_cookie)();	/* for lack of void* */
	int	(*_read)();
	int	(*_write)();
	long	(*_seek)();
	int	(*_close)();

You will then need to put the following function and its obvious
analogues into one or several files:

	int
	_stdioread(cookie, buf, n)
		char *cookie, *buf;
		int n;
	{

		return (read(fileno((FILE *)cookie), buf, n));
	}

and change the various places within /usr/src/lib/libc/stdio/*.c
that call `read', `write', `seek', and `close' from

	n = read(iop->_file, iop->_base, iop->_bufsize);

to

	n = (*iop->_read)(iop->_cookie, iop->_base, iop->_bufsize);

You will also have add to fopen.c and fdopen.c:

	iop->_cookie = (char *)iop;
	if (rwmode == readonly || rwmode == readwrite)
		iop->_read = _stdioread;
	else
		iop->_read = NULL;
	if (rwmode == writeonly || rwmode == readwrite)
		iop->_write = _stdiowrite;
	else
		iop->_write = NULL;
	iop->_seek = _stdioseek;
	iop->_close = _stdioclose;

and of course these functions must be declared.  Writing funopen.c
becomes trivial; all it need do is ensure that at least a read or
a write function is given, and calculate the proper flags, and so
forth.  fseek.c must also ensure that a seek function exists
(iop->_seek!=NULL), and return an error if not.

The last task is to set up the descriptors for stdin, stdout, and
stderr properly; to aid this I included the following in the new
<stdio.h>:

/* help stdio source generate initial values for stdin, stdout, & stderr */
#ifdef _CONSTRUCT_IOB
#define	STD_IOB(flag, file, cookie, r, w, s, c) \
	{ 0, NULL, NULL, 0, flag, file, cookie, r, w, s, c }
	/*cnt ptr base size flag fileno */
#endif

It might be nice if you also fixed the various sins in the existing
functions (for instance, try fprintf or fwrite on stdin!).  But that
is the larger task.

>I can't quite pick up the semantics of funopen() from the declaration.  My
>guess is that the f{whatever}open function performs the appropriate open,
>packages whatever info the virtual functions will need into a cookie record,
>and then returns the result of funopen()--or am I completely wrong again :-(.

This is correct: the cookie is implicit for fopen and fdopen (whatever
stdio needs for its internal functions---in this case iop itself), and
is explicit in the case of funopen (where the cookie is just passed on
to the io functions).

>Where/how do you describe the `open' call ... ?

That is unnecessary: it is implicit from the fact that the stream is
open in the first place.  The open is given by the creation of the
stream (in principle, immediately before funopen()).

>Is there a funreopen() (for those cases where you want to
>change functions in mid-stream :-)?

No: if you intend to apply several functions, you must define a
wrapper function that knows when to switch.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.unix.wizards mailing list