Xref: utzoo comp.unix.questions:7112 comp.unix.wizards:8620 Path: utzoo!attcan!uunet!husc6!purdue!umd5!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.unix.questions,comp.unix.wizards Subject: functional stdio Message-ID: <11582@mimsy.UUCP> Date: 19 May 88 19:03:10 GMT References: <136@insyte.uucp> <11331@mimsy.UUCP> <13597@comp.vuw.ac.nz> <13621@comp.vuw.ac.nz> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 113 (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, 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 : /* 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