[comp.unix.questions] functional stdio

chris@mimsy.UUCP (Chris Torek) (05/20/88)

(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@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@comp.vuw.ac.nz> andrew@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@mimsy.umd.edu	Path:	uunet!mimsy!chris

chris@mimsy.UUCP (Chris Torek) (05/20/88)

In article <11582@mimsy.UUCP> I wrote:
>	char	(*_cookie)();	/* for lack of void* */

Oops, that should be

	char	*cookie;	/* for lack of void* */
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

sullivan@vsi.UUCP (05/20/88)

Does anybody else find it ironic that IBM doesn't want to be tied down
to a single vendor's standard, and to avoid that will make its
own clone of that standard?  Why is IBM expecting AT&T to act in a way
that IBM won't act regarding PS/2?

-- 
Michael Sullivan		{uunet|attmail}!vsi!sullivan
				sullivan@vsi.com
HE V MTL			Anybody out there remember Max Webster?

scs@athena.mit.edu (Steve Summit) (06/02/88)

In article <11582@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>As for obtaining it: that is somewhat difficult.  funopen() is
>based upon the existing 4.3BSD stdio...
>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.

I've been meaning to respond to this stdio discussion for a while:
I started writing a stdio replacement based on exactly this idea.
I'd assumed I'd post it when I was finished with it, but I
haven't worked on it in a while.  I do know that it runs well
enough for me to have linked RCS against it to get RCS to work on
my v7 pdp11, which didn't have fopen("w+").  I suppose it wouldn't
take much to convince me to cast it to the four winds "as is"...

                                            Steve Summit
                                            scs@adam.pika.mit.edu