]> git.ipfire.org Git - thirdparty/man-pages.git/blame - man3/fopencookie.3
alloca.3: Prevent any misunderstanding about when allocated memory is released
[thirdparty/man-pages.git] / man3 / fopencookie.3
CommitLineData
79bf8cdc
MK
1.\" Copyright (c) 2008, Linux Foundation, written by Michael Kerrisk
2.\" <mtk.manpages@gmail.com>
3.\"
93015253 4.\" %%%LICENSE_START(VERBATIM)
79bf8cdc
MK
5.\" Permission is granted to make and distribute verbatim copies of this
6.\" manual provided the copyright notice and this permission notice are
7.\" preserved on all copies.
8.\"
9.\" Permission is granted to copy and distribute modified versions of this
10.\" manual under the conditions for verbatim copying, provided that the
11.\" entire resulting derived work is distributed under the terms of a
12.\" permission notice identical to this one.
13.\"
14.\" Since the Linux kernel and libraries are constantly changing, this
15.\" manual page may be incorrect or out-of-date. The author(s) assume no
16.\" responsibility for errors or omissions, or for damages resulting from
17.\" the use of the information contained herein. The author(s) may not
18.\" have taken the same level of care in the production of this manual,
19.\" which is licensed free of charge, as they might when working
20.\" professionally.
21.\"
22.\" Formatted or processed versions of this manual, if unaccompanied by
23.\" the source, must acknowledge the copyright and authors of this work.
4b72fb64 24.\" %%%LICENSE_END
79bf8cdc 25.\"
4b8c67d9 26.TH FOPENCOOKIE 3 2017-09-15 "Linux" "Linux Programmer's Manual"
79bf8cdc
MK
27.SH NAME
28fopencookie \- opening a custom stream
29.SH SYNOPSIS
30.nf
b80f966b 31.BR "#define _GNU_SOURCE" " /* See feature_test_macros(7) */"
79bf8cdc 32.B #include <stdio.h>
dbfe9c70 33.PP
79bf8cdc
MK
34.BI "FILE *fopencookie(void *" cookie ", const char *" mode ,
35.BI " cookie_io_functions_t " io_funcs );
36.fi
37.SH DESCRIPTION
38The
39.BR fopencookie ()
40function allows the programmer to create a custom implementation
41for a standard I/O stream.
42This implementation can store the stream's data at a location of
43its own choosing; for example,
44.BR fopencookie ()
45is used to implement
46.BR fmemopen (3),
183d08ce 47which provides a stream interface to data that is stored in a
79bf8cdc 48buffer in memory.
847e0d88 49.PP
79bf8cdc
MK
50In order to create a custom stream the programmer must:
51.IP * 3
52Implement four "hook" functions that are used internally by the
53standard I/O library when performing I/O on the stream.
54.IP *
55Define a "cookie" data type,
56a structure that provides bookkeeping information
57(e.g., where to store data) used by the aforementioned hook functions.
58The standard I/O package knows nothing about the contents of this cookie
59(thus it is typed as
60.IR "void\ *"
61when passed to
62.BR fopencookie ()),
63but automatically supplies the cookie
64as the first argument when calling the hook functions.
65.IP *
66Call
67.BR fopencookie ()
68to open a new stream and associate the cookie and hook functions
69with that stream.
70.PP
71The
72.BR fopencookie ()
73function serves a purpose similar to
74.BR fopen (3):
d4e9903b 75it opens a new stream and returns a pointer to a
79bf8cdc
MK
76.I FILE
77object that is used to operate on that stream.
847e0d88 78.PP
79bf8cdc
MK
79The
80.I cookie
81argument is a pointer to the caller's cookie structure
82that is to be associated with the new stream.
83This pointer is supplied as the first argument when the standard I/O
84library invokes any of the hook functions described below.
847e0d88 85.PP
79bf8cdc
MK
86The
87.I mode
88argument serves the same purpose as for
89.BR fopen (3).
90The following modes are supported:
91.IR r ,
92.IR w ,
93.IR a ,
94.IR r+ ,
95.IR w+ ,
96and
97.IR a+ .
98See
99.BR fopen (3)
100for details.
847e0d88 101.PP
79bf8cdc
MK
102The
103.I io_funcs
104argument is a structure that contains four fields pointing to the
105programmer-defined hook functions that are used to implement this stream.
106The structure is defined as follows
e646a1ba 107.PP
79bf8cdc 108.in +4n
e646a1ba 109.EX
70a97b16 110typedef struct {
79bf8cdc
MK
111 cookie_read_function_t *read;
112 cookie_write_function_t *write;
113 cookie_seek_function_t *seek;
114 cookie_close_function_t *close;
70a97b16 115} cookie_io_functions_t;
e646a1ba 116.EE
79bf8cdc 117.in
e646a1ba 118.PP
79bf8cdc
MK
119The four fields are as follows:
120.TP
121.I cookie_read_function_t *read
122This function implements read operations for the stream.
123When called, it receives three arguments:
847e0d88 124.IP
79bf8cdc 125 ssize_t read(void *cookie, char *buf, size_t size);
847e0d88 126.IP
79bf8cdc
MK
127The
128.I buf
129and
130.I size
131arguments are, respectively,
132a buffer into which input data can be placed and the size of that buffer.
133As its function result, the
134.I read
135function should return the number of bytes copied into
136.IR buf ,
1370 on end of file, or \-1 on error.
138The
139.I read
140function should update the stream offset appropriately.
847e0d88 141.IP
79bf8cdc
MK
142If
143.I *read
b437fdd9 144is a null pointer,
79bf8cdc
MK
145then reads from the custom stream always return end of file.
146.TP
147.I cookie_write_function_t *write
148This function implements write operations for the stream.
149When called, it receives three arguments:
847e0d88 150.IP
79bf8cdc 151 ssize_t write(void *cookie, const char *buf, size_t size);
847e0d88 152.IP
79bf8cdc
MK
153The
154.I buf
155and
156.I size
157arguments are, respectively,
158a buffer of data to be output to the stream and the size of that buffer.
159As its function result, the
160.I write
161function should return the number of bytes copied from
162.IR buf ,
6cfe6225
MK
163or 0 on error.
164(The function must not return a negative value.)
79bf8cdc
MK
165The
166.I write
167function should update the stream offset appropriately.
847e0d88 168.IP
79bf8cdc
MK
169If
170.I *write
b437fdd9 171is a null pointer,
79bf8cdc
MK
172then output to the stream is discarded.
173.TP
174.I cookie_seek_function_t *seek
175This function implements seek operations on the stream.
176When called, it receives three arguments:
847e0d88 177.IP
79bf8cdc 178 int seek(void *cookie, off64_t *offset, int whence);
847e0d88 179.IP
79bf8cdc
MK
180The
181.I *offset
182argument specifies the new file offset depending on which
183of the following three values is supplied in
184.IR whence :
185.RS
186.TP 10
187.B SEEK_SET
188The stream offset should be set
189.I *offset
190bytes from the start of the stream.
191.TP
192.B SEEK_CUR
193.I *offset
194should be added to the current stream offset.
195.TP
196.B SEEK_END
197The stream offset should be set to the size of the stream plus
198.IR *offset .
199.RE
200.IP
201Before returning, the
202.I seek
203function should update
204.I *offset
205to indicate the new stream offset.
847e0d88 206.IP
79bf8cdc
MK
207As its function result, the
208.I seek
209function should return 0 on success, and \-1 on error.
847e0d88 210.IP
79bf8cdc
MK
211If
212.I *seek
b437fdd9 213is a null pointer,
79bf8cdc
MK
214then it is not possible to perform seek operations on the stream.
215.TP
216.I cookie_close_function_t *close
217This function closes the stream.
218The hook function can do things such as freeing buffers allocated
219for the stream.
220When called, it receives one argument:
847e0d88 221.IP
79bf8cdc 222 int close(void *cookie);
847e0d88 223.IP
79bf8cdc
MK
224The
225.I cookie
226argument is the cookie that the programmer supplied when calling
227.BR fopencookie ().
847e0d88 228.IP
79bf8cdc
MK
229As its function result, the
230.I close
231function should return 0 on success, and
232.B EOF
233on error.
847e0d88 234.IP
79bf8cdc
MK
235If
236.I *close
237is NULL, then no special action is performed when the stream is closed.
238.SH RETURN VALUE
239On success
240.BR fopencookie ()
241returns a pointer to the new stream.
242On error, NULL is returned.
243.\" .SH ERRORS
244.\" It's not clear if errno ever gets set...
1c3ceb6a
MS
245.SH ATTRIBUTES
246For an explanation of the terms used in this section, see
247.BR attributes (7).
248.TS
249allbox;
250lb lb lb
251l l l.
252Interface Attribute Value
253T{
254.BR fopencookie ()
255T} Thread safety MT-Safe
256.TE
79bf8cdc 257.SH CONFORMING TO
c8f2dd47 258This function is a nonstandard GNU extension.
79bf8cdc
MK
259.SH EXAMPLE
260The program below implements a custom stream whose functionality
261is similar (but not identical) to that available via
262.BR fmemopen (3).
263It implements a stream whose data is stored in a memory buffer.
264The program writes its command-line arguments to the stream,
265and then seeks through the stream reading two out of every
266five characters and writing them to standard output.
267The following shell session demonstrates the use of the program:
e646a1ba 268.PP
79bf8cdc 269.in +4n
e646a1ba 270.EX
b43a3b30 271.RB "$" " ./a.out \(aqhello world\(aq"
79bf8cdc
MK
272/he/
273/ w/
274/d/
275Reached end of file
e646a1ba 276.EE
79bf8cdc 277.in
e646a1ba 278.PP
79bf8cdc
MK
279Note that a more general version of the program below
280could be improved to more robustly handle various error situations
281(e.g., opening a stream with a cookie that already has an open stream;
282closing a stream that has already been closed).
9c330504 283.SS Program source
d84d0300 284\&
e7d0bb47 285.EX
79bf8cdc
MK
286#define _GNU_SOURCE
287#include <sys/types.h>
288#include <stdio.h>
289#include <stdlib.h>
290#include <unistd.h>
291#include <string.h>
292
293#define INIT_BUF_SIZE 4
294
295struct memfile_cookie {
296 char *buf; /* Dynamically sized buffer for data */
297 size_t allocated; /* Size of buf */
298 size_t endpos; /* Number of characters in buf */
299 off_t offset; /* Current file offset in buf */
300};
301
302ssize_t
303memfile_write(void *c, const char *buf, size_t size)
304{
305 char *new_buff;
306 struct memfile_cookie *cookie = c;
307
308 /* Buffer too small? Keep doubling size until big enough */
309
72da9ef1
MK
310 while (size + cookie\->offset > cookie\->allocated) {
311 new_buff = realloc(cookie\->buf, cookie\->allocated * 2);
79bf8cdc
MK
312 if (new_buff == NULL) {
313 return \-1;
314 } else {
315 cookie\->allocated *= 2;
316 cookie\->buf = new_buff;
317 }
318 }
319
72da9ef1 320 memcpy(cookie\->buf + cookie\->offset, buf, size);
79bf8cdc
MK
321
322 cookie\->offset += size;
72da9ef1
MK
323 if (cookie\->offset > cookie\->endpos)
324 cookie\->endpos = cookie\->offset;
79bf8cdc
MK
325
326 return size;
327}
328
329ssize_t
330memfile_read(void *c, char *buf, size_t size)
331{
332 ssize_t xbytes;
333 struct memfile_cookie *cookie = c;
334
335 /* Fetch minimum of bytes requested and bytes available */
336
337 xbytes = size;
72da9ef1
MK
338 if (cookie\->offset + size > cookie\->endpos)
339 xbytes = cookie\->endpos \- cookie\->offset;
79bf8cdc
MK
340 if (xbytes < 0) /* offset may be past endpos */
341 xbytes = 0;
342
72da9ef1 343 memcpy(buf, cookie\->buf + cookie\->offset, xbytes);
79bf8cdc
MK
344
345 cookie\->offset += xbytes;
346 return xbytes;
347}
348
349int
350memfile_seek(void *c, off64_t *offset, int whence)
351{
352 off64_t new_offset;
353 struct memfile_cookie *cookie = c;
354
355 if (whence == SEEK_SET)
356 new_offset = *offset;
357 else if (whence == SEEK_END)
358 new_offset = cookie\->endpos + *offset;
359 else if (whence == SEEK_CUR)
360 new_offset = cookie\->offset + *offset;
361 else
362 return \-1;
363
364 if (new_offset < 0)
365 return \-1;
366
367 cookie\->offset = new_offset;
368 *offset = new_offset;
369 return 0;
370}
371
372int
373memfile_close(void *c)
374{
375 struct memfile_cookie *cookie = c;
376
377 free(cookie\->buf);
378 cookie\->allocated = 0;
379 cookie\->buf = NULL;
380
381 return 0;
382}
383
384int
385main(int argc, char *argv[])
386{
387 cookie_io_functions_t memfile_func = {
388 .read = memfile_read,
389 .write = memfile_write,
390 .seek = memfile_seek,
391 .close = memfile_close
392 };
d41abf5d 393 FILE *stream;
79bf8cdc
MK
394 struct memfile_cookie mycookie;
395 ssize_t nread;
396 long p;
397 int j;
398 char buf[1000];
399
400 /* Set up the cookie before calling fopencookie() */
401
402 mycookie.buf = malloc(INIT_BUF_SIZE);
403 if (mycookie.buf == NULL) {
404 perror("malloc");
405 exit(EXIT_FAILURE);
406 }
407
408 mycookie.allocated = INIT_BUF_SIZE;
409 mycookie.offset = 0;
410 mycookie.endpos = 0;
411
d41abf5d
MK
412 stream = fopencookie(&mycookie,"w+", memfile_func);
413 if (stream == NULL) {
79bf8cdc
MK
414 perror("fopencookie");
415 exit(EXIT_FAILURE);
416 }
417
d4e9903b 418 /* Write command\-line arguments to our file */
79bf8cdc
MK
419
420 for (j = 1; j < argc; j++)
d41abf5d 421 if (fputs(argv[j], stream) == EOF) {
79bf8cdc
MK
422 perror("fputs");
423 exit(EXIT_FAILURE);
424 }
425
426 /* Read two bytes out of every five, until EOF */
427
428 for (p = 0; ; p += 5) {
d41abf5d 429 if (fseek(stream, p, SEEK_SET) == \-1) {
79bf8cdc
MK
430 perror("fseek");
431 exit(EXIT_FAILURE);
432 }
d41abf5d 433 nread = fread(buf, 1, 2, stream);
79bf8cdc
MK
434 if (nread == \-1) {
435 perror("fread");
436 exit(EXIT_FAILURE);
437 }
438 if (nread == 0) {
439 printf("Reached end of file\\n");
440 break;
441 }
442
443 printf("/%.*s/\\n", nread, buf);
444 }
445
446 exit(EXIT_SUCCESS);
447}
e7d0bb47 448.EE
79bf8cdc
MK
449.SH SEE ALSO
450.BR fclose (3),
451.BR fmemopen (3),
452.BR fopen (3),
0a4f8b7b 453.BR fseek (3)