1fopencookie(3)             Library Functions Manual             fopencookie(3)
2
3
4

NAME

6       fopencookie - opening a custom stream
7

LIBRARY

9       Standard C library (libc, -lc)
10

SYNOPSIS

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

DESCRIPTION

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

RETURN VALUE

143       On success fopencookie() returns a pointer to the new stream.   On  er‐
144       ror, NULL is returned.
145

ATTRIBUTES

147       For  an  explanation  of  the  terms  used  in  this  section,  see at‐
148       tributes(7).
149
150       ┌────────────────────────────────────────────┬───────────────┬─────────┐
151Interface                                   Attribute     Value   
152       ├────────────────────────────────────────────┼───────────────┼─────────┤
153fopencookie()                               │ Thread safety │ MT-Safe │
154       └────────────────────────────────────────────┴───────────────┴─────────┘
155

STANDARDS

157       GNU.
158

EXAMPLES

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

SEE ALSO

343       fclose(3), fmemopen(3), fopen(3), fseek(3)
344
345
346
347Linux man-pages 6.04              2023-03-30                    fopencookie(3)
Impressum