source: trunk/libs/newlib/src/newlib/libc/stdio/funopen.c @ 620

Last change on this file since 620 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 7.3 KB
Line 
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/*
7FUNCTION
8<<funopen>>, <<fropen>>, <<fwopen>>---open a stream with custom callbacks
9
10INDEX
11        funopen
12INDEX
13        fropen
14INDEX
15        fwopen
16
17SYNOPSIS
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));
28
29DESCRIPTION
30<<funopen>> creates a <<FILE>> stream where I/O is performed using
31custom callbacks.  At least one of <[readfn]> and <[writefn]> must be
32provided, 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
36read (0 on EOF).  It is similar to <<read>>, except that <int> rather
37than <size_t> bounds a transaction size, and <[cookie]> will be passed
38as the first argument.  A NULL <[readfn]> makes attempts to read the
39stream fail.
40
41<[writefn]> should return -1 on failure, or else the number of bytes
42written.  It is similar to <<write>>, except that <int> rather than
43<size_t> bounds a transaction size, and <[cookie]> will be passed as
44the first argument.  A NULL <[writefn]> makes attempts to write the
45stream fail.
46
47<[seekfn]> should return (fpos_t)-1 on failure, or else the current
48file position.  It is similar to <<lseek>>, except that <[cookie]>
49will be passed as the first argument.  A NULL <[seekfn]> makes the
50stream behave similarly to a pipe in relation to stdio functions that
51require positioning.  This implementation assumes fpos_t and off_t are
52the same type.
53
54<[closefn]> should return -1 on failure, or 0 on success.  It is
55similar to <<close>>, except that <[cookie]> will be passed as the
56first argument.  A NULL <[closefn]> merely flushes all data then lets
57<<fclose>> succeed.  A failed close will still invalidate the stream.
58
59Read and write I/O functions are allowed to change the underlying
60buffer on fully buffered or line buffered streams by calling
61<<setvbuf>>.  They are also not required to completely fill or empty
62the buffer.  They are not, however, allowed to change streams from
63unbuffered to buffered or to change the state of the line buffering
64flag.  They must also be prepared to have read or write calls occur on
65buffers other than the one most recently specified.
66
67The functions <<fropen>> and <<fwopen>> are convenience macros around
68<<funopen>> that only use the specified callback.
69
70RETURNS
71The return value is an open FILE pointer on success.  On error,
72<<NULL>> is returned, and <<errno>> will be set to EINVAL if a
73function pointer is missing, ENOMEM if the stream cannot be created,
74or EMFILE if too many streams are already open.
75
76PORTABILITY
77This function is a newlib extension, copying the prototype from BSD.
78It is not portable.  See also the <<fopencookie>> interface from Linux.
79
80Supporting OS subroutines required: <<sbrk>>.
81*/
82
83#include <stdio.h>
84#include <errno.h>
85#include <sys/lock.h>
86#include "local.h"
87
88typedef int (*funread)(void *_cookie, char *_buf, _READ_WRITE_BUFSIZE_TYPE _n);
89typedef int (*funwrite)(void *_cookie, const char *_buf,
90                        _READ_WRITE_BUFSIZE_TYPE _n);
91#ifdef __LARGE64_FILES
92typedef _fpos64_t (*funseek)(void *_cookie, _fpos64_t _off, int _whence);
93#else
94typedef fpos_t (*funseek)(void *_cookie, fpos_t _off, int _whence);
95#endif
96typedef int (*funclose)(void *_cookie);
97
98typedef struct funcookie {
99  void *cookie;
100  funread readfn;
101  funwrite writefn;
102  funseek seekfn;
103  funclose closefn;
104} funcookie;
105
106static _READ_WRITE_RETURN_TYPE
107funreader (struct _reent *ptr,
108       void *cookie,
109       char *buf,
110       _READ_WRITE_BUFSIZE_TYPE n)
111{
112  int result;
113  funcookie *c = (funcookie *) cookie;
114  errno = 0;
115  if ((result = c->readfn (c->cookie, buf, n)) < 0 && errno)
116    ptr->_errno = errno;
117  return result;
118}
119
120static _READ_WRITE_RETURN_TYPE
121funwriter (struct _reent *ptr,
122       void *cookie,
123       const char *buf,
124       _READ_WRITE_BUFSIZE_TYPE n)
125{
126  int result;
127  funcookie *c = (funcookie *) cookie;
128  errno = 0;
129  if ((result = c->writefn (c->cookie, buf, n)) < 0 && errno)
130    ptr->_errno = errno;
131  return result;
132}
133
134static _fpos_t
135funseeker (struct _reent *ptr,
136       void *cookie,
137       _fpos_t off,
138       int whence)
139{
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    ptr->_errno = 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    ptr->_errno = errno;
151  else if ((_fpos_t)result != result)
152    {
153      ptr->_errno = EOVERFLOW;
154      result = -1;
155    }
156#endif /* __LARGE64_FILES */
157  return result;
158}
159
160#ifdef __LARGE64_FILES
161static _fpos64_t
162funseeker64 (struct _reent *ptr,
163       void *cookie,
164       _fpos64_t off,
165       int whence)
166{
167  _fpos64_t result;
168  funcookie *c = (funcookie *) cookie;
169  errno = 0;
170  if ((result = c->seekfn (c->cookie, off, whence)) < 0 && errno)
171    ptr->_errno = errno;
172  return result;
173}
174#endif /* __LARGE64_FILES */
175
176static int
177funcloser (struct _reent *ptr,
178       void *cookie)
179{
180  int result = 0;
181  funcookie *c = (funcookie *) cookie;
182  if (c->closefn)
183    {
184      errno = 0;
185      if ((result = c->closefn (c->cookie)) < 0 && errno)
186        ptr->_errno = errno;
187    }
188  _free_r (ptr, c);
189  return result;
190}
191
192FILE *
193_funopen_r (struct _reent *ptr,
194       const void *cookie,
195       funread readfn,
196       funwrite writefn,
197       funseek seekfn,
198       funclose closefn)
199{
200  FILE *fp;
201  funcookie *c;
202
203  if (!readfn && !writefn)
204    {
205      ptr->_errno = EINVAL;
206      return NULL;
207    }
208  if ((fp = __sfp (ptr)) == NULL)
209    return NULL;
210  if ((c = (funcookie *) _malloc_r (ptr, sizeof *c)) == NULL)
211    {
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;
219    }
220
221  _newlib_flockfile_start (fp);
222  fp->_file = -1;
223  c->cookie = (void *) cookie; /* cast away const */
224  fp->_cookie = c;
225  if (readfn)
226    {
227      c->readfn = readfn;
228      fp->_read = funreader;
229      if (writefn)
230        {
231          fp->_flags = __SRW;
232          c->writefn = writefn;
233          fp->_write = funwriter;
234        }
235      else
236        {
237          fp->_flags = __SRD;
238          c->writefn = NULL;
239          fp->_write = NULL;
240        }
241    }
242  else
243    {
244      fp->_flags = __SWR;
245      c->writefn = writefn;
246      fp->_write = funwriter;
247      c->readfn = NULL;
248      fp->_read = NULL;
249    }
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;
260}
261
262#ifndef _REENT_ONLY
263FILE *
264funopen (const void *cookie,
265       funread readfn,
266       funwrite writefn,
267       funseek seekfn,
268       funclose closefn)
269{
270  return _funopen_r (_REENT, cookie, readfn, writefn, seekfn, closefn);
271}
272#endif /* !_REENT_ONLY */
Note: See TracBrowser for help on using the repository browser.