### 4.18 `fopencookie`—open a stream with custom callbacks

Synopsis

         #include <stdio.h>
         FILE *fopencookie(const void *cookie, const char *mode,
             cookie_io_functions_t functions);

Description
`fopencookie` creates a `FILE` stream where I/O is performed using custom callbacks. The callbacks are registered via the structure:

typedef ssize_t (*cookie_read_function_t)(void *_cookie, char *_buf, size_t _n); typedef ssize_t (*cookie_write_function_t)(void *_cookie, const char *_buf, size_t _n); typedef int (*cookie_seek_function_t)(void *_cookie, off_t *_off, int _whence); typedef int (*cookie_close_function_t)(void *_cookie);

         	typedef struct
         	{
         		cookie_read_function_t	*read;
         		cookie_write_function_t *write;
         		cookie_seek_function_t	*seek;
         		cookie_close_function_t *close;
         	} cookie_io_functions_t;

The stream is opened with mode treated as in `fopen`. The callbacks functions.read and functions.write may only be NULL when mode does not require them.

functions.read should return -1 on failure, or else the number of bytes read (0 on EOF). It is similar to `read`, except that cookie will be passed as the first argument.

functions.write should return -1 on failure, or else the number of bytes written. It is similar to `write`, except that cookie will be passed as the first argument.

functions.seek should return -1 on failure, and 0 on success, with _off set to the current file position. It is a cross between `lseek` and `fseek`, with the _whence argument interpreted in the same manner. A NULL functions.seek makes the stream behave similarly to a pipe in relation to stdio functions that require positioning.

functions.close should return -1 on failure, or 0 on success. It is similar to `close`, except that cookie will be passed as the first argument. A NULL functions.close merely flushes all data then lets `fclose` succeed. A failed close will still invalidate the stream.

Read and write I/O functions are allowed to change the underlying buffer on fully buffered or line buffered streams by calling `setvbuf`. They are also not required to completely fill or empty the buffer. They are not, however, allowed to change streams from unbuffered to buffered or 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.

Returns
The return value is an open FILE pointer on success. On error, `NULL` is returned, and `errno` will be set to EINVAL if a function pointer is missing or mode is invalid, ENOMEM if the stream cannot be created, or EMFILE if too many streams are already open.

Portability
This function is a newlib extension, copying the prototype from Linux. It is not portable. See also the `funopen` interface from BSD.

Supporting OS subroutines required: `sbrk`.