Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / stdio / funopen.c
blob4ed50196ea20fe4fb30943e97b0754263f1742bf
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 */
6 /*
7 FUNCTION
8 <<funopen>>, <<fropen>>, <<fwopen>>---open a stream with custom callbacks
10 INDEX
11 funopen
12 INDEX
13 fropen
14 INDEX
15 fwopen
17 SYNOPSIS
18 #include <stdio.h>
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));
29 DESCRIPTION
30 <<funopen>> creates a <<FILE>> stream where I/O is performed using
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+">.
35 <[readfn]> should return -1 on failure, or else the number of bytes
36 read (0 on EOF). It is similar to <<read>>, except that <int> rather
37 than <size_t> bounds a transaction size, and <[cookie]> will be passed
38 as the first argument. A NULL <[readfn]> makes attempts to read the
39 stream fail.
41 <[writefn]> should return -1 on failure, or else the number of bytes
42 written. It is similar to <<write>>, except that <int> rather than
43 <size_t> bounds a transaction size, and <[cookie]> will be passed as
44 the first argument. A NULL <[writefn]> makes attempts to write the
45 stream fail.
47 <[seekfn]> should return (fpos_t)-1 on failure, or else the current
48 file position. It is similar to <<lseek>>, except that <[cookie]>
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.
54 <[closefn]> should return -1 on failure, or 0 on success. It is
55 similar to <<close>>, except that <[cookie]> will be passed as the
56 first argument. A NULL <[closefn]> merely flushes all data then lets
57 <<fclose>> succeed. A failed close will still invalidate the stream.
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 <<setvbuf>>. They are also not required to completely fill or empty
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.
67 The functions <<fropen>> and <<fwopen>> are convenience macros around
68 <<funopen>> that only use the specified callback.
70 RETURNS
71 The return value is an open FILE pointer on success. On error,
72 <<NULL>> is returned, and <<errno>> will be set to EINVAL if a
73 function pointer is missing, ENOMEM if the stream cannot be created,
74 or EMFILE if too many streams are already open.
76 PORTABILITY
77 This function is a newlib extension, copying the prototype from BSD.
78 It is not portable. See also the <<fopencookie>> interface from Linux.
80 Supporting OS subroutines required: <<sbrk>>.
83 #include <stdio.h>
84 #include <errno.h>
85 #include <sys/lock.h>
86 #include "local.h"
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);
98 typedef struct funcookie {
99 void *cookie;
100 funread readfn;
101 funwrite writefn;
102 funseek seekfn;
103 funclose closefn;
104 } funcookie;
106 static _READ_WRITE_RETURN_TYPE
107 funreader (struct _reent *ptr,
108 void *cookie,
109 char *buf,
110 _READ_WRITE_BUFSIZE_TYPE n)
112 int result;
113 funcookie *c = (funcookie *) cookie;
114 errno = 0;
115 if ((result = c->readfn (c->cookie, buf, n)) < 0 && errno)
116 _REENT_ERRNO(ptr) = errno;
117 return result;
120 static _READ_WRITE_RETURN_TYPE
121 funwriter (struct _reent *ptr,
122 void *cookie,
123 const char *buf,
124 _READ_WRITE_BUFSIZE_TYPE n)
126 int result;
127 funcookie *c = (funcookie *) cookie;
128 errno = 0;
129 if ((result = c->writefn (c->cookie, buf, n)) < 0 && errno)
130 _REENT_ERRNO(ptr) = errno;
131 return result;
134 static _fpos_t
135 funseeker (struct _reent *ptr,
136 void *cookie,
137 _fpos_t off,
138 int whence)
140 funcookie *c = (funcookie *) cookie;
141 #ifndef __LARGE64_FILES
142 fpos_t result;
143 errno = 0;
144 if ((result = c->seekfn (c->cookie, (fpos_t) off, whence)) < 0 && errno)
145 _REENT_ERRNO(ptr) = errno;
146 #else /* __LARGE64_FILES */
147 _fpos64_t result;
148 errno = 0;
149 if ((result = c->seekfn (c->cookie, (_fpos64_t) off, whence)) < 0 && errno)
150 _REENT_ERRNO(ptr) = errno;
151 else if ((_fpos_t)result != result)
153 _REENT_ERRNO(ptr) = EOVERFLOW;
154 result = -1;
156 #endif /* __LARGE64_FILES */
157 return result;
160 #ifdef __LARGE64_FILES
161 static _fpos64_t
162 funseeker64 (struct _reent *ptr,
163 void *cookie,
164 _fpos64_t off,
165 int whence)
167 _fpos64_t result;
168 funcookie *c = (funcookie *) cookie;
169 errno = 0;
170 if ((result = c->seekfn (c->cookie, off, whence)) < 0 && errno)
171 _REENT_ERRNO(ptr) = errno;
172 return result;
174 #endif /* __LARGE64_FILES */
176 static int
177 funcloser (struct _reent *ptr,
178 void *cookie)
180 int result = 0;
181 funcookie *c = (funcookie *) cookie;
182 if (c->closefn)
184 errno = 0;
185 if ((result = c->closefn (c->cookie)) < 0 && errno)
186 _REENT_ERRNO(ptr) = errno;
188 _free_r (ptr, c);
189 return result;
192 FILE *
193 _funopen_r (struct _reent *ptr,
194 const void *cookie,
195 funread readfn,
196 funwrite writefn,
197 funseek seekfn,
198 funclose closefn)
200 FILE *fp;
201 funcookie *c;
203 if (!readfn && !writefn)
205 _REENT_ERRNO(ptr) = EINVAL;
206 return NULL;
208 if ((fp = __sfp (ptr)) == NULL)
209 return NULL;
210 if ((c = (funcookie *) _malloc_r (ptr, sizeof *c)) == NULL)
212 _newlib_sfp_lock_start ();
213 fp->_flags = 0; /* release */
214 #ifndef __SINGLE_THREAD__
215 __lock_close_recursive (fp->_lock);
216 #endif
217 _newlib_sfp_lock_end ();
218 return NULL;
221 _newlib_flockfile_start (fp);
222 fp->_file = -1;
223 c->cookie = (void *) cookie; /* cast away const */
224 fp->_cookie = c;
225 if (readfn)
227 c->readfn = readfn;
228 fp->_read = funreader;
229 if (writefn)
231 fp->_flags = __SRW;
232 c->writefn = writefn;
233 fp->_write = funwriter;
235 else
237 fp->_flags = __SRD;
238 c->writefn = NULL;
239 fp->_write = NULL;
242 else
244 fp->_flags = __SWR;
245 c->writefn = writefn;
246 fp->_write = funwriter;
247 c->readfn = NULL;
248 fp->_read = NULL;
250 c->seekfn = seekfn;
251 fp->_seek = seekfn ? funseeker : NULL;
252 #ifdef __LARGE64_FILES
253 fp->_seek64 = seekfn ? funseeker64 : NULL;
254 fp->_flags |= __SL64;
255 #endif
256 c->closefn = closefn;
257 fp->_close = funcloser;
258 _newlib_flockfile_end (fp);
259 return fp;
262 #ifndef _REENT_ONLY
263 FILE *
264 funopen (const void *cookie,
265 funread readfn,
266 funwrite writefn,
267 funseek seekfn,
268 funclose closefn)
270 return _funopen_r (_REENT, cookie, readfn, writefn, seekfn, closefn);
272 #endif /* !_REENT_ONLY */