1FOPENCOOKIE(3)             Linux Programmer's Manual            FOPENCOOKIE(3)
2
3
4

NAME

6       fopencookie - opening a custom stream
7

SYNOPSIS

9       #define _GNU_SOURCE         /* See feature_test_macros(7) */
10       #include <stdio.h>
11
12       FILE *fopencookie(void *cookie, const char *mode,
13                         cookie_io_functions_t io_funcs);
14

DESCRIPTION

16       The  fopencookie()  function  allows  the programmer to create a custom
17       implementation for a standard  I/O  stream.   This  implementation  can
18       store the stream's data at a location of its own choosing; for example,
19       fopencookie() is used to implement fmemopen(3), which provides a stream
20       interface to data that is stored in a buffer in memory.
21
22       In order to create a custom stream the programmer must:
23
24       *  Implement  four  "hook"  functions  that  are used internally by the
25          standard I/O library when performing I/O on the stream.
26
27       *  Define a "cookie" data type, a structure that  provides  bookkeeping
28          information  (e.g.,  where to store data) used by the aforementioned
29          hook functions.  The standard I/O package knows  nothing  about  the
30          contents  of  this cookie (thus it is typed as void * when passed to
31          fopencookie()), but automatically supplies the cookie as  the  first
32          argument when calling the hook functions.
33
34       *  Call fopencookie() to open a new stream and associate the cookie and
35          hook functions with that stream.
36
37       The fopencookie() function serves a purpose  similar  to  fopen(3):  it
38       opens  a new stream and returns a pointer to a FILE object that is used
39       to operate on that stream.
40
41       The cookie argument is a pointer to the caller's cookie structure  that
42       is  to  be associated with the new stream.  This pointer is supplied as
43       the first argument when the standard I/O library  invokes  any  of  the
44       hook functions described below.
45
46       The mode argument serves the same purpose as for fopen(3).  The follow‐
47       ing modes are supported: r, w, a, r+, w+, and  a+.   See  fopen(3)  for
48       details.
49
50       The io_funcs argument is a structure that contains four fields pointing
51       to the programmer-defined hook functions that  are  used  to  implement
52       this stream.  The structure is defined as follows
53
54           typedef struct {
55               cookie_read_function_t  *read;
56               cookie_write_function_t *write;
57               cookie_seek_function_t  *seek;
58               cookie_close_function_t *close;
59           } cookie_io_functions_t;
60
61       The four fields are as follows:
62
63       cookie_read_function_t *read
64              This  function  implements read operations for the stream.  When
65              called, it receives three arguments:
66
67                  ssize_t read(void *cookie, char *buf, size_t size);
68
69              The buf and size arguments  are,  respectively,  a  buffer  into
70              which  input data can be placed and the size of that buffer.  As
71              its function result, the read function should return the  number
72              of bytes copied into buf, 0 on end of file, or -1 on error.  The
73              read function should update the stream offset appropriately.
74
75              If *read is a null pointer, then reads from  the  custom  stream
76              always return end of file.
77
78       cookie_write_function_t *write
79              This  function implements write operations for the stream.  When
80              called, it receives three arguments:
81
82                  ssize_t write(void *cookie, const char *buf, size_t size);
83
84              The buf and size arguments are, respectively, a buffer  of  data
85              to  be output to the stream and the size of that buffer.  As its
86              function result, the write function should return the number  of
87              bytes  copied  from  buf, or 0 on error.  (The function must not
88              return a negative value.)  The write function should update  the
89              stream offset appropriately.
90
91              If  *write  is a null pointer, then output to the stream is dis‐
92              carded.
93
94       cookie_seek_function_t *seek
95              This function implements seek operations on  the  stream.   When
96              called, it receives three arguments:
97
98                  int seek(void *cookie, off64_t *offset, int whence);
99
100              The  *offset argument specifies the new file offset depending on
101              which of the following three values is supplied in whence:
102
103              SEEK_SET  The stream offset should be set *offset bytes from the
104                        start of the stream.
105
106              SEEK_CUR  *offset should be added to the current stream offset.
107
108              SEEK_END  The  stream  offset  should  be set to the size of the
109                        stream plus *offset.
110
111              Before returning, the seek function  should  update  *offset  to
112              indicate the new stream offset.
113
114              As  its  function  result,  the seek function should return 0 on
115              success, and -1 on error.
116
117              If *seek is a null pointer, then it is not possible  to  perform
118              seek operations on the stream.
119
120       cookie_close_function_t *close
121              This  function  closes  the  stream.   The  hook function can do
122              things such as freeing buffers allocated for the  stream.   When
123              called, it receives one argument:
124
125                  int close(void *cookie);
126
127              The  cookie  argument is the cookie that the programmer supplied
128              when calling fopencookie().
129
130              As its function result, the close function should  return  0  on
131              success, and EOF on error.
132
133              If  *close is NULL, then no special action is performed when the
134              stream is closed.
135

RETURN VALUE

137       On success fopencookie() returns a  pointer  to  the  new  stream.   On
138       error, NULL is returned.
139

ATTRIBUTES

141       For   an   explanation   of   the  terms  used  in  this  section,  see
142       attributes(7).
143
144       ┌──────────────┬───────────────┬─────────┐
145Interface     Attribute     Value   
146       ├──────────────┼───────────────┼─────────┤
147fopencookie() │ Thread safety │ MT-Safe │
148       └──────────────┴───────────────┴─────────┘

CONFORMING TO

150       This function is a nonstandard GNU extension.
151

EXAMPLE

