Bad idea. funopen() needs to be a wrapper around something with the
new functionality.

That's possible only if the wrapper is part of stdio, because fpos_t is
too opaque.

?? Of course. funopen() is *part* of BSD's stdio.h.
I use software probes to detect if my target platform supports funopen.
I don't use probes to detect if funopen() is a #define wrapper.

And, as long as you are doing that, it makes *MUCH* more sense to go
with an interface that takes a ops structure:

Like the Linux one. Hmm, @gnu.org...coincidence? :-)

You could also use bruce dot korb at gmail.
I try not to be a bigot. :) In fact, I really use my own interface
that layers on top of either funopen or fopencookie, but not
either of the POSIX interfaces. They don't cut it.
Anyway, truthfully, my teething was on SVR1 and using
file ops structures makes sense in this context. Linux, I think,
goes a little over the top in using them.

Please, no. I've written glue to run code designed for funopen() using
fopencookie; while I haven't written it, I've sketched out how to do
the converse. Implementing funopen with fopencookie is annoying (it

costs an extra malloc on stream open, free on close, and one more
function call for each method operation on the stream); the converse is
trivial. Which way is easier to write glue for is a fairly clear
indication which interface is preferable.

The glue is important because I've released software that depends upon
funopen() that likely won't disappear for years into the future.
So it will be some years after your new interface comes along that
my stuff will be able to cope. I still have clients using Guile 1.6,
lo these many years after Guile 1.8 and now 2.0 have been released.

What do you think?

If you're going to break something, then go whole hog and fix it so
you won't have to break the API ever again. :)

How does an ops struct do that? You still have an API flag day

API flag *YEARS*. That's my point. It isn't a day. It is years.
A struct does it by using an initializer that stamps it with the
initializer version. I was sketching an interface, not fleshing
it out. :) Consequently, the handling code can then look at the
version and decide to go ahead or not: