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

CONFORMING TO

141       This function is a nonstandard GNU extension.
142

EXAMPLE

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

SEE ALSO

329       fclose(3), fmemopen(3), fopen(3), fseek(3)
330

COLOPHON

332       This page is part of release 3.53 of the Linux  man-pages  project.   A
333       description  of  the project, and information about reporting bugs, can
334       be found at http://www.kernel.org/doc/man-pages/.
335
336
337
338Linux                             2013-03-17                    FOPENCOOKIE(3)
Impressum