153       The program below implements a custom  stream  whose  functionality  is
154       similar  (but  not  identical)  to  that available via fmemopen(3).  It
155       implements a stream whose data is stored in a memory buffer.  The  pro‐
156       gram  writes  its  command-line arguments to the stream, and then seeks
157       through the stream reading two out of every five characters and writing
158       them  to standard output.  The following shell session demonstrates the
159       use of the program:
160
161           $ ./a.out 'hello world'
162           /he/
163           / w/
164           /d/
165           Reached end of file
166
167       Note that a more general version of the program below could be improved
168       to  more  robustly  handle  various  error  situations (e.g., opening a
169       stream with a cookie that already has an open stream; closing a  stream
170       that has already been closed).
171
172   Program source
173
174       #define _GNU_SOURCE
175       #include <sys/types.h>
176       #include <stdio.h>
177       #include <stdlib.h>
178       #include <unistd.h>
179       #include <string.h>
180
181       #define INIT_BUF_SIZE 4
182
183       struct memfile_cookie {
184           char   *buf;        /* Dynamically sized buffer for data */
185           size_t  allocated;  /* Size of buf */
186           size_t  endpos;     /* Number of characters in buf */
187           off_t   offset;     /* Current file offset in buf */
188       };
189
190       ssize_t
191       memfile_write(void *c, const char *buf, size_t size)
192       {
193           char *new_buff;
194           struct memfile_cookie *cookie = c;
195
196           /* Buffer too small? Keep doubling size until big enough */
197
198           while (size + cookie->offset > cookie->allocated) {
199               new_buff = realloc(cookie->buf, cookie->allocated * 2);
200               if (new_buff == NULL) {
201                   return -1;
202               } else {
203                   cookie->allocated *= 2;
204                   cookie->buf = new_buff;
205               }
206           }
207
208           memcpy(cookie->buf + cookie->offset, buf, size);
209
210           cookie->offset += size;
211           if (cookie->offset > cookie->endpos)
212               cookie->endpos = cookie->offset;
213
214           return size;
215       }
216
217       ssize_t
218       memfile_read(void *c, char *buf, size_t size)
219       {
220           ssize_t xbytes;
221           struct memfile_cookie *cookie = c;
222
223           /* Fetch minimum of bytes requested and bytes available */
224
225           xbytes = size;
226           if (cookie->offset + size > cookie->endpos)
227               xbytes = cookie->endpos - cookie->offset;
228           if (xbytes < 0)     /* offset may be past endpos */
229              xbytes = 0;
230
231           memcpy(buf, cookie->buf + cookie->offset, xbytes);
232
233           cookie->offset += xbytes;
234           return xbytes;
235       }
236
237       int
238       memfile_seek(void *c, off64_t *offset, int whence)
239       {
240           off64_t new_offset;
241           struct memfile_cookie *cookie = c;
242
243           if (whence == SEEK_SET)
244               new_offset = *offset;
245           else if (whence == SEEK_END)
246               new_offset = cookie->endpos + *offset;
247           else if (whence == SEEK_CUR)
248               new_offset = cookie->offset + *offset;
249           else
250               return -1;
251
252           if (new_offset < 0)
253               return -1;
254
255           cookie->offset = new_offset;
256           *offset = new_offset;
257           return 0;
258       }
259
260       int
261       memfile_close(void *c)
262       {
263           struct memfile_cookie *cookie = c;
264
265           free(cookie->buf);
266           cookie->allocated = 0;
267           cookie->buf = NULL;
268
269           return 0;
270       }
271
272       int
273       main(int argc, char *argv[])
274       {
275           cookie_io_functions_t  memfile_func = {
276               .read  = memfile_read,
277               .write = memfile_write,
278               .seek  = memfile_seek,
279               .close = memfile_close
280           };
281           FILE *stream;
282           struct memfile_cookie mycookie;
283           ssize_t nread;
284           long p;
285           int j;
286           char buf[1000];
287
288           /* Set up the cookie before calling fopencookie() */
289
290           mycookie.buf = malloc(INIT_BUF_SIZE);
291           if (mycookie.buf == NULL) {
292               perror("malloc");
293               exit(EXIT_FAILURE);
294           }
295
296           mycookie.allocated = INIT_BUF_SIZE;
297           mycookie.offset = 0;
298           mycookie.endpos = 0;
299
300           stream = fopencookie(&mycookie,"w+", memfile_func);
301           if (stream == NULL) {
302               perror("fopencookie");
303               exit(EXIT_FAILURE);
304           }
305
306           /* Write command-line arguments to our file */
307
308           for (j = 1; j < argc; j++)
309               if (fputs(argv[j], stream) == EOF) {
310                   perror("fputs");
311                   exit(EXIT_FAILURE);
312               }
313
314           /* Read two bytes out of every five, until EOF */
315
316           for (p = 0; ; p += 5) {
317               if (fseek(stream, p, SEEK_SET) == -1) {
318                   perror("fseek");
319                   exit(EXIT_FAILURE);
320               }
321               nread = fread(buf, 1, 2, stream);
322               if (nread == -1) {
323                   perror("fread");
324                   exit(EXIT_FAILURE);
325               }
326               if (nread == 0) {
327                   printf("Reached end of file\n");
328                   break;
329               }
330
331               printf("/%.*s/\n", nread, buf);
332           }
333
334           exit(EXIT_SUCCESS);
335       }
336

SEE ALSO

338       fclose(3), fmemopen(3), fopen(3), fseek(3)
339

COLOPHON

341       This  page  is  part of release 4.15 of the Linux man-pages project.  A
342       description of the project, information about reporting bugs,  and  the
343       latest     version     of     this    page,    can    be    found    at
344       https://www.kernel.org/doc/man-pages/.
345
346
347
348Linux                             2017-09-15                    FOPENCOOKIE(3)
Impressum