Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6536 | serge | 1 | /* Copyright (C) 2007 Eric Blake |
2 | * Permission to use, copy, modify, and distribute this software |
||
3 | * is freely granted, provided that this notice is preserved. |
||
4 | */ |
||
5 | |||
6 | /* |
||
7 | FUNCTION |
||
8 | < |
||
9 | |||
10 | INDEX |
||
11 | funopen |
||
12 | INDEX |
||
13 | fropen |
||
14 | INDEX |
||
15 | fwopen |
||
16 | |||
17 | ANSI_SYNOPSIS |
||
18 | #include |
||
19 | FILE *funopen(const void *<[cookie]>, |
||
20 | int (*<[readfn]>) (void *cookie, char *buf, int n), |
||
21 | int (*<[writefn]>) (void *cookie, const char *buf, int n), |
||
22 | fpos_t (*<[seekfn]>) (void *cookie, fpos_t off, int whence), |
||
23 | int (*<[closefn]>) (void *cookie)); |
||
24 | FILE *fropen(const void *<[cookie]>, |
||
25 | int (*<[readfn]>) (void *cookie, char *buf, int n)); |
||
26 | FILE *fwopen(const void *<[cookie]>, |
||
27 | int (*<[writefn]>) (void *cookie, const char *buf, int n)); |
||
28 | |||
29 | DESCRIPTION |
||
30 | < |
||
31 | custom callbacks. At least one of <[readfn]> and <[writefn]> must be |
||
32 | provided, which determines whether the stream behaves with mode <"r">, |
||
33 | <"w">, or <"r+">. |
||
34 | |||
35 | <[readfn]> should return -1 on failure, or else the number of bytes |
||
36 | read (0 on EOF). It is similar to < |
||
37 | than |
||
38 | as the first argument. A NULL <[readfn]> makes attempts to read the |
||
39 | stream fail. |
||
40 | |||
41 | <[writefn]> should return -1 on failure, or else the number of bytes |
||
42 | written. It is similar to < |
||
43 |
|
||
44 | the first argument. A NULL <[writefn]> makes attempts to write the |
||
45 | stream fail. |
||
46 | |||
47 | <[seekfn]> should return (fpos_t)-1 on failure, or else the current |
||
48 | file position. It is similar to < |
||
49 | will be passed as the first argument. A NULL <[seekfn]> makes the |
||
50 | stream behave similarly to a pipe in relation to stdio functions that |
||
51 | require positioning. This implementation assumes fpos_t and off_t are |
||
52 | the same type. |
||
53 | |||
54 | <[closefn]> should return -1 on failure, or 0 on success. It is |
||
55 | similar to < |
||
56 | first argument. A NULL <[closefn]> merely flushes all data then lets |
||
57 | < |
||
58 | |||
59 | Read and write I/O functions are allowed to change the underlying |
||
60 | buffer on fully buffered or line buffered streams by calling |
||
61 | < |
||
62 | the buffer. They are not, however, allowed to change streams from |
||
63 | unbuffered to buffered or to change the state of the line buffering |
||
64 | flag. They must also be prepared to have read or write calls occur on |
||
65 | buffers other than the one most recently specified. |
||
66 | |||
67 | The functions < |
||
68 | < |
||
69 | |||
70 | RETURNS |
||
71 | The return value is an open FILE pointer on success. On error, |
||
72 | < |
||
73 | function pointer is missing, ENOMEM if the stream cannot be created, |
||
74 | or EMFILE if too many streams are already open. |
||
75 | |||
76 | PORTABILITY |
||
77 | This function is a newlib extension, copying the prototype from BSD. |
||
78 | It is not portable. See also the < |
||
79 | |||
80 | Supporting OS subroutines required: < |
||
81 | */ |
||
82 | |||
83 | #include |
||
84 | #include |
||
85 | #include |
||
86 | #include "local.h" |
||
87 | |||
88 | typedef int (*funread)(void *_cookie, char *_buf, _READ_WRITE_BUFSIZE_TYPE _n); |
||
89 | typedef int (*funwrite)(void *_cookie, const char *_buf, |
||
90 | _READ_WRITE_BUFSIZE_TYPE _n); |
||
91 | #ifdef __LARGE64_FILES |
||
92 | typedef _fpos64_t (*funseek)(void *_cookie, _fpos64_t _off, int _whence); |
||
93 | #else |
||
94 | typedef fpos_t (*funseek)(void *_cookie, fpos_t _off, int _whence); |
||
95 | #endif |
||
96 | typedef int (*funclose)(void *_cookie); |
||
97 | |||
98 | typedef struct funcookie { |
||
99 | void *cookie; |
||
100 | funread readfn; |
||
101 | funwrite writefn; |
||
102 | funseek seekfn; |
||
103 | funclose closefn; |
||
104 | } funcookie; |
||
105 | |||
106 | static _READ_WRITE_RETURN_TYPE |
||
107 | _DEFUN(funreader, (ptr, cookie, buf, n), |
||
108 | struct _reent *ptr _AND |
||
109 | void *cookie _AND |
||
110 | char *buf _AND |
||
111 | _READ_WRITE_BUFSIZE_TYPE n) |
||
112 | { |
||
113 | int result; |
||
114 | funcookie *c = (funcookie *) cookie; |
||
115 | errno = 0; |
||
116 | if ((result = c->readfn (c->cookie, buf, n)) < 0 && errno) |
||
117 | ptr->_errno = errno; |
||
118 | return result; |
||
119 | } |
||
120 | |||
121 | static _READ_WRITE_RETURN_TYPE |
||
122 | _DEFUN(funwriter, (ptr, cookie, buf, n), |
||
123 | struct _reent *ptr _AND |
||
124 | void *cookie _AND |
||
125 | const char *buf _AND |
||
126 | _READ_WRITE_BUFSIZE_TYPE n) |
||
127 | { |
||
128 | int result; |
||
129 | funcookie *c = (funcookie *) cookie; |
||
130 | errno = 0; |
||
131 | if ((result = c->writefn (c->cookie, buf, n)) < 0 && errno) |
||
132 | ptr->_errno = errno; |
||
133 | return result; |
||
134 | } |
||
135 | |||
136 | static _fpos_t |
||
137 | _DEFUN(funseeker, (ptr, cookie, off, whence), |
||
138 | struct _reent *ptr _AND |
||
139 | void *cookie _AND |
||
140 | _fpos_t off _AND |
||
141 | int whence) |
||
142 | { |
||
143 | funcookie *c = (funcookie *) cookie; |
||
144 | #ifndef __LARGE64_FILES |
||
145 | fpos_t result; |
||
146 | errno = 0; |
||
147 | if ((result = c->seekfn (c->cookie, (fpos_t) off, whence)) < 0 && errno) |
||
148 | ptr->_errno = errno; |
||
149 | #else /* __LARGE64_FILES */ |
||
150 | _fpos64_t result; |
||
151 | errno = 0; |
||
152 | if ((result = c->seekfn (c->cookie, (_fpos64_t) off, whence)) < 0 && errno) |
||
153 | ptr->_errno = errno; |
||
154 | else if ((_fpos_t)result != result) |
||
155 | { |
||
156 | ptr->_errno = EOVERFLOW; |
||
157 | result = -1; |
||
158 | } |
||
159 | #endif /* __LARGE64_FILES */ |
||
160 | return result; |
||
161 | } |
||
162 | |||
163 | #ifdef __LARGE64_FILES |
||
164 | static _fpos64_t |
||
165 | _DEFUN(funseeker64, (ptr, cookie, off, whence), |
||
166 | struct _reent *ptr _AND |
||
167 | void *cookie _AND |
||
168 | _fpos64_t off _AND |
||
169 | int whence) |
||
170 | { |
||
171 | _fpos64_t result; |
||
172 | funcookie *c = (funcookie *) cookie; |
||
173 | errno = 0; |
||
174 | if ((result = c->seekfn (c->cookie, off, whence)) < 0 && errno) |
||
175 | ptr->_errno = errno; |
||
176 | return result; |
||
177 | } |
||
178 | #endif /* __LARGE64_FILES */ |
||
179 | |||
180 | static int |
||
181 | _DEFUN(funcloser, (ptr, cookie), |
||
182 | struct _reent *ptr _AND |
||
183 | void *cookie) |
||
184 | { |
||
185 | int result = 0; |
||
186 | funcookie *c = (funcookie *) cookie; |
||
187 | if (c->closefn) |
||
188 | { |
||
189 | errno = 0; |
||
190 | if ((result = c->closefn (c->cookie)) < 0 && errno) |
||
191 | ptr->_errno = errno; |
||
192 | } |
||
193 | _free_r (ptr, c); |
||
194 | return result; |
||
195 | } |
||
196 | |||
197 | FILE * |
||
198 | _DEFUN(_funopen_r, (ptr, cookie, readfn, writefn, seekfn, closefn), |
||
199 | struct _reent *ptr _AND |
||
200 | const void *cookie _AND |
||
201 | funread readfn _AND |
||
202 | funwrite writefn _AND |
||
203 | funseek seekfn _AND |
||
204 | funclose closefn) |
||
205 | { |
||
206 | FILE *fp; |
||
207 | funcookie *c; |
||
208 | |||
209 | if (!readfn && !writefn) |
||
210 | { |
||
211 | ptr->_errno = EINVAL; |
||
212 | return NULL; |
||
213 | } |
||
214 | if ((fp = __sfp (ptr)) == NULL) |
||
215 | return NULL; |
||
216 | if ((c = (funcookie *) _malloc_r (ptr, sizeof *c)) == NULL) |
||
217 | { |
||
218 | _newlib_sfp_lock_start (); |
||
219 | fp->_flags = 0; /* release */ |
||
220 | #ifndef __SINGLE_THREAD__ |
||
221 | __lock_close_recursive (fp->_lock); |
||
222 | #endif |
||
223 | _newlib_sfp_lock_end (); |
||
224 | return NULL; |
||
225 | } |
||
226 | |||
227 | _newlib_flockfile_start (fp); |
||
228 | fp->_file = -1; |
||
229 | c->cookie = (void *) cookie; /* cast away const */ |
||
230 | fp->_cookie = c; |
||
231 | if (readfn) |
||
232 | { |
||
233 | c->readfn = readfn; |
||
234 | fp->_read = funreader; |
||
235 | if (writefn) |
||
236 | { |
||
237 | fp->_flags = __SRW; |
||
238 | c->writefn = writefn; |
||
239 | fp->_write = funwriter; |
||
240 | } |
||
241 | else |
||
242 | { |
||
243 | fp->_flags = __SRD; |
||
244 | c->writefn = NULL; |
||
245 | fp->_write = NULL; |
||
246 | } |
||
247 | } |
||
248 | else |
||
249 | { |
||
250 | fp->_flags = __SWR; |
||
251 | c->writefn = writefn; |
||
252 | fp->_write = funwriter; |
||
253 | c->readfn = NULL; |
||
254 | fp->_read = NULL; |
||
255 | } |
||
256 | c->seekfn = seekfn; |
||
257 | fp->_seek = seekfn ? funseeker : NULL; |
||
258 | #ifdef __LARGE64_FILES |
||
259 | fp->_seek64 = seekfn ? funseeker64 : NULL; |
||
260 | fp->_flags |= __SL64; |
||
261 | #endif |
||
262 | c->closefn = closefn; |
||
263 | fp->_close = funcloser; |
||
264 | _newlib_flockfile_end (fp); |
||
265 | return fp; |
||
266 | } |
||
267 | |||
268 | #ifndef _REENT_ONLY |
||
269 | FILE * |
||
270 | _DEFUN(funopen, (cookie, readfn, writefn, seekfn, closefn), |
||
271 | const void *cookie _AND |
||
272 | funread readfn _AND |
||
273 | funwrite writefn _AND |
||
274 | funseek seekfn _AND |
||
275 | funclose closefn) |
||
276 | { |
||
277 | return _funopen_r (_REENT, cookie, readfn, writefn, seekfn, closefn); |
||
278 | } |
||
279 | #endif /* !_REENT_ONLY */>>>>>> |