OSDN Git Service

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