funopen(3bsd)

πŸ“¦
version 0.12.2 Β· 3 versions
, in alpine 3.22, alpine 3.23, alpine 3.24, arch rolling, debian trixie, epel 10, epel 9, fedora 43, fedora 44, nixos 26.05, ubuntu noble, ubuntu questing, ubuntu resolute, ubuntu stonking

πŸ’– funopen(3bsd) β€” bestie edition πŸ’–

okay so this one is a libbsd situation, meaning it's a utility function from the BSD world that you get to borrow, and the manpage name is funopen(3bsd). yes it's a section 3 page, yes it's LOCAL, we move πŸ’…


✨ NAME ✨

funopen, fropen, fwopen β€” open a stream πŸŽ€


πŸ“š LIBRARY πŸ“š

Utility functions from BSD systems, i.e. libbsd, link it with -lbsd.


🌸 SYNOPSIS 🌸

#include <stdio.h>
(See libbsd(7) for include usage.)

FILE *
funopen(const void *cookie, int (*readfn)(void *, char *, int),
    int (*writefn)(void *, const char *, int),
    off_t (*seekfn)(void *, off_t, int), int (*closefn)(void *));

FILE *
fropen(void *cookie, int (*readfn)(void *, char *, int));

FILE *
fwopen(void *cookie, int (*writefn)(void *, const char *, int));

πŸ’« DESCRIPTION πŸ’«

so funopen() basically glues a stream to up to four "I/O functions" and honestly? iconic. πŸ¦‹

you must specify either readfn or writefn. the other slots can be handed an appropriately-typed NULL pointer, no shame in that. these I/O functions are the ones that'll do the reading, writing, seeking and closing for your brand new stream.

ngl, leaving a function out is a whole statement: if you skip one, any attempt to do that operation on the resulting stream will fail. πŸ’€ one exception though β€” if you leave out the close function, closing the stream will just flush any buffered output and then succeed. slay.

the calling conventions of readfn, writefn, seekfn and closefn have to match those of read(2), write(2), lseek(2) and close(2) respectively, with literally one single exception: instead of the traditional file descriptor argument, they get passed the cookie argument you gave to funopen(). that's it. that's the twist. πŸ“

read and write I/O functions are allowed to change the underlying buffer on fully buffered or line buffered streams by calling setvbuf(3). they're also not required to completely fill or empty the buffer, we're chill like that. but β€” and this is the part where you pay attention bestie πŸ™ˆ β€” they are not allowed to change streams from unbuffered to buffered, and they are not allowed to change the state of the line buffering flag. they must also be prepared to have read or write calls occur on buffers other than the one most recently specified. keep up, it's giving multitasking ✨

all user I/O functions can report an error by returning -1. and additionally, all of the functions should set the external variable errno appropriately if an error occurs. do it, set it, be responsible. 😌

An error on closefn() does not keep the stream open. like, it's done. closed. bye. πŸ‘‹

and as a little convenience, the include file <stdio.h> defines the macros fropen() and fwopen() as calls to funopen() with only a read or write function specified. cute, right? πŸŽ€


⭐ RETURN VALUES ⭐

upon successful completion, funopen() returns a FILE pointer. main character energy. otherwise NULL is returned and the global variable errno is set to indicate the error. sad but informative. 😭


πŸ”₯ ERRORS πŸ”₯

  • [EINVAL] β€” the funopen() function was called without either a read or write function. you literally have to give it one, bestie, that's the whole deal. the funopen() function may also fail and set errno for any of the errors specified for the routine malloc(3).

πŸ‘‘ SEE ALSO πŸ‘‘

fcntl(2), open(2), fclose(3), fopen(3), fseek(3), setbuf(3)


🌈 HISTORY 🌈

the funopen() functions first appeared in 4.4BSD. vintage. πŸ’œ


πŸ’€ BUGS πŸ’€

the funopen() function may not be portable to systems other than BSD, glibc- and musl-based ones (as the libbsd implementation is only provided when the system has fopencookie() available). so like, vibe check your platform first, fr fr.

on FreeBSD, OpenBSD and DragonFly the funopen() interface erroneously assumes that fpos_t is an integral type, and uses it in the seekfn hook. but because code using a seekfn hook will fail to build on systems where fpos_t is a struct, and it will need to be slightly fixed anyway, the implementation provided by libbsd (in the same way as NetBSD) uses the correct off_t types. so that's the tea 🍡


and that's the whole page, bestie 🫢 this version was cooked up on March 19, 2004 and shipped as part of the Debian packaging of it. go open some streams. periodt. πŸ’…βœ¨

πŸ“¦ where this page comes from