OSDN Git Service

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