568 lines
18 KiB
HTML
568 lines
18 KiB
HTML
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<HTML><HEAD><TITLE>Man page of FOPENCOOKIE</TITLE>
|
|
</HEAD><BODY>
|
|
<H1>FOPENCOOKIE</H1>
|
|
Section: Linux Programmer's Manual (3)<BR>Updated: 2019-03-06<BR><A HREF="#index">Index</A>
|
|
<A HREF="/cgi-bin/man/man2html">Return to Main Contents</A><HR>
|
|
|
|
<A NAME="lbAB"> </A>
|
|
<H2>NAME</H2>
|
|
|
|
fopencookie - opening a custom stream
|
|
<A NAME="lbAC"> </A>
|
|
<H2>SYNOPSIS</H2>
|
|
|
|
<PRE>
|
|
<B>#define _GNU_SOURCE</B> /* See <A HREF="/cgi-bin/man/man2html?7+feature_test_macros">feature_test_macros</A>(7) */
|
|
<B>#include <<A HREF="file:///usr/include/stdio.h">stdio.h</A>></B>
|
|
|
|
<B>FILE *fopencookie(void *</B><I>cookie</I><B>, const char *</B><I>mode</I><B>,</B>
|
|
<B> cookie_io_functions_t </B><I>io_funcs</I><B>);</B>
|
|
</PRE>
|
|
|
|
<A NAME="lbAD"> </A>
|
|
<H2>DESCRIPTION</H2>
|
|
|
|
The
|
|
<B>fopencookie</B>()
|
|
|
|
function allows the programmer to create a custom implementation
|
|
for a standard I/O stream.
|
|
This implementation can store the stream's data at a location of
|
|
its own choosing; for example,
|
|
<B>fopencookie</B>()
|
|
|
|
is used to implement
|
|
<B><A HREF="/cgi-bin/man/man2html?3+fmemopen">fmemopen</A></B>(3),
|
|
|
|
which provides a stream interface to data that is stored in a
|
|
buffer in memory.
|
|
<P>
|
|
|
|
In order to create a custom stream the programmer must:
|
|
<DL COMPACT>
|
|
<DT id="1">*<DD>
|
|
Implement four "hook" functions that are used internally by the
|
|
standard I/O library when performing I/O on the stream.
|
|
<DT id="2">*<DD>
|
|
Define a "cookie" data type,
|
|
a structure that provides bookkeeping information
|
|
(e.g., where to store data) used by the aforementioned hook functions.
|
|
The standard I/O package knows nothing about the contents of this cookie
|
|
(thus it is typed as
|
|
<I>void *</I>
|
|
|
|
when passed to
|
|
<B>fopencookie</B>()),
|
|
|
|
but automatically supplies the cookie
|
|
as the first argument when calling the hook functions.
|
|
<DT id="3">*<DD>
|
|
Call
|
|
<B>fopencookie</B>()
|
|
|
|
to open a new stream and associate the cookie and hook functions
|
|
with that stream.
|
|
</DL>
|
|
<P>
|
|
|
|
The
|
|
<B>fopencookie</B>()
|
|
|
|
function serves a purpose similar to
|
|
<B><A HREF="/cgi-bin/man/man2html?3+fopen">fopen</A></B>(3):
|
|
|
|
it opens a new stream and returns a pointer to a
|
|
<I>FILE</I>
|
|
|
|
object that is used to operate on that stream.
|
|
<P>
|
|
|
|
The
|
|
<I>cookie</I>
|
|
|
|
argument is a pointer to the caller's cookie structure
|
|
that is to be associated with the new stream.
|
|
This pointer is supplied as the first argument when the standard I/O
|
|
library invokes any of the hook functions described below.
|
|
<P>
|
|
|
|
The
|
|
<I>mode</I>
|
|
|
|
argument serves the same purpose as for
|
|
<B><A HREF="/cgi-bin/man/man2html?3+fopen">fopen</A></B>(3).
|
|
|
|
The following modes are supported:
|
|
<I>r</I>,
|
|
|
|
<I>w</I>,
|
|
|
|
<I>a</I>,
|
|
|
|
<I>r+</I>,
|
|
|
|
<I>w+</I>,
|
|
|
|
and
|
|
<I>a+</I>.
|
|
|
|
See
|
|
<B><A HREF="/cgi-bin/man/man2html?3+fopen">fopen</A></B>(3)
|
|
|
|
for details.
|
|
<P>
|
|
|
|
The
|
|
<I>io_funcs</I>
|
|
|
|
argument is a structure that contains four fields pointing to the
|
|
programmer-defined hook functions that are used to implement this stream.
|
|
The structure is defined as follows
|
|
<P>
|
|
|
|
|
|
|
|
typedef struct {
|
|
<BR> cookie_read_function_t *read;
|
|
<BR> cookie_write_function_t *write;
|
|
<BR> cookie_seek_function_t *seek;
|
|
<BR> cookie_close_function_t *close;
|
|
} cookie_io_functions_t;
|
|
|
|
|
|
<P>
|
|
|
|
The four fields are as follows:
|
|
<DL COMPACT>
|
|
<DT id="4"><I>cookie_read_function_t *read</I>
|
|
|
|
<DD>
|
|
This function implements read operations for the stream.
|
|
When called, it receives three arguments:
|
|
<DT id="5"><DD>
|
|
<BR> ssize_t read(void *cookie, char *buf, size_t size);
|
|
<DT id="6"><DD>
|
|
The
|
|
<I>buf</I>
|
|
|
|
and
|
|
<I>size</I>
|
|
|
|
arguments are, respectively,
|
|
a buffer into which input data can be placed and the size of that buffer.
|
|
As its function result, the
|
|
<I>read</I>
|
|
|
|
function should return the number of bytes copied into
|
|
<I>buf</I>,
|
|
|
|
0 on end of file, or -1 on error.
|
|
The
|
|
<I>read</I>
|
|
|
|
function should update the stream offset appropriately.
|
|
<DT id="7"><DD>
|
|
If
|
|
<I>*read</I>
|
|
|
|
is a null pointer,
|
|
then reads from the custom stream always return end of file.
|
|
<DT id="8"><I>cookie_write_function_t *write</I>
|
|
|
|
<DD>
|
|
This function implements write operations for the stream.
|
|
When called, it receives three arguments:
|
|
<DT id="9"><DD>
|
|
<BR> ssize_t write(void *cookie, const char *buf, size_t size);
|
|
<DT id="10"><DD>
|
|
The
|
|
<I>buf</I>
|
|
|
|
and
|
|
<I>size</I>
|
|
|
|
arguments are, respectively,
|
|
a buffer of data to be output to the stream and the size of that buffer.
|
|
As its function result, the
|
|
<I>write</I>
|
|
|
|
function should return the number of bytes copied from
|
|
<I>buf</I>,
|
|
|
|
or 0 on error.
|
|
(The function must not return a negative value.)
|
|
The
|
|
<I>write</I>
|
|
|
|
function should update the stream offset appropriately.
|
|
<DT id="11"><DD>
|
|
If
|
|
<I>*write</I>
|
|
|
|
is a null pointer,
|
|
then output to the stream is discarded.
|
|
<DT id="12"><I>cookie_seek_function_t *seek</I>
|
|
|
|
<DD>
|
|
This function implements seek operations on the stream.
|
|
When called, it receives three arguments:
|
|
<DT id="13"><DD>
|
|
<BR> int seek(void *cookie, off64_t *offset, int whence);
|
|
<DT id="14"><DD>
|
|
The
|
|
<I>*offset</I>
|
|
|
|
argument specifies the new file offset depending on which
|
|
of the following three values is supplied in
|
|
<I>whence</I>:
|
|
|
|
<DL COMPACT><DT id="15"><DD>
|
|
<DL COMPACT>
|
|
<DT id="16"><B>SEEK_SET</B>
|
|
|
|
<DD>
|
|
The stream offset should be set
|
|
<I>*offset</I>
|
|
|
|
bytes from the start of the stream.
|
|
<DT id="17"><B>SEEK_CUR</B>
|
|
|
|
<DD>
|
|
<I>*offset</I>
|
|
|
|
should be added to the current stream offset.
|
|
<DT id="18"><B>SEEK_END</B>
|
|
|
|
<DD>
|
|
The stream offset should be set to the size of the stream plus
|
|
<I>*offset</I>.
|
|
|
|
</DL>
|
|
</DL>
|
|
|
|
<DT id="19"><DD>
|
|
Before returning, the
|
|
<I>seek</I>
|
|
|
|
function should update
|
|
<I>*offset</I>
|
|
|
|
to indicate the new stream offset.
|
|
<DT id="20"><DD>
|
|
As its function result, the
|
|
<I>seek</I>
|
|
|
|
function should return 0 on success, and -1 on error.
|
|
<DT id="21"><DD>
|
|
If
|
|
<I>*seek</I>
|
|
|
|
is a null pointer,
|
|
then it is not possible to perform seek operations on the stream.
|
|
<DT id="22"><I>cookie_close_function_t *close</I>
|
|
|
|
<DD>
|
|
This function closes the stream.
|
|
The hook function can do things such as freeing buffers allocated
|
|
for the stream.
|
|
When called, it receives one argument:
|
|
<DT id="23"><DD>
|
|
<BR> int close(void *cookie);
|
|
<DT id="24"><DD>
|
|
The
|
|
<I>cookie</I>
|
|
|
|
argument is the cookie that the programmer supplied when calling
|
|
<B>fopencookie</B>().
|
|
|
|
<DT id="25"><DD>
|
|
As its function result, the
|
|
<I>close</I>
|
|
|
|
function should return 0 on success, and
|
|
<B>EOF</B>
|
|
|
|
on error.
|
|
<DT id="26"><DD>
|
|
If
|
|
<I>*close</I>
|
|
|
|
is NULL, then no special action is performed when the stream is closed.
|
|
</DL>
|
|
<A NAME="lbAE"> </A>
|
|
<H2>RETURN VALUE</H2>
|
|
|
|
On success
|
|
<B>fopencookie</B>()
|
|
|
|
returns a pointer to the new stream.
|
|
On error, NULL is returned.
|
|
|
|
|
|
<A NAME="lbAF"> </A>
|
|
<H2>ATTRIBUTES</H2>
|
|
|
|
For an explanation of the terms used in this section, see
|
|
<B><A HREF="/cgi-bin/man/man2html?7+attributes">attributes</A></B>(7).
|
|
|
|
<TABLE BORDER>
|
|
<TR VALIGN=top><TD><B>Interface</B></TD><TD><B>Attribute</B></TD><TD><B>Value</B><BR></TD></TR>
|
|
<TR VALIGN=top><TD>
|
|
<B>fopencookie</B>()
|
|
|
|
</TD><TD>Thread safety</TD><TD>MT-Safe<BR></TD></TR>
|
|
</TABLE>
|
|
|
|
<A NAME="lbAG"> </A>
|
|
<H2>CONFORMING TO</H2>
|
|
|
|
This function is a nonstandard GNU extension.
|
|
<A NAME="lbAH"> </A>
|
|
<H2>EXAMPLE</H2>
|
|
|
|
The program below implements a custom stream whose functionality
|
|
is similar (but not identical) to that available via
|
|
<B><A HREF="/cgi-bin/man/man2html?3+fmemopen">fmemopen</A></B>(3).
|
|
|
|
It implements a stream whose data is stored in a memory buffer.
|
|
The program writes its command-line arguments to the stream,
|
|
and then seeks through the stream reading two out of every
|
|
five characters and writing them to standard output.
|
|
The following shell session demonstrates the use of the program:
|
|
<P>
|
|
|
|
|
|
|
|
$<B> ./a.out 'hello world'</B>
|
|
|
|
/he/
|
|
/ w/
|
|
/d/
|
|
Reached end of file
|
|
|
|
|
|
<P>
|
|
|
|
Note that a more general version of the program below
|
|
could be improved to more robustly handle various error situations
|
|
(e.g., opening a stream with a cookie that already has an open stream;
|
|
closing a stream that has already been closed).
|
|
<A NAME="lbAI"> </A>
|
|
<H3>Program source</H3>
|
|
|
|
|
|
|
|
#define _GNU_SOURCE
|
|
#include <<A HREF="file:///usr/include/sys/types.h">sys/types.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdio.h">stdio.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdlib.h">stdlib.h</A>>
|
|
#include <<A HREF="file:///usr/include/unistd.h">unistd.h</A>>
|
|
#include <<A HREF="file:///usr/include/string.h">string.h</A>>
|
|
<P>
|
|
#define INIT_BUF_SIZE 4
|
|
<P>
|
|
struct memfile_cookie {
|
|
<BR> char *buf; /* Dynamically sized buffer for data */
|
|
<BR> size_t allocated; /* Size of buf */
|
|
<BR> size_t endpos; /* Number of characters in buf */
|
|
<BR> off_t offset; /* Current file offset in buf */
|
|
};
|
|
<P>
|
|
ssize_t
|
|
memfile_write(void *c, const char *buf, size_t size)
|
|
{
|
|
<BR> char *new_buff;
|
|
<BR> struct memfile_cookie *cookie = c;
|
|
<P>
|
|
<BR> /* Buffer too small? Keep doubling size until big enough */
|
|
<P>
|
|
<BR> while (size + cookie->offset > cookie->allocated) {
|
|
<BR> new_buff = realloc(cookie->buf, cookie->allocated * 2);
|
|
<BR> if (new_buff == NULL) {
|
|
<BR> return -1;
|
|
<BR> } else {
|
|
<BR> cookie->allocated *= 2;
|
|
<BR> cookie->buf = new_buff;
|
|
<BR> }
|
|
<BR> }
|
|
<P>
|
|
<BR> memcpy(cookie->buf + cookie->offset, buf, size);
|
|
<P>
|
|
<BR> cookie->offset += size;
|
|
<BR> if (cookie->offset > cookie->endpos)
|
|
<BR> cookie->endpos = cookie->offset;
|
|
<P>
|
|
<BR> return size;
|
|
}
|
|
<P>
|
|
ssize_t
|
|
memfile_read(void *c, char *buf, size_t size)
|
|
{
|
|
<BR> ssize_t xbytes;
|
|
<BR> struct memfile_cookie *cookie = c;
|
|
<P>
|
|
<BR> /* Fetch minimum of bytes requested and bytes available */
|
|
<P>
|
|
<BR> xbytes = size;
|
|
<BR> if (cookie->offset + size > cookie->endpos)
|
|
<BR> xbytes = cookie->endpos - cookie->offset;
|
|
<BR> if (xbytes < 0) /* offset may be past endpos */
|
|
<BR> xbytes = 0;
|
|
<P>
|
|
<BR> memcpy(buf, cookie->buf + cookie->offset, xbytes);
|
|
<P>
|
|
<BR> cookie->offset += xbytes;
|
|
<BR> return xbytes;
|
|
}
|
|
<P>
|
|
int
|
|
memfile_seek(void *c, off64_t *offset, int whence)
|
|
{
|
|
<BR> off64_t new_offset;
|
|
<BR> struct memfile_cookie *cookie = c;
|
|
<P>
|
|
<BR> if (whence == SEEK_SET)
|
|
<BR> new_offset = *offset;
|
|
<BR> else if (whence == SEEK_END)
|
|
<BR> new_offset = cookie->endpos + *offset;
|
|
<BR> else if (whence == SEEK_CUR)
|
|
<BR> new_offset = cookie->offset + *offset;
|
|
<BR> else
|
|
<BR> return -1;
|
|
<P>
|
|
<BR> if (new_offset < 0)
|
|
<BR> return -1;
|
|
<P>
|
|
<BR> cookie->offset = new_offset;
|
|
<BR> *offset = new_offset;
|
|
<BR> return 0;
|
|
}
|
|
<P>
|
|
int
|
|
memfile_close(void *c)
|
|
{
|
|
<BR> struct memfile_cookie *cookie = c;
|
|
<P>
|
|
<BR> free(cookie->buf);
|
|
<BR> cookie->allocated = 0;
|
|
<BR> cookie->buf = NULL;
|
|
<P>
|
|
<BR> return 0;
|
|
}
|
|
<P>
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
<BR> cookie_io_functions_t memfile_func = {
|
|
<BR> .read = memfile_read,
|
|
<BR> .write = memfile_write,
|
|
<BR> .seek = memfile_seek,
|
|
<BR> .close = memfile_close
|
|
<BR> };
|
|
<BR> FILE *stream;
|
|
<BR> struct memfile_cookie mycookie;
|
|
<BR> ssize_t nread;
|
|
<BR> long p;
|
|
<BR> int j;
|
|
<BR> char buf[1000];
|
|
<P>
|
|
<BR> /* Set up the cookie before calling fopencookie() */
|
|
<P>
|
|
<BR> mycookie.buf = malloc(INIT_BUF_SIZE);
|
|
<BR> if (mycookie.buf == NULL) {
|
|
<BR> perror("malloc");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> mycookie.allocated = INIT_BUF_SIZE;
|
|
<BR> mycookie.offset = 0;
|
|
<BR> mycookie.endpos = 0;
|
|
<P>
|
|
<BR> stream = fopencookie(&mycookie,"w+", memfile_func);
|
|
<BR> if (stream == NULL) {
|
|
<BR> perror("fopencookie");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Write command-line arguments to our file */
|
|
<P>
|
|
<BR> for (j = 1; j < argc; j++)
|
|
<BR> if (fputs(argv[j], stream) == EOF) {
|
|
<BR> perror("fputs");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Read two bytes out of every five, until EOF */
|
|
<P>
|
|
<BR> for (p = 0; ; p += 5) {
|
|
<BR> if (fseek(stream, p, SEEK_SET) == -1) {
|
|
<BR> perror("fseek");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<BR> nread = fread(buf, 1, 2, stream);
|
|
<BR> if (nread == -1) {
|
|
<BR> perror("fread");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<BR> if (nread == 0) {
|
|
<BR> printf("Reached end of file\n");
|
|
<BR> break;
|
|
<BR> }
|
|
<P>
|
|
<BR> printf("/%.*s/\n", nread, buf);
|
|
<BR> }
|
|
<P>
|
|
<BR> exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
<A NAME="lbAJ"> </A>
|
|
<H2>SEE ALSO</H2>
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?3+fclose">fclose</A></B>(3),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?3+fmemopen">fmemopen</A></B>(3),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?3+fopen">fopen</A></B>(3),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?3+fseek">fseek</A></B>(3)
|
|
|
|
<A NAME="lbAK"> </A>
|
|
<H2>COLOPHON</H2>
|
|
|
|
This page is part of release 5.05 of the Linux
|
|
<I>man-pages</I>
|
|
|
|
project.
|
|
A description of the project,
|
|
information about reporting bugs,
|
|
and the latest version of this page,
|
|
can be found at
|
|
<A HREF="https://www.kernel.org/doc/man-pages/.">https://www.kernel.org/doc/man-pages/.</A>
|
|
<P>
|
|
|
|
<HR>
|
|
<A NAME="index"> </A><H2>Index</H2>
|
|
<DL>
|
|
<DT id="27"><A HREF="#lbAB">NAME</A><DD>
|
|
<DT id="28"><A HREF="#lbAC">SYNOPSIS</A><DD>
|
|
<DT id="29"><A HREF="#lbAD">DESCRIPTION</A><DD>
|
|
<DT id="30"><A HREF="#lbAE">RETURN VALUE</A><DD>
|
|
<DT id="31"><A HREF="#lbAF">ATTRIBUTES</A><DD>
|
|
<DT id="32"><A HREF="#lbAG">CONFORMING TO</A><DD>
|
|
<DT id="33"><A HREF="#lbAH">EXAMPLE</A><DD>
|
|
<DL>
|
|
<DT id="34"><A HREF="#lbAI">Program source</A><DD>
|
|
</DL>
|
|
<DT id="35"><A HREF="#lbAJ">SEE ALSO</A><DD>
|
|
<DT id="36"><A HREF="#lbAK">COLOPHON</A><DD>
|
|
</DL>
|
|
<HR>
|
|
This document was created by
|
|
<A HREF="/cgi-bin/man/man2html">man2html</A>,
|
|
using the manual pages.<BR>
|
|
Time: 00:05:43 GMT, March 31, 2021
|
|
</BODY>
|
|
</HTML>
